Bladeren bron

Import bitmap fix

Krzysztof Krysiński 2 jaren geleden
bovenliggende
commit
0283675fc1

+ 1 - 1
src/PixiEditor.AvaloniaUI/Helpers/SurfaceHelpers.cs

@@ -26,7 +26,7 @@ public static class SurfaceHelpers
 
     public static WriteableBitmap ToWriteableBitmap(this Surface surface)
     {
-        WriteableBitmap result = WriteableBitmapHelpers.CreateBitmap(surface.Size);
+        WriteableBitmap result = WriteableBitmapUtility.CreateBitmap(surface.Size);
         using var framebuffer = result.Lock();
         var dirty = new RectI(0, 0, surface.Size.X, surface.Size.Y);
         framebuffer.WritePixels(dirty, ToByteArray(surface));

+ 1 - 1
src/PixiEditor.AvaloniaUI/Helpers/WriteableBitmapHelpers.cs → src/PixiEditor.AvaloniaUI/Helpers/WriteableBitmapUtility.cs

@@ -8,7 +8,7 @@ using PixiEditor.DrawingApi.Core.Surface.ImageData;
 
 namespace PixiEditor.AvaloniaUI.Helpers;
 
-internal static class WriteableBitmapHelpers
+public static class WriteableBitmapUtility
 {
     public static WriteableBitmap FromBgra8888Array(byte[] bgra8888, VecI size)
     {

+ 4 - 4
src/PixiEditor.AvaloniaUI/Models/DocumentModels/DocumentUpdater.cs

@@ -276,8 +276,8 @@ internal class DocumentUpdater
         foreach ((ChunkResolution res, DrawingSurface surf) in doc.Surfaces)
         {
             surf.Dispose();
-            newBitmaps[res] = WriteableBitmapHelpers.CreateBitmap((VecI)(info.Size * res.Multiplier()));
-            doc.Surfaces[res] = WriteableBitmapHelpers.CreateDrawingSurface(newBitmaps[res]);
+            newBitmaps[res] = WriteableBitmapUtility.CreateBitmap((VecI)(info.Size * res.Multiplier()));
+            doc.Surfaces[res] = WriteableBitmapUtility.CreateDrawingSurface(newBitmaps[res]);
         }
 
         doc.LazyBitmaps = newBitmaps;
@@ -288,8 +288,8 @@ internal class DocumentUpdater
 
         VecI documentPreviewSize = StructureHelpers.CalculatePreviewSize(info.Size);
         doc.PreviewSurface.Dispose();
-        doc.PreviewBitmap = WriteableBitmapHelpers.CreateBitmap(documentPreviewSize);
-        doc.PreviewSurface = WriteableBitmapHelpers.CreateDrawingSurface(doc.PreviewBitmap);
+        doc.PreviewBitmap = WriteableBitmapUtility.CreateBitmap(documentPreviewSize);
+        doc.PreviewSurface = WriteableBitmapUtility.CreateDrawingSurface(doc.PreviewBitmap);
 
         // TODO: Make sure property changed events are raised internally
         /*doc.OnPropertyChanged(nameof(doc.LazyBitmaps));

+ 1 - 10
src/PixiEditor.AvaloniaUI/Models/IO/Importer.cs

@@ -48,16 +48,7 @@ internal class Importer : ObservableObject
         try
         {
             Uri uri = new Uri(path, UriKind.RelativeOrAbsolute);
-            Bitmap bitmap = new Bitmap(path);
-
-            using MemoryStream stream = new();
-            bitmap.Save(stream);
-
-            IntPtr ptr = Marshal.AllocHGlobal((int)stream.Length);
-
-            WriteableBitmap writeableBitmap = new(bitmap.Format.Value, AlphaFormat.Premul, ptr, bitmap.PixelSize, bitmap.Dpi, bitmap.PixelSize.Width * 4);
-
-            return writeableBitmap;
+            return new Bitmap(path).ToWriteableBitmap();
         }
         catch (NotSupportedException e)
         {

+ 1 - 1
src/PixiEditor.AvaloniaUI/Models/IO/PaletteParsers/PngPaletteParser.cs

@@ -111,7 +111,7 @@ internal class PngPaletteParser : PaletteFileParser
     {
         await Task.Run(() =>
         {
-            WriteableBitmap bitmap = WriteableBitmapHelpers.CreateBitmap(new VecI(data.Colors.Length, 1));
+            WriteableBitmap bitmap = WriteableBitmapUtility.CreateBitmap(new VecI(data.Colors.Length, 1));
             using var framebuffer = bitmap.Lock();
             for (int i = 0; i < data.Colors.Length; i++)
             {

+ 4 - 4
src/PixiEditor.AvaloniaUI/Models/Rendering/MemberPreviewUpdater.cs

@@ -222,8 +222,8 @@ internal class MemberPreviewUpdater
                 else
                 {
                     member.PreviewSurface?.Dispose();
-                    member.PreviewBitmap = WriteableBitmapHelpers.CreateBitmap(newSize.Value.previewSize);
-                    member.PreviewSurface = WriteableBitmapHelpers.CreateDrawingSurface(member.PreviewBitmap);
+                    member.PreviewBitmap = WriteableBitmapUtility.CreateBitmap(newSize.Value.previewSize);
+                    member.PreviewSurface = WriteableBitmapUtility.CreateDrawingSurface(member.PreviewBitmap);
                 }
             }
 
@@ -244,8 +244,8 @@ internal class MemberPreviewUpdater
             }
             else
             {
-                member.MaskPreviewBitmap = WriteableBitmapHelpers.CreateBitmap(newSize.Value.previewSize);
-                member.MaskPreviewSurface = WriteableBitmapHelpers.CreateDrawingSurface(member.MaskPreviewBitmap);
+                member.MaskPreviewBitmap = WriteableBitmapUtility.CreateBitmap(newSize.Value.previewSize);
+                member.MaskPreviewSurface = WriteableBitmapUtility.CreateDrawingSurface(member.MaskPreviewBitmap);
             }
 
             //TODO: Make sure MaskPreviewBitmap implementation raises PropertyChanged

+ 7 - 7
src/PixiEditor.AvaloniaUI/ViewModels/Document/DocumentViewModel.cs

@@ -137,10 +137,10 @@ internal partial class DocumentViewModel : PixiObservableObject, IDocument
     public Dictionary<ChunkResolution, DrawingSurface> Surfaces { get; set; } = new();
     public Dictionary<ChunkResolution, WriteableBitmap> LazyBitmaps { get; set; } = new()
     {
-        [ChunkResolution.Full] = WriteableBitmapHelpers.CreateBitmap(new VecI(64, 64)),
-        [ChunkResolution.Half] = WriteableBitmapHelpers.CreateBitmap(new VecI(32, 32)),
-        [ChunkResolution.Quarter] = WriteableBitmapHelpers.CreateBitmap(new VecI(16, 16)),
-        [ChunkResolution.Eighth] = WriteableBitmapHelpers.CreateBitmap(new VecI(8, 8)),
+        [ChunkResolution.Full] = WriteableBitmapUtility.CreateBitmap(new VecI(64, 64)),
+        [ChunkResolution.Half] = WriteableBitmapUtility.CreateBitmap(new VecI(32, 32)),
+        [ChunkResolution.Quarter] = WriteableBitmapUtility.CreateBitmap(new VecI(16, 16)),
+        [ChunkResolution.Eighth] = WriteableBitmapUtility.CreateBitmap(new VecI(8, 8)),
     };
     public WriteableBitmap PreviewBitmap { get; set; }
     public DrawingSurface PreviewSurface { get; set; }
@@ -186,13 +186,13 @@ internal partial class DocumentViewModel : PixiObservableObject, IDocument
 
         foreach (KeyValuePair<ChunkResolution, WriteableBitmap> bitmap in LazyBitmaps)
         {
-            DrawingSurface? surface = WriteableBitmapHelpers.CreateDrawingSurface(bitmap.Value);
+            DrawingSurface? surface = WriteableBitmapUtility.CreateDrawingSurface(bitmap.Value);
             Surfaces[bitmap.Key] = surface;
         }
 
         VecI previewSize = StructureMemberViewModel.CalculatePreviewSize(SizeBindable);
-        PreviewBitmap = WriteableBitmapHelpers.CreateBitmap(previewSize);
-        PreviewSurface = WriteableBitmapHelpers.CreateDrawingSurface(PreviewBitmap);
+        PreviewBitmap = WriteableBitmapUtility.CreateBitmap(previewSize);
+        PreviewSurface = WriteableBitmapUtility.CreateDrawingSurface(PreviewBitmap);
 
         ReferenceLayerViewModel = new(this, Internals);
     }

+ 2 - 2
src/PixiEditor.AvaloniaUI/ViewModels/Document/ReferenceLayerViewModel.cs

@@ -41,7 +41,7 @@ internal class ReferenceLayerViewModel : ObservableObject, IReferenceLayerHandle
         {
             if (ReferenceBitmap is null)
                 return Matrix.Identity;
-            Matrix3X3 skiaMatrix = OperationHelper.CreateMatrixFromPoints((ShapeCorners)ReferenceShapeBindable, new VecD(ReferenceBitmap.PixelSize.Width, ReferenceBitmap.PixelSize.Height));
+            Matrix3X3 skiaMatrix = OperationHelper.CreateMatrixFromPoints(ReferenceShapeBindable, new VecD(ReferenceBitmap.PixelSize.Width, ReferenceBitmap.PixelSize.Height));
             return new Matrix(skiaMatrix.ScaleX, skiaMatrix.SkewY, skiaMatrix.SkewX, skiaMatrix.ScaleY, skiaMatrix.TransX, skiaMatrix.TransY);
         }
     }
@@ -109,7 +109,7 @@ internal class ReferenceLayerViewModel : ObservableObject, IReferenceLayerHandle
     
     public void SetReferenceLayer(ImmutableArray<byte> imageBgra8888Bytes, VecI imageSize, ShapeCorners shape)
     {
-        ReferenceBitmap = WriteableBitmapHelpers.FromBgra8888Array(imageBgra8888Bytes.ToArray(), imageSize);
+        ReferenceBitmap = WriteableBitmapUtility.FromBgra8888Array(imageBgra8888Bytes.ToArray(), imageSize);
         referenceShape = shape;
         isVisible = true;
         isTransforming = false;

+ 3 - 4
src/PixiEditor.AvaloniaUI/Views/Main/Viewport.axaml

@@ -169,12 +169,12 @@
                             IsVisible="{Binding Document.ReferenceLayerViewModel.IsVisibleBindable}"
                             SizeChanged="OnReferenceImageSizeChanged"
                             FlowDirection="LeftToRight">
-                            <!--<Image.RenderTransform>
+                            <Image.RenderTransform>
                                 <TransformGroup>
                                     <MatrixTransform
                                         Matrix="{Binding Document.ReferenceLayerViewModel.ReferenceTransformMatrix}" />
                                 </TransformGroup>
-                            </Image.RenderTransform>-->
+                            </Image.RenderTransform>
                             <Image.Styles>
                                 <!--TODO: Implement this-->
                                 <!--<Style>
@@ -231,12 +231,12 @@
                             </Style>-->
                         </Canvas.Styles>
                     </Canvas>
-                    <!--TODO: RenderOptions.BitmapInterpolationMode="{Binding Zoombox.Scale, Converter={converters:ScaleToBitmapScalingModeConverter}}"-->
                     <Image
                         Focusable="False"
                         Width="{Binding Document.Width}"
                         Height="{Binding Document.Height}"
                         Source="{Binding TargetBitmap}"
+                        ui1:RenderOptionsBindable.BitmapInterpolationMode="{Binding Zoombox.Scale, Converter={converters:ScaleToBitmapScalingModeConverter}}"
                         FlowDirection="LeftToRight">
                         <Image.Styles>
                             <!--TODO: Implement-->
@@ -267,7 +267,6 @@
                         </Image.Styles>
                     </Image>
                     <Grid ZIndex="5">
-                        <!--TODO: Implement overlays-->
                         <symmetryOverlay:SymmetryOverlay
                             Focusable="False"
                             IsHitTestVisible="{Binding ZoomMode, Converter={converters:ZoomModeToHitTestVisibleConverter}}"

+ 1 - 1
src/PixiEditor.Tests/AvaloniaTestRunner.cs

@@ -56,7 +56,7 @@ namespace PixiEditor.Tests
                     try
                     {
                         PixiEditor.AvaloniaUI.Desktop.Program.BuildAvaloniaApp()
-                            .UseHeadless(new AvaloniaHeadlessPlatformOptions { FrameBufferFormat = PixelFormat.Bgra8888, UseHeadlessDrawing = true })
+                            .UseHeadless(new AvaloniaHeadlessPlatformOptions { FrameBufferFormat = PixelFormat.Bgra8888, UseHeadlessDrawing = false })
                             .SetupWithoutStarting();
                         tcs.SetResult(SynchronizationContext.Current);
                     }

+ 43 - 7
src/PixiEditor.Tests/FramebufferExtensionTests.cs

@@ -1,12 +1,9 @@
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
 using Avalonia;
 using Avalonia.Media;
 using Avalonia.Media.Imaging;
 using Avalonia.Platform;
 using PixiEditor.AvaloniaUI.Helpers.Extensions;
 using PixiEditor.DrawingApi.Core.Numerics;
-using SkiaSharp;
 
 namespace PixiEditor.Tests;
 
@@ -40,6 +37,26 @@ public class FramebufferExtensionTests
         Assert.Equal(a, pixels[3]);
     }
 
+    [Theory]
+    [InlineData(255, 0, 0, 255)]
+    [InlineData(0, 255, 0, 255)]
+    [InlineData(0, 0, 255, 255)]
+    [InlineData(255, 255, 255, 255)]
+    [InlineData(0, 0, 0, 255)]
+    [InlineData(255, 255, 255, 0)]
+    [InlineData(0, 0, 0, 0)]
+    public void TestThatWritePixelsSetsCorrectColor(byte r, byte g, byte b, byte a)
+    {
+        var bitmap = new WriteableBitmap(new PixelSize(1, 1), new Vector(96, 96), PixelFormats.Bgra8888);
+        using var framebuffer = bitmap.Lock();
+        framebuffer.WritePixels(new RectI(0, 0, 1, 1), new byte[] { b, g, r, a });
+        var pixels = framebuffer.GetPixels();
+        Assert.Equal(r, pixels[2]);
+        Assert.Equal(g, pixels[1]);
+        Assert.Equal(b, pixels[0]);
+        Assert.Equal(a, pixels[3]);
+    }
+
     [Theory]
     [InlineData(255, 0, 0, 255)]
     [InlineData(0, 255, 0, 255)]
@@ -60,16 +77,35 @@ public class FramebufferExtensionTests
         Assert.Equal(a, color.A);
     }
 
-    /*[Fact]
+    [Fact]
     public void TestThatExtractPixelsFromBitmapReturnsCorrectBgra8888ByteSequence()
     {
         var bitmap = new WriteableBitmap(new PixelSize(4, 1), new Vector(96, 96), PixelFormats.Bgra8888);
         using var framebuffer = bitmap.Lock();
-        framebuffer.WritePixel();
+        framebuffer.WritePixel(0, 0, Color.FromArgb(255, 255, 0, 0)); //Red
+        framebuffer.WritePixel(1, 0, Color.FromArgb(255, 0, 255, 0)); //Green
+        framebuffer.WritePixel(2, 0, Color.FromArgb(255, 0, 0, 255)); //Blue
+        framebuffer.WritePixel(3, 0, Color.FromArgb(255, 255, 255, 255)); //White
         var pixels = bitmap.ExtractPixels();
 
-        Assert.Equal(4, pixels.Length);
         Assert.Equal(0, pixels[0]);
         Assert.Equal(0, pixels[1]);
-    }*/
+        Assert.Equal(255, pixels[2]);
+        Assert.Equal(255, pixels[3]);
+
+        Assert.Equal(0, pixels[4]);
+        Assert.Equal(255, pixels[5]);
+        Assert.Equal(0, pixels[6]);
+        Assert.Equal(255, pixels[7]);
+
+        Assert.Equal(255, pixels[8]);
+        Assert.Equal(0, pixels[9]);
+        Assert.Equal(0, pixels[10]);
+        Assert.Equal(255, pixels[11]);
+
+        Assert.Equal(255, pixels[12]);
+        Assert.Equal(255, pixels[13]);
+        Assert.Equal(255, pixels[14]);
+        Assert.Equal(255, pixels[15]);
+    }
 }

+ 37 - 0
src/PixiEditor.Tests/WriteableBitmapUtilityTests.cs

@@ -0,0 +1,37 @@
+using Avalonia.Media;
+using Avalonia.Media.Imaging;
+using Avalonia.Platform;
+using PixiEditor.AvaloniaUI.Helpers;
+using PixiEditor.AvaloniaUI.Helpers.Extensions;
+using PixiEditor.DrawingApi.Core.Numerics;
+
+namespace PixiEditor.Tests;
+
+public class WriteableBitmapUtilityTests
+{
+    [Fact]
+    public void TestThatFromBgra8888ArrayReturnsCorrectWriteableBitmap()
+    {
+        byte[] bgra8888 = new byte[4];
+        Color color = Color.FromArgb(5, 150, 200, 255);
+        bgra8888[0] = color.B;
+        bgra8888[1] = color.G;
+        bgra8888[2] = color.R;
+        bgra8888[3] = color.A;
+
+        VecI size = new(1, 1);
+        WriteableBitmap result = WriteableBitmapUtility.FromBgra8888Array(bgra8888, size);
+        Assert.NotNull(result);
+        Assert.Equal(1, result.PixelSize.Width);
+        Assert.Equal(1, result.PixelSize.Height);
+        Assert.Equal(96, result.Dpi.X);
+        Assert.Equal(96, result.Dpi.Y);
+        Assert.Equal(PixelFormats.Bgra8888, result.Format);
+
+        using ILockedFramebuffer frameBuffer = result.Lock();
+        Assert.Equal(4, frameBuffer.RowBytes);
+        Assert.Equal(1, frameBuffer.Size.Width);
+        Assert.Equal(1, frameBuffer.Size.Height);
+        Assert.Equal(color, frameBuffer.GetPixel(0, 0));
+    }
+}