Skip to content

Commit

Permalink
Fixed ClipboardController converting image to premultiplied one if it…
Browse files Browse the repository at this point in the history
… wasnt Pbgra32 and used fixed keyword for ToPbgra32ByteArray()
  • Loading branch information
CPKreu committed Oct 9, 2021
1 parent 1125355 commit 37ca2da
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 28 deletions.
73 changes: 73 additions & 0 deletions PixiEditor/Helpers/Extensions/PixelFormatHelper.cs
Original file line number Diff line number Diff line change
@@ -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 _);
}
}
}
14 changes: 7 additions & 7 deletions PixiEditor/Models/Controllers/ClipboardController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,11 @@ public static IEnumerable<(Surface, string name)> GetImagesFromClipboard()
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))
{
foreach (string path in data.GetFileDropList())
Expand All @@ -136,11 +141,6 @@ public static IEnumerable<(Surface, string name)> GetImagesFromClipboard()

yield break;
}
else if (TryFromSingleImage(data, out Surface singleImage))
{
yield return (singleImage, "Copied");
yield break;
}
else
{
throw new NotImplementedException();
Expand Down Expand Up @@ -213,7 +213,7 @@ private static bool TryFromSingleImage(DataObject data, out Surface result)
return false;
}

if (source.Format == PixelFormats.Pbgra32)
if (source.Format.IsSkiaSupported())
{
result = new Surface(source);
}
Expand All @@ -222,7 +222,7 @@ private static bool TryFromSingleImage(DataObject data, out Surface result)
FormatConvertedBitmap newFormat = new FormatConvertedBitmap();
newFormat.BeginInit();
newFormat.Source = source;
newFormat.DestinationFormat = PixelFormats.Pbgra32;
newFormat.DestinationFormat = PixelFormats.Rgba64;
newFormat.EndInit();

result = new Surface(newFormat);
Expand Down
39 changes: 18 additions & 21 deletions PixiEditor/Models/DataHolders/Surface.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using SkiaSharp;
using PixiEditor.Helpers.Extensions;
using SkiaSharp;
using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
Expand Down Expand Up @@ -43,13 +43,12 @@ public Surface(int w, int h, byte[] pbgra32Bytes)
throw new ArgumentException("Surface dimensions must be non-zero");
Width = w;
Height = h;
SkiaSurface = Pbgra32BytesToSkSurface(w, h, pbgra32Bytes);
SkiaSurface = BytesToSkSurface(w, h, pbgra32Bytes, SKColorType.Bgra8888, SKAlphaType.Premul);
}

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)
throw new ArgumentException("Surface dimensions must be non-zero");

Expand All @@ -58,7 +57,7 @@ public Surface(BitmapSource original)

Width = original.PixelWidth;
Height = original.PixelHeight;
SkiaSurface = Pbgra32BytesToSkSurface(Width, Height, pixels);
SkiaSurface = BytesToSkSurface(Width, Height, pixels, color, alpha);
}

public Surface(SKImage image)
Expand Down Expand Up @@ -99,22 +98,20 @@ public void SetSRGBPixel(int x, int y, SKColor color)
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 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()
Expand All @@ -133,11 +130,11 @@ public void 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 SKSurface surface = SKSurface.Create(map);
Expand Down

0 comments on commit 37ca2da

Please sign in to comment.