OSDN Git Service

fixed snapshot, it now works when there are blank rows of chunks! + added to csproj
[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.Filtered;
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, lastPosY = 0, posY = 0;
56                         foreach (var chunkGroup in orderedList)
57                         {
58                                 // oh god here we go...
59                                 posY = chunkGroup.Key - NorthEdge;
60                                 var delta = posY - lastPosY;
61                                 lastPosY = posY;
62
63                                 // if there is more than 1 blank step then the gap needs to be filled.
64                                 for (int i = 1; i < delta; i++)
65                                 {
66                                         byte[] blankLine = new byte[info.BytesPerRow];
67                                         for (int j = 0; j < chunkSize; j++)
68                                                 snapWriter.WriteRowByte(blankLine, row++);
69                                 }
70
71                                 var inGroup = (await ReadAllInGroup(chunkGroup)).ToArray();
72                                 
73                                 for (int r = 0; r < chunkSize; r++)
74                                 {
75                                         var line = new byte[info.BytesPerRow];
76                                         for (int chunk = 0; chunk < inGroup.Length; chunk++)
77                                         {
78                                                 var posX = inGroup[chunk].Key * chunkSize * info.BytesPixel;
79                                                 inGroup[chunk].Value?[r].CopyTo(line, posX);
80                                         }
81                                         snapWriter.WriteRowByte(line, row++);
82                                 }
83                         }
84                         snapWriter.ShouldCloseStream = true;
85                         try
86                         {
87                                 snapWriter.End();
88                         }
89                         catch (Exception)
90                         {
91                                 Console.WriteLine("Snapshot exception!");
92                         }
93                         Console.WriteLine($"snapshot finished in {t.ElapsedMilliseconds}");
94                 }
95
96                 private async Task<Dictionary<int, byte[][]>> ReadAllInGroup(IGrouping<int, ColumnMeta> group)
97                 {
98                         var taskGroup = new Dictionary<int, byte[][]>(group.Count());
99                         foreach (var shardMeta in group)
100                         {
101                                 var shardPath = Path.Combine(chunkPath, $"{shardMeta.Location.X}_{shardMeta.Location.Y}.png");
102                                 taskGroup.Add(shardMeta.Location.X - WestEdge, await ReadNoThrow(shardPath));
103                         }
104                         return taskGroup;
105                 }
106
107                 private async Task<byte[][]> ReadNoThrow(string readPath)
108                 {
109                         try
110                         {
111                                 return await Task.Run(() => FileHelper.CreatePngReader(readPath).ReadRowsByte().ScanlinesB);
112                         }
113                         catch (Exception e)
114                         {
115                                 Console.WriteLine(e.Message);
116                                 return null;
117                         } // do nothing on error
118                 }
119         }
120 }