소스 검색

Merge pull request #328 from PixiEditor/rect-based-undo-fixes

Fixed some StorageBasedUndo cases?
Krzysztof Krysiński 3 년 전
부모
커밋
8f326c07d5

+ 8 - 2
PixiEditor/Helpers/Extensions/Int32RectEx.cs

@@ -1,9 +1,10 @@
-using System;
+using SkiaSharp;
+using System;
 using System.Windows;
 
 namespace PixiEditor.Helpers.Extensions
 {
-    static class Int32RectEx
+    public static class Int32RectEx
     {
         public static Int32Rect Intersect(this Int32Rect rect, Int32Rect other)
         {
@@ -50,5 +51,10 @@ namespace PixiEditor.Helpers.Extensions
 
             return new Int32Rect(minX1, minY1, width, height);
         }
+
+        public static SKRectI ToSKRectI(this Int32Rect rect)
+        {
+            return new SKRectI(rect.X, rect.Y, rect.X + rect.Width, rect.Y + rect.Height);
+        }
     }
 }

+ 13 - 0
PixiEditor/Helpers/Extensions/SKRectIEx.cs

@@ -0,0 +1,13 @@
+using SkiaSharp;
+using System.Windows;
+
+namespace PixiEditor.Helpers.Extensions
+{
+    public static class SKRectIEx
+    {
+        public static Int32Rect ToInt32Rect(this SKRectI rect)
+        {
+            return new Int32Rect(rect.Left, rect.Top, rect.Width, rect.Height);
+        }
+    }
+}

+ 1 - 0
PixiEditor/Models/DataHolders/Document/Document.Operations.cs

@@ -7,6 +7,7 @@ using SkiaSharp;
 using System;
 using System.Linq;
 using System.Windows;
+using Windows.Graphics;
 
 namespace PixiEditor.Models.DataHolders
 {

+ 3 - 0
PixiEditor/Models/Layers/Layer.cs

@@ -9,6 +9,7 @@ using System.Collections.Generic;
 using System.Diagnostics;
 using System.Linq;
 using System.Windows;
+using Windows.Graphics;
 
 namespace PixiEditor.Models.Layers
 {
@@ -208,6 +209,8 @@ namespace PixiEditor.Models.Layers
 
         public bool IsReset { get; private set; }
 
+        public Int32Rect TightBounds => GetContentDimensions();
+
         public event EventHandler<Int32Rect> LayerBitmapChanged;
 
         public void InvokeLayerBitmapChange()

+ 1 - 1
PixiEditor/Models/Tools/BitmapOperationTool.cs

@@ -56,7 +56,7 @@ namespace PixiEditor.Models.Tools
             Document doc = ViewModels.ViewModelMain.Current.BitmapManager.ActiveDocument;
             var toolSize = Toolbar.GetSetting<SizeSetting>("ToolSize");
             SKRectI finalRect = toolSessionRect;
-            if (toolSize != null)
+            if (toolSize != null && toolSize.Value > 1)
             {
                 int halfSize = (int)Math.Ceiling(toolSize.Value / 2f);
                 finalRect.Inflate(halfSize, halfSize);

+ 1 - 1
PixiEditor/Models/Tools/Tools/MoveTool.cs

@@ -69,7 +69,7 @@ namespace PixiEditor.Models.Tools.Tools
                 affectedLayers = doc.Layers.Where(x => x.IsActive && doc.GetFinalLayerIsVisible(x)).ToArray();
             }
 
-            change = new StorageBasedChange(doc, affectedLayers, true);
+            change = new StorageBasedChange(doc, affectedLayers, true, true);
 
             Layer selLayer = selection.SelectionLayer;
             moveStartRect = anySelection ?

+ 44 - 52
PixiEditor/Models/Undo/StorageBasedChange.cs

@@ -1,9 +1,11 @@
-using PixiEditor.Models.DataHolders;
+using PixiEditor.Helpers.Extensions;
+using PixiEditor.Models.DataHolders;
 using PixiEditor.Models.IO;
 using PixiEditor.Models.Layers;
 using SkiaSharp;
 using System;
 using System.Collections.Generic;
+using System.Diagnostics;
 using System.IO;
 using System.Linq;
 using System.Text;
@@ -31,6 +33,12 @@ namespace PixiEditor.Models.Undo
             Initialize(layers, DefaultUndoChangeLocation, saveOnStartup);
         }
 
+        public StorageBasedChange(Document doc, IEnumerable<Layer> layers, bool useDocumentSize, bool saveOnStartup)
+        {
+            Document = doc;
+            Initialize(layers, DefaultUndoChangeLocation, saveOnStartup, useDocumentSize);
+        }
+
         public StorageBasedChange(Document doc, IEnumerable<Layer> layers, string undoChangeLocation, bool saveOnStartup = true)
         {
             Document = doc;
@@ -57,14 +65,27 @@ namespace PixiEditor.Models.Undo
             }
         }
 
-        private void Initialize(IEnumerable<Layer> layers, string undoChangeLocation, bool saveOnStartup)
+        private void Initialize(IEnumerable<Layer> layers, string undoChangeLocation, bool saveOnStartup, bool useDocumentSize = false)
         {
             var layersArray = layers as Layer[] ?? layers.ToArray();
             LayerChunk[] layerChunks = new LayerChunk[layersArray.Length];
             for (var i = 0; i < layersArray.Length; i++)
             {
                 var layer = layersArray[i];
-                layerChunks[i] = new LayerChunk(layer, SKRectI.Create(layer.OffsetX, layer.OffsetY, layer.Width, layer.Height));
+                int width = layer.Width;
+                int height = layer.Height;
+                int offsetX = layer.OffsetX;
+                int offsetY = layer.OffsetY;
+
+                if (useDocumentSize)
+                {
+                    width = layer.MaxWidth;
+                    height = layer.MaxHeight;
+                    offsetX = 0;
+                    offsetY = 0;
+                }
+
+                layerChunks[i] = new LayerChunk(layer, SKRectI.Create(offsetX, offsetY, width, height));
                 layersToStore.Add(layer.GuidValue);
             }
 
@@ -97,6 +118,8 @@ namespace PixiEditor.Models.Undo
 
                     targetSizeSurface.SkiaSurface.Canvas.DrawImage(image, finalRect, SKRect.Create(0, 0, finalRect.Width, finalRect.Height), Surface.ReplacingPaint);
 
+                    //DebugSavePng(targetSizeSurface, storedLayer);
+
                     Exporter.SaveAsGZippedBytes(storedLayer.StoredPngLayerName, targetSizeSurface);
                 }
 
@@ -106,6 +129,19 @@ namespace PixiEditor.Models.Undo
             layersToStore = new List<Guid>();
         }
 
+        [Conditional("DEBUG")]
+        private static void DebugSavePng(Surface surface, UndoLayer storedLayer)
+        {
+            //Debug png visualization
+            using var targetSizeImage = surface.SkiaSurface.Snapshot();
+            using (var data = targetSizeImage.Encode(SKEncodedImageFormat.Png, 100))
+            using (var stream = File.OpenWrite(storedLayer.StoredPngLayerName + ".png"))
+            {
+                // save the data to a stream
+                data.SaveTo(stream);
+            }
+        }
+
         /// <summary>
         /// Loads saved layers from disk.
         /// </summary>
@@ -319,7 +355,7 @@ namespace PixiEditor.Models.Undo
 
                     if (foundLayer != null)
                     {
-                        ApplyChunkToLayer(foundLayer, layerData, layer.LayerBitmap);
+                        ApplyChunkToLayer(foundLayer, layerData.SerializedRect, layer.LayerBitmap);
                     }
                     else
                     {
@@ -335,56 +371,12 @@ namespace PixiEditor.Models.Undo
             }
         }
 
-        private static void ApplyChunkToLayer(Layer layer, UndoLayer layerData, Surface chunk)
+        private static void ApplyChunkToLayer(Layer layer, SKRectI rect, Surface chunk)
         {
-            bool widthBigger = layer.Width < chunk.Width;
-            bool heightBigger = layer.Height < chunk.Height;
-            int targetWidth = widthBigger ? chunk.Width : layer.Width;
-            int targetHeight = heightBigger ? chunk.Height : layer.Height;
-
-            targetWidth = Math.Clamp(targetWidth, 0, layerData.MaxWidth);
-            targetHeight = Math.Clamp(targetHeight, 0, layerData.MaxHeight);
-
-            int offsetDiffX = layerData.OffsetX - layer.OffsetX;
-            int offsetDiffY = layerData.OffsetY - layer.OffsetY;
-
-            // Experiment with this, there is a bug, but I still don't know where. Code below might help
-            //if (widthBigger) offsetDiffX += chunk.Width - layer.Width;
-            //if (heightBigger) offsetDiffY += chunk.Height - layer.Height;
-
-            bool offsetXBigger = Math.Abs(offsetDiffX) > 0;
-            bool offsetYBigger = Math.Abs(offsetDiffY) > 0;
-
-            int targetOffsetX = offsetXBigger ? layerData.SerializedRect.Left : layerData.OffsetX;
-            int targetOffsetY = offsetYBigger ? layerData.SerializedRect.Top : layerData.OffsetY;
-
-            targetOffsetX = Math.Max(0, targetOffsetX);
-            targetOffsetY = Math.Max(0, targetOffsetY);
-
-            Surface targetSizeSurface = new Surface(targetWidth, targetHeight);
-            using var foundLayerSnapshot = layer.LayerBitmap.SkiaSurface.Snapshot();
-            targetSizeSurface.SkiaSurface.Canvas.DrawImage(
-                foundLayerSnapshot,
-                SKRect.Create(offsetDiffX, offsetDiffY, layer.Width, layer.Height),
-                SKRect.Create(0, 0, targetWidth, targetHeight),
-                Surface.ReplacingPaint);
-
-            layer.Offset = new Thickness(targetOffsetX, targetOffsetY, 0, 0);
-
-            SKRect finalRect = SKRect.Create(
-                layerData.SerializedRect.Left - layer.OffsetX,
-                layerData.SerializedRect.Top - layer.OffsetY,
-                layerData.SerializedRect.Width,
-                layerData.SerializedRect.Height);
-
+            layer.DynamicResizeAbsolute(rect.ToInt32Rect());
             using var snapshot = chunk.SkiaSurface.Snapshot();
-
-            targetSizeSurface.SkiaSurface.Canvas.DrawImage(
-                snapshot,
-                finalRect,
-                Surface.ReplacingPaint);
-
-            layer.LayerBitmap = targetSizeSurface;
+            layer.LayerBitmap.SkiaSurface.Canvas.DrawImage(snapshot, new SKPoint(rect.Left - layer.OffsetX, rect.Top - layer.OffsetY), Surface.ReplacingPaint);
+            layer.InvokeLayerBitmapChange(rect.ToInt32Rect());
         }
 
         public void Dispose()

+ 32 - 0
PixiEditorTests/ModelsTests/PositionTests/RectTests.cs

@@ -0,0 +1,32 @@
+using PixiEditor.Helpers.Extensions;
+using SkiaSharp;
+using System.Windows;
+using Xunit;
+
+namespace PixiEditorTests.ModelsTests.PositionTests
+{
+    public class RectTests
+    {
+        [Fact]
+        public void TestThatInt32RectToSKRectIWorks()
+        {
+            Int32Rect rect = new Int32Rect(5, 2, 8, 10);
+            SKRectI converted = rect.ToSKRectI();
+            Assert.Equal(rect.X, converted.Left);
+            Assert.Equal(rect.Y, converted.Top);
+            Assert.Equal(rect.Width, converted.Width);
+            Assert.Equal(rect.Height, converted.Height);
+        }
+
+        [Fact]
+        public void TestThatSKRectIToInt32RectWorks()
+        {
+            SKRectI rect = new SKRectI(5, 2, 8, 10);
+            Int32Rect converted = rect.ToInt32Rect();
+            Assert.Equal(rect.Left, converted.X);
+            Assert.Equal(rect.Top, converted.Y);
+            Assert.Equal(rect.Width, converted.Width);
+            Assert.Equal(rect.Height, converted.Height);
+        }
+    }
+}