Browse Source

Fixed ClipboardController converting image to premultiplied one if it wasnt Pbgra32 and used fixed keyword for ToPbgra32ByteArray()

CPKreuz 3 years ago
parent
commit
37ca2da702

+ 73 - 0
PixiEditor/Helpers/Extensions/PixelFormatHelper.cs

@@ -0,0 +1,73 @@
+using SkiaSharp;
+using System;
+using System.Windows.Media;
+
+namespace PixiEditor.Helpers.Extensions
+{
+    public static class PixelFormatHelper
+    {
+        public static SKColorType ToSkia(this PixelFormat format, out SKAlphaType alphaType)
+        {
+            if (TryToSkia(format, out SKColorType color, out alphaType))
+            {
+                return color;
+            }
+            else
+            {
+                throw new NotImplementedException($"Skia does not support the '{format}' format");
+            }
+        }
+
+        public static bool TryToSkia(this PixelFormat format, out SKColorType colorType, out SKAlphaType alphaType)
+        {
+            if (format == PixelFormats.Rgba64)
+            {
+                alphaType = SKAlphaType.Unpremul;
+                colorType = SKColorType.Rgba16161616;
+                return true;
+            }
+            else if (format == PixelFormats.Bgra32)
+            {
+                alphaType = SKAlphaType.Unpremul;
+                colorType = SKColorType.Bgra8888;
+                return true;
+            }
+            else if (format == PixelFormats.Default)
+            {
+                alphaType = SKAlphaType.Unpremul;
+                colorType = SKColorType.RgbaF16;
+                return true;
+            }
+            else if (format == PixelFormats.Gray8)
+            {
+                alphaType = SKAlphaType.Opaque;
+                colorType = SKColorType.Gray8;
+                return true;
+            }
+            else if (format == PixelFormats.Pbgra32)
+            {
+                alphaType = SKAlphaType.Premul;
+                colorType = SKColorType.Bgra8888;
+                return true;
+            }
+            else if (format == PixelFormats.Bgr101010 || format == PixelFormats.Bgr24 || format == PixelFormats.Bgr32 || format == PixelFormats.Bgr555 ||
+                     format == PixelFormats.Bgr565 || format == PixelFormats.BlackWhite || format == PixelFormats.Cmyk32 || format == PixelFormats.Gray16 ||
+                     format == PixelFormats.Gray2 || format == PixelFormats.Gray32Float || format == PixelFormats.Gray4 || format == PixelFormats.Indexed1 ||
+                     format == PixelFormats.Indexed2 || format == PixelFormats.Indexed4 || format == PixelFormats.Indexed8 || format == PixelFormats.Prgba128Float ||
+                     format == PixelFormats.Prgba64 || format == PixelFormats.Rgb128Float || format == PixelFormats.Rgb24 || format == PixelFormats.Rgb48 ||
+                     format == PixelFormats.Rgba128Float)
+            {
+                alphaType = SKAlphaType.Unknown;
+                colorType = SKColorType.Unknown;
+                return false;
+            }
+
+            throw new NotImplementedException($"'{format}' has not been implemented by {nameof(PixelFormatHelper)}.{nameof(TryToSkia)}()");
+        }
+
+        public static bool IsSkiaSupported(this PixelFormat format)
+        {
+            return TryToSkia(format, out _, out _);
+        }
+    }
+}

+ 7 - 7
PixiEditor/Models/Controllers/ClipboardController.cs

@@ -127,6 +127,11 @@ namespace PixiEditor.Models.Controllers
                     yield return (tempSurface.Crop(crop.OffsetX, crop.OffsetY, crop.Width, crop.Height), layer.Name);
                     yield return (tempSurface.Crop(crop.OffsetX, crop.OffsetY, crop.Width, crop.Height), layer.Name);
                 }
                 }
             }
             }
+            else if (TryFromSingleImage(data, out Surface singleImage))
+            {
+                yield return (singleImage, "Copied");
+                yield break;
+            }
             else if(data.GetDataPresent(DataFormats.FileDrop))
             else if(data.GetDataPresent(DataFormats.FileDrop))
             {
             {
                 foreach (string path in data.GetFileDropList())
                 foreach (string path in data.GetFileDropList())
@@ -136,11 +141,6 @@ namespace PixiEditor.Models.Controllers
 
 
                 yield break;
                 yield break;
             }
             }
-            else if (TryFromSingleImage(data, out Surface singleImage))
-            {
-                yield return (singleImage, "Copied");
-                yield break;
-            }
             else
             else
             {
             {
                 throw new NotImplementedException();
                 throw new NotImplementedException();
@@ -213,7 +213,7 @@ namespace PixiEditor.Models.Controllers
                 return false;
                 return false;
             }
             }
 
 
-            if (source.Format == PixelFormats.Pbgra32)
+            if (source.Format.IsSkiaSupported())
             {
             {
                 result = new Surface(source);
                 result = new Surface(source);
             }
             }
@@ -222,7 +222,7 @@ namespace PixiEditor.Models.Controllers
                 FormatConvertedBitmap newFormat = new FormatConvertedBitmap();
                 FormatConvertedBitmap newFormat = new FormatConvertedBitmap();
                 newFormat.BeginInit();
                 newFormat.BeginInit();
                 newFormat.Source = source;
                 newFormat.Source = source;
-                newFormat.DestinationFormat = PixelFormats.Pbgra32;
+                newFormat.DestinationFormat = PixelFormats.Rgba64;
                 newFormat.EndInit();
                 newFormat.EndInit();
 
 
                 result = new Surface(newFormat);
                 result = new Surface(newFormat);

+ 18 - 21
PixiEditor/Models/DataHolders/Surface.cs

@@ -1,6 +1,6 @@
-using SkiaSharp;
+using PixiEditor.Helpers.Extensions;
+using SkiaSharp;
 using System;
 using System;
-using System.Runtime.InteropServices;
 using System.Windows;
 using System.Windows;
 using System.Windows.Media;
 using System.Windows.Media;
 using System.Windows.Media.Imaging;
 using System.Windows.Media.Imaging;
@@ -43,13 +43,12 @@ namespace PixiEditor.Models.DataHolders
                 throw new ArgumentException("Surface dimensions must be non-zero");
                 throw new ArgumentException("Surface dimensions must be non-zero");
             Width = w;
             Width = w;
             Height = h;
             Height = h;
-            SkiaSurface = Pbgra32BytesToSkSurface(w, h, pbgra32Bytes);
+            SkiaSurface = BytesToSkSurface(w, h, pbgra32Bytes, SKColorType.Bgra8888, SKAlphaType.Premul);
         }
         }
 
 
         public Surface(BitmapSource original)
         public Surface(BitmapSource original)
         {
         {
-            if (original.Format != PixelFormats.Pbgra32)
-                throw new ArgumentException("This method only supports Pbgra32 bitmaps");
+            SKColorType color = original.Format.ToSkia(out SKAlphaType alpha);
             if (original.PixelWidth <= 0 || original.PixelHeight <= 0)
             if (original.PixelWidth <= 0 || original.PixelHeight <= 0)
                 throw new ArgumentException("Surface dimensions must be non-zero");
                 throw new ArgumentException("Surface dimensions must be non-zero");
 
 
@@ -58,7 +57,7 @@ namespace PixiEditor.Models.DataHolders
 
 
             Width = original.PixelWidth;
             Width = original.PixelWidth;
             Height = original.PixelHeight;
             Height = original.PixelHeight;
-            SkiaSurface = Pbgra32BytesToSkSurface(Width, Height, pixels);
+            SkiaSurface = BytesToSkSurface(Width, Height, pixels, color, alpha);
         }
         }
 
 
         public Surface(SKImage image)
         public Surface(SKImage image)
@@ -99,22 +98,20 @@ namespace PixiEditor.Models.DataHolders
             SkiaSurface.Canvas.DrawPoint(x, y, drawingPaint);
             SkiaSurface.Canvas.DrawPoint(x, y, drawingPaint);
         }
         }
 
 
-        public byte[] ToPbgra32ByteArray()
+        public unsafe byte[] ToPbgra32ByteArray()
         {
         {
             var imageInfo = new SKImageInfo(Width, Height, SKColorType.Bgra8888, SKAlphaType.Premul, SKColorSpace.CreateSrgb());
             var imageInfo = new SKImageInfo(Width, Height, SKColorType.Bgra8888, SKAlphaType.Premul, SKColorSpace.CreateSrgb());
-            var buffer = Marshal.AllocHGlobal(Width * Height * 4);
-            try
-            {
-                using SKSurface surface = SKSurface.Create(imageInfo, buffer, Width * 4);
-                SkiaSurface.Draw(surface.Canvas, 0, 0, ReplacingPaint);
-                byte[] managed = new byte[Width * Height * 4];
-                Marshal.Copy(buffer, managed, 0, Width * Height * 4);
-                return managed;
-            }
-            finally
+
+            byte[] buffer = new byte[Width * Height * 4];
+            fixed (void* pointer = buffer)
             {
             {
-                Marshal.FreeHGlobal(buffer);
+                using SKPixmap map = new(imageInfo, new IntPtr(pointer));
+                using SKSurface surface = SKSurface.Create(map);
+                var newSurface = CreateSurface(Width, Height);
+                surface.Draw(newSurface.Canvas, 0, 0, ReplacingPaint);
             }
             }
+
+            return buffer;
         }
         }
 
 
         public WriteableBitmap ToWriteableBitmap()
         public WriteableBitmap ToWriteableBitmap()
@@ -133,11 +130,11 @@ namespace PixiEditor.Models.DataHolders
             SkiaSurface.Dispose();
             SkiaSurface.Dispose();
         }
         }
 
 
-        private static unsafe SKSurface Pbgra32BytesToSkSurface(int w, int h, byte[] pbgra32Bytes)
+        private static unsafe SKSurface BytesToSkSurface(int w, int h, byte[] bytes, SKColorType colorType, SKAlphaType alphaType)
         {
         {
-            SKImageInfo info = new SKImageInfo(w, h, SKColorType.Bgra8888, SKAlphaType.Premul);
+            SKImageInfo info = new SKImageInfo(w, h, colorType, alphaType);
 
 
-            fixed (void* pointer = pbgra32Bytes)
+            fixed (void* pointer = bytes)
             {
             {
                 using SKPixmap map = new(info, new IntPtr(pointer));
                 using SKPixmap map = new(info, new IntPtr(pointer));
                 using SKSurface surface = SKSurface.Create(map);
                 using SKSurface surface = SKSurface.Create(map);