OSDN Git Service

added WIP snapshot system
[automap/automap.git] / Automap / Subsystems / Snapshot.cs
1 using System;
2 using System.Collections.Generic;
3 using System.Diagnostics;
4 using System.IO;
5 using System.Linq;
6 using System.Threading;
7 using System.Threading.Tasks;
8 using Hjg.Pngcs;
9
10 namespace Automap
11 {
12         public class Snapshotter
13         {
14                 public string path;
15                 public string chunkPath;
16                 public ColumnsMetadata cols;
17                 public int chunkSize;
18                 public int NorthEdge => cols.North_mostChunk;
19                 public int WestEdge => cols.West_mostChunk;
20                 public int Width => (cols.East_mostChunk - WestEdge + 1);
21                 public int Height => (cols.South_mostChunk - NorthEdge + 1);
22
23                 public Snapshotter(string path, string chunkPath, ColumnsMetadata cols, int chunkSize)
24                 {
25                         this.path = Path.Combine(path, "snapshot.png");
26                         this.chunkPath = Path.Combine(path, chunkPath);
27                         this.cols = cols;
28                         this.chunkSize = chunkSize;
29                 }
30
31                 /// <summary>
32                 /// takes a snapshot. this should be called from an extra thread.
33                 /// </summary>
34                 /// <param name="path">path to the map dir</param>
35                 /// <param name="chunkPath">name of the chunks dir part thing</param>
36                 /// <param name="cols"></param>
37                 /// <param name="chunkSize"></param>
38                 public async void Take()
39                 {
40                         var t = new Stopwatch();
41                         t.Start();
42                         Console.WriteLine("snapshot started");
43
44                         ImageInfo info = new ImageInfo(Width * chunkSize, Height * chunkSize, 8, false);
45                         PngWriter snapWriter = FileHelper.CreatePngWriter(path, info, true);
46                         snapWriter.CompLevel = 5;
47                         snapWriter.CompressionStrategy = Hjg.Pngcs.Zlib.EDeflateCompressStrategy.Huffman;
48
49                         var orderedList =
50                                 from ch in cols
51                                 group ch by ch.Location.Y into g
52                                 orderby g.Key
53                                 select g;
54                         // that sorts things in ascending order so we can only create (chunkSize) lines at once
55                         int row = 0;
56                         foreach (var chunkGroup in orderedList)
57                         {
58                                 var posY = chunkGroup.Key - NorthEdge;
59                                 var inGroup = (await ReadAllInGroup(chunkGroup)).ToArray();
60                                 // oh god here we go...
61                                 for (int r = 0; r < chunkSize; r++)
62                                 {
63                                         var line = new byte[info.BytesPerRow];
64                                         for (int chunk = 0; chunk < inGroup.Length; chunk++)
65                                         {
66                                                 var posX = inGroup[chunk].Key * chunkSize * info.BytesPixel;
67                                                 inGroup[chunk].Value?[r].CopyTo(line, posX);
68                                         }
69                                         snapWriter.WriteRowByte(line, row++);
70                                 }
71                         }
72                         snapWriter.ShouldCloseStream = true;
73
74                         Console.WriteLine($"snapshot finished in {t.ElapsedMilliseconds}");
75                 }
76
77                 private async Task<Dictionary<int, byte[][]>> ReadAllInGroup(IGrouping<int, ColumnMeta> group)
78                 {
79                         var taskGroup = new Dictionary<int, byte[][]>(group.Count());
80                         foreach (var shardMeta in group)
81                         {
82                                 var shardPath = Path.Combine(chunkPath, $"{shardMeta.Location.X}_{shardMeta.Location.Y}.png");
83                                 taskGroup.Add(shardMeta.Location.X - WestEdge, await ReadNoThrow(shardPath));
84                         }
85                         return taskGroup;
86                 }
87
88                 private async Task<byte[][]> ReadNoThrow(string readPath)
89                 {
90                         try
91                         {
92                                 return await Task.Run(() => FileHelper.CreatePngReader(readPath).ReadRowsByte().ScanlinesB);
93                         }
94                         catch (Exception e)
95                         {
96                                 Console.WriteLine(e.Message);
97                                 return null;
98                         } // do nothing on error
99
100                 }
101         }
102 }