ソースを参照

Save only non empty chunks for ChunkyImage

Krzysztof Krysiński 2 週間 前
コミット
09ac7076e6

+ 20 - 0
src/ChunkyImageLib/ChunkyImage.cs

@@ -1184,6 +1184,26 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable, ICloneable, ICache
         }
     }
 
+    public Dictionary<VecI, Surface> CloneAllCommitedNonEmptyChunks()
+    {
+        lock (lockObject)
+        {
+            ThrowIfDisposed();
+            var dict = new Dictionary<VecI, Surface>();
+            foreach (var (pos, chunk) in committedChunks[ChunkResolution.Full])
+            {
+                if (chunk.FindPreciseBounds().HasValue)
+                {
+                    var surf = new Surface(chunk.Surface.ImageInfo);
+                    surf.DrawingSurface.Canvas.DrawSurface(chunk.Surface.DrawingSurface, 0, 0);
+                    dict[pos] = surf;
+                }
+            }
+
+            return dict;
+        }
+    }
+
     /// <returns>
     /// Chunks affected by operations that haven't been committed yet
     /// </returns>

+ 5 - 0
src/PixiEditor/Models/Serialization/Factories/ByteBuilder.cs

@@ -83,4 +83,9 @@ public class ByteBuilder
     {
         _data.Add(value ? (byte)1 : (byte)0);
     }
+
+    public void AddByteArray(byte[] serialized)
+    {
+        _data.AddRange(serialized);
+    }
 }

+ 10 - 0
src/PixiEditor/Models/Serialization/Factories/ByteExtractor.cs

@@ -122,4 +122,14 @@ public class ByteExtractor
 
         return sb.ToString();
     }
+
+    public byte[] GetByteArray(int length)
+    {
+        byte[] value = new byte[length];
+        Array.Copy(_data, Position, value, 0, length);
+
+        Position += length;
+
+        return value;
+    }
 }

+ 61 - 18
src/PixiEditor/Models/Serialization/Factories/ChunkyImageSerializationFactory.cs

@@ -1,49 +1,92 @@
 using ChunkyImageLib;
 using ChunkyImageLib.DataHolders;
 using Drawie.Backend.Core;
+using Drawie.Backend.Core.Numerics;
 using Drawie.Backend.Core.Surfaces.PaintImpl;
 using Drawie.Numerics;
+using PixiEditor.Extensions.CommonApi.Utilities;
 
 namespace PixiEditor.Models.Serialization.Factories;
 
 public class ChunkyImageSerializationFactory : SerializationFactory<byte[], ChunkyImage>
 {
-    private static SurfaceSerializationFactory surfaceFactory = new();
-
     public override byte[] Serialize(ChunkyImage original)
     {
-        var encoder = Config.Encoder;
+        var chunks = original.CloneAllCommitedNonEmptyChunks();
+        ByteBuilder builder = new();
+        builder.AddVecD(original.CommittedSize);
+
+        SurfaceSerializationFactory surfaceFactory = new();
         surfaceFactory.Config = Config;
 
-        using Surface surface = new Surface(original.LatestSize);
-        original.DrawMostUpToDateRegionOn(
-            new RectI(0, 0, original.LatestSize.X,
-                original.LatestSize.Y), ChunkResolution.Full, surface.DrawingSurface, new VecI(0, 0), new Paint());
+        builder.AddInt(chunks.Count);
+        foreach (var chunk in chunks)
+        {
+            builder.AddVecD(chunk.Key);
+            byte[] serialized = surfaceFactory.Serialize(chunk.Value);
+            builder.AddInt(serialized.Length);
+            builder.AddByteArray(serialized);
+        }
 
-        return surfaceFactory.Serialize(surface);
+        return builder.Build();
     }
 
     public override bool TryDeserialize(object serialized, out ChunkyImage original,
         (string serializerName, string serializerVersion) serializerData)
     {
-        if (serialized is byte[] imgBytes)
+        SurfaceSerializationFactory surfaceFactory = new();
+        surfaceFactory.Config = Config;
+        if (IsFilePreVersion(serializerData, new Version(2, 0, 1, 12)))
+        {
+            if (serialized is byte[] imgBytes)
+            {
+                if (!surfaceFactory.TryDeserialize(imgBytes, out Surface surface, serializerData))
+                {
+                    original = null;
+                    return false;
+                }
+
+                original = new ChunkyImage(surface.Size, Config.ProcessingColorSpace);
+                original.EnqueueDrawImage(VecI.Zero, surface);
+                original.CommitChanges();
+                surface.Dispose();
+                return true;
+            }
+
+            original = null;
+            return false;
+        }
+
+        if (serialized is not byte[] bytes)
+        {
+            original = null;
+            return false;
+        }
+
+        ByteExtractor byteExtractor = new(bytes);
+        VecD size = byteExtractor.GetVecD();
+        original = new ChunkyImage((VecI)size, Config.ProcessingColorSpace);
+        int chunkCount = byteExtractor.GetInt();
+
+        for (int i = 0; i < chunkCount; i++)
         {
-            surfaceFactory.Config = Config;
-            if (!surfaceFactory.TryDeserialize(imgBytes, out Surface surface, serializerData))
+            VecD chunkPos = byteExtractor.GetVecD();
+            int chunkDataLength = byteExtractor.GetInt();
+            byte[] chunkData = byteExtractor.GetByteArray(chunkDataLength);
+            if (!surfaceFactory.TryDeserialize(chunkData, out Surface chunkSurface, serializerData))
             {
+                original.Dispose();
                 original = null;
                 return false;
             }
 
-            original = new ChunkyImage(surface.Size, Config.ProcessingColorSpace);
-            original.EnqueueDrawImage(VecI.Zero, surface);
-            original.CommitChanges();
-            surface.Dispose();
-            return true;
+            RectD chunkRect = new RectD(chunkPos * chunkSurface.Size.X, chunkSurface.Size);
+            original.EnqueueDrawImage((VecI)chunkRect.TopLeft, chunkSurface);
+            chunkSurface.Dispose();
         }
 
-        original = null;
-        return false;
+        original.CommitChanges();
+        return true;
     }
 
     public override string DeserializationId { get; } = "PixiEditor.ChunkyImage";

+ 2 - 2
src/PixiEditor/Properties/AssemblyInfo.cs

@@ -43,5 +43,5 @@ using System.Runtime.InteropServices;
 // You can specify all the values or you can default the Build and Revision Numbers
 // by using the '*' as shown below:
 // [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("2.0.1.11")]
-[assembly: AssemblyFileVersion("2.0.1.11")]
+[assembly: AssemblyVersion("2.0.1.12")]
+[assembly: AssemblyFileVersion("2.0.1.12")]