Browse Source

Most of backend code converted!

flabbet 2 years ago
parent
commit
0cb240a4f4
51 changed files with 356 additions and 217 deletions
  1. 2 2
      src/ChunkyImageLib/CommittedChunkStorage.cs
  2. 6 5
      src/ChunkyImageLib/Shaders/ShaderUtils.cs
  3. 3 6
      src/ChunkyImageLib/Surface.cs
  4. 23 21
      src/ChunkyImageLibTest/ChunkyImageTests.cs
  5. 8 7
      src/ChunkyImageLibTest/RectangleOperationTests.cs
  6. 2 0
      src/PixiEditor.DrawingApi.Core/Bridge/IDrawingBackend.cs
  7. 10 0
      src/PixiEditor.DrawingApi.Core/Bridge/NativeObjectsImpl/IBitmapImplementation.cs
  8. 1 1
      src/PixiEditor.DrawingApi.Core/Bridge/NativeObjectsImpl/IColorImplementation.cs
  9. 12 0
      src/PixiEditor.DrawingApi.Core/Bridge/NativeObjectsImpl/IImgDataImplementation.cs
  10. 4 0
      src/PixiEditor.DrawingApi.Core/Bridge/NativeObjectsImpl/IPixmapImplementation.cs
  11. 2 0
      src/PixiEditor.DrawingApi.Core/Bridge/Operations/ICanvasOperations.cs
  12. 1 0
      src/PixiEditor.DrawingApi.Core/Bridge/Operations/IImageOperations.cs
  13. 3 0
      src/PixiEditor.DrawingApi.Core/Bridge/Operations/ISurfaceOperations.cs
  14. 21 0
      src/PixiEditor.DrawingApi.Core/Surface/Bitmap.cs
  15. 7 0
      src/PixiEditor.DrawingApi.Core/Surface/Canvas.cs
  16. 11 1
      src/PixiEditor.DrawingApi.Core/Surface/DrawingSurface.cs
  17. 10 1
      src/PixiEditor.DrawingApi.Core/Surface/ImageData/Image.cs
  18. 29 0
      src/PixiEditor.DrawingApi.Core/Surface/ImageData/ImgData.cs
  19. 12 0
      src/PixiEditor.DrawingApi.Core/Surface/Pixmap.cs
  20. 7 9
      src/PixiEditor/Helpers/Converters/BackendColorToMediaColorConverter.cs
  21. 3 5
      src/PixiEditor/Helpers/DocumentViewModelBuilder.cs
  22. 13 0
      src/PixiEditor/Helpers/Extensions/ColorHelpers.cs
  23. 41 32
      src/PixiEditor/Helpers/Extensions/PixelFormatHelper.cs
  24. 0 13
      src/PixiEditor/Helpers/Extensions/SkiaWPFHelpers.cs
  25. 1 1
      src/PixiEditor/Helpers/SurfaceHelpers.cs
  26. 8 8
      src/PixiEditor/Models/Commands/Search/ColorSearchResult.cs
  27. 2 1
      src/PixiEditor/Models/Controllers/ClipboardController.cs
  28. 2 1
      src/PixiEditor/Models/DataProviders/LocalPalettesFetcher.cs
  29. 12 10
      src/PixiEditor/Models/DocumentModels/DocumentUpdater.cs
  30. 2 1
      src/PixiEditor/Models/DocumentModels/Public/DocumentOperationsModule.cs
  31. 4 4
      src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/EraserToolExecutor.cs
  32. 3 3
      src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/FloodFillToolExecutor.cs
  33. 3 2
      src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/LineToolExecutor.cs
  34. 2 1
      src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/PenToolExecutor.cs
  35. 4 3
      src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/ShapeToolExecutor.cs
  36. 7 6
      src/PixiEditor/Models/IO/PaletteFileData.cs
  37. 3 3
      src/PixiEditor/ViewModels/SubViewModels/Document/DocumentViewModel.cs
  38. 3 3
      src/PixiEditor/ViewModels/SubViewModels/Main/ClipboardViewModel.cs
  39. 16 19
      src/PixiEditor/ViewModels/SubViewModels/Main/ColorsViewModel.cs
  40. 2 1
      src/PixiEditor/ViewModels/ViewModelMain.cs
  41. 3 2
      src/PixiEditor/Views/Dialogs/PalettesBrowser.xaml.cs
  42. 7 7
      src/PixiEditor/Views/MainWindow.xaml
  43. 5 4
      src/PixiEditor/Views/UserControls/CommandSearch/CommandSearchControlHelper.cs
  44. 8 7
      src/PixiEditor/Views/UserControls/Palettes/ColorReplacer.xaml.cs
  45. 2 2
      src/PixiEditor/Views/UserControls/Palettes/PaletteColor.xaml
  46. 4 4
      src/PixiEditor/Views/UserControls/Palettes/PaletteColor.xaml.cs
  47. 13 13
      src/PixiEditor/Views/UserControls/Palettes/PaletteColorAdder.xaml.cs
  48. 3 3
      src/PixiEditor/Views/UserControls/PreviewWindow.xaml.cs
  49. 1 1
      src/PixiEditor/Views/UserControls/SwatchesView.xaml
  50. 4 3
      src/PixiEditor/Views/UserControls/SwatchesView.xaml.cs
  51. 1 1
      src/PixiEditor/Views/UserControls/ToolSettingColorPicker.xaml

+ 2 - 2
src/ChunkyImageLib/CommittedChunkStorage.cs

@@ -1,6 +1,6 @@
 using ChunkyImageLib.DataHolders;
 using PixiEditor.DrawingApi.Core.Numerics;
-using SkiaSharp;
+using PixiEditor.DrawingApi.Core.Surface;
 
 namespace ChunkyImageLib;
 
@@ -8,7 +8,7 @@ public class CommittedChunkStorage : IDisposable
 {
     private bool disposed = false;
     private List<(VecI, Chunk?)> savedChunks = new();
-    private static SKPaint ReplacingPaint { get; } = new SKPaint() { BlendMode = SKBlendMode.Src };
+    private static Paint ReplacingPaint { get; } = new Paint() { BlendMode = BlendMode.Src };
 
     public CommittedChunkStorage(ChunkyImage image, HashSet<VecI> committedChunksToSave)
     {

+ 6 - 5
src/ChunkyImageLib/Shaders/ShaderUtils.cs

@@ -1,4 +1,5 @@
 using ComputeSharp;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
 using SkiaSharp;
 
 namespace ChunkyImageLib.Shaders;
@@ -15,12 +16,12 @@ public static class ShaderUtils
         );
     }
 
-    public static uint2 PackPixel(SKColor color)
+    public static uint2 PackPixel(Color color)
     {
-        uint convR = (BitConverter.HalfToUInt16Bits((Half)(color.Red / 255f)));
-        uint convG = (BitConverter.HalfToUInt16Bits((Half)(color.Green / 255f)));
-        uint convB = (BitConverter.HalfToUInt16Bits((Half)(color.Blue / 255f)));
-        uint convA = (BitConverter.HalfToUInt16Bits((Half)(color.Alpha / 255f)));
+        uint convR = (BitConverter.HalfToUInt16Bits((Half)(color.R / 255f)));
+        uint convG = (BitConverter.HalfToUInt16Bits((Half)(color.G / 255f)));
+        uint convB = (BitConverter.HalfToUInt16Bits((Half)(color.B / 255f)));
+        uint convA = (BitConverter.HalfToUInt16Bits((Half)(color.A / 255f)));
 
         return new UInt2(convG << 16 | convR, convB | convA << 16);
     }

+ 3 - 6
src/ChunkyImageLib/Surface.cs

@@ -1,12 +1,9 @@
 using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
-using ChunkyImageLib.DataHolders;
 using PixiEditor.DrawingApi.Core.ColorsImpl;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Surface;
 using PixiEditor.DrawingApi.Core.Surface.ImageData;
-using PixiEditor.PixelE;
-using SkiaSharp;
 
 namespace ChunkyImageLib;
 
@@ -70,7 +67,7 @@ public class Surface : IDisposable
     {
         using Image image = DrawingSurface.Snapshot();
         Surface newSurface = new(newSize);
-        newSurface.DrawingSurface.Canvas.DrawImage(image, new SKRect(0, 0, newSize.X, newSize.Y), nearestNeighborReplacingPaint);
+        newSurface.DrawingSurface.Canvas.DrawImage(image, new RectD(0, 0, newSize.X, newSize.Y), nearestNeighborReplacingPaint);
         return newSurface;
     }
 
@@ -90,7 +87,7 @@ public class Surface : IDisposable
     {
         Half* ptr = (Half*)(PixelBuffer + (pos.X + pos.Y * Size.X) * BytesPerPixel);
         float a = (float)ptr[3];
-        return (SKColor)new SKColorF((float)ptr[0] / a, (float)ptr[1] / a, (float)ptr[2] / a, (float)ptr[3]);
+        return (Color)new ColorF((float)ptr[0] / a, (float)ptr[1] / a, (float)ptr[2] / a, (float)ptr[3]);
     }
 
     public void SetSRGBPixel(VecI pos, Color color)
@@ -114,7 +111,7 @@ public class Surface : IDisposable
 
     public void SaveToDesktop(string filename = "savedSurface.png")
     {
-        using var final = SKSurface.Create(new SKImageInfo(Size.X, Size.Y, SKColorType.Rgba8888, SKAlphaType.Premul, SKColorSpace.CreateSrgb()));
+        using var final = DrawingSurface.Create(new ImageInfo(Size.X, Size.Y, ColorType.Rgba8888, AlphaType.Premul, ColorSpace.CreateSrgb()));
         final.Canvas.DrawSurface(DrawingSurface, 0, 0);
         using (var snapshot = final.Snapshot())
         {

+ 23 - 21
src/ChunkyImageLibTest/ChunkyImageTests.cs

@@ -2,7 +2,9 @@
 using System.IO;
 using ChunkyImageLib;
 using ChunkyImageLib.DataHolders;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
 using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.DrawingApi.Core.Surface;
 using SkiaSharp;
 using Xunit;
 
@@ -25,30 +27,30 @@ public class ChunkyImageTests
     public void LoadDemo()
     {
         var path = @"C:\Users\egor0\Desktop\SpazzS1.png";
-        ImportImage(path, new VecI(5,5));
+        ImportImage(path, new VecI(5, 5));
     }
 
     [Fact]
     public void Dispose_ComplexImage_ReturnsAllChunks()
     {
         ChunkyImage image = new ChunkyImage(new(ChunkyImage.FullChunkSize, ChunkyImage.FullChunkSize));
-        image.EnqueueDrawRectangle(new(new(5, 5), new(80, 80), 0, 2, SKColors.AliceBlue, SKColors.Snow));
+        image.EnqueueDrawRectangle(new(new(5, 5), new(80, 80), 0, 2, Colors.AliceBlue, Colors.Snow));
         using (Chunk target = Chunk.Create())
         {
             image.DrawMostUpToDateChunkOn(new(0, 0), ChunkResolution.Full, target.Surface.DrawingSurface, VecI.Zero);
             image.CancelChanges();
             image.EnqueueResize(new(ChunkyImage.FullChunkSize * 4, ChunkyImage.FullChunkSize * 4));
-            image.EnqueueDrawRectangle(new(VecD.Zero, image.CommittedSize, 0, 2, SKColors.AliceBlue, SKColors.Snow, SKBlendMode.Multiply));
+            image.EnqueueDrawRectangle(new(VecD.Zero, image.CommittedSize, 0, 2, Colors.AliceBlue, Colors.Snow, BlendMode.Multiply));
             image.CommitChanges();
-            image.SetBlendMode(SKBlendMode.Overlay);
-            image.EnqueueDrawRectangle(new(VecD.Zero, image.CommittedSize, 0, 2, SKColors.AliceBlue, SKColors.Snow, SKBlendMode.Multiply));
-            image.EnqueueDrawRectangle(new(VecD.Zero, image.CommittedSize, 0, 2, SKColors.AliceBlue, SKColors.Snow));
+            image.SetBlendMode(BlendMode.Overlay);
+            image.EnqueueDrawRectangle(new(VecD.Zero, image.CommittedSize, 0, 2, Colors.AliceBlue, Colors.Snow, BlendMode.Multiply));
+            image.EnqueueDrawRectangle(new(VecD.Zero, image.CommittedSize, 0, 2, Colors.AliceBlue, Colors.Snow));
             image.CommitChanges();
-            image.SetBlendMode(SKBlendMode.Screen);
-            image.EnqueueDrawRectangle(new(VecD.Zero, image.CommittedSize, 0, 2, SKColors.AliceBlue, SKColors.Snow));
+            image.SetBlendMode(BlendMode.Screen);
+            image.EnqueueDrawRectangle(new(VecD.Zero, image.CommittedSize, 0, 2, Colors.AliceBlue, Colors.Snow));
             image.CancelChanges();
-            image.SetBlendMode(SKBlendMode.SrcOver);
-            image.EnqueueDrawRectangle(new(VecD.Zero, image.CommittedSize, 0, 2, SKColors.AliceBlue, SKColors.Snow));
+            image.SetBlendMode(BlendMode.SrcOver);
+            image.EnqueueDrawRectangle(new(VecD.Zero, image.CommittedSize, 0, 2, Colors.AliceBlue, Colors.Snow));
         }
         image.Dispose();
 
@@ -61,9 +63,9 @@ public class ChunkyImageTests
         const int chunkSize = ChunkyImage.FullChunkSize;
         ChunkyImage image = new ChunkyImage(new VecI(chunkSize * 2));
         image.EnqueueDrawRectangle
-            (new ShapeData(new VecD(chunkSize), new VecD(chunkSize * 2), 0, 0, SKColors.Transparent, SKColors.Red));
+            (new ShapeData(new VecD(chunkSize), new VecD(chunkSize * 2), 0, 0, Colors.Transparent, Colors.Red));
         image.CommitChanges();
-        Assert.Equal(SKColors.Red, image.GetCommittedPixel(new VecI(chunkSize + chunkSize / 2)));
+        Assert.Equal(Colors.Red, image.GetCommittedPixel(new VecI(chunkSize + chunkSize / 2)));
         image.Dispose();
         Assert.Equal(0, Chunk.ChunkCounter);
     }
@@ -74,8 +76,8 @@ public class ChunkyImageTests
         const int chunkSize = ChunkyImage.FullChunkSize;
         ChunkyImage image = new ChunkyImage(new VecI(chunkSize * 2));
         image.EnqueueDrawRectangle
-            (new ShapeData(new VecD(chunkSize), new VecD(chunkSize * 2), 0, 0, SKColors.Transparent, SKColors.Red));
-        Assert.Equal(SKColors.Red, image.GetMostUpToDatePixel(new VecI(chunkSize + chunkSize / 2)));
+            (new ShapeData(new VecD(chunkSize), new VecD(chunkSize * 2), 0, 0, Colors.Transparent, Colors.Red));
+        Assert.Equal(Colors.Red, image.GetMostUpToDatePixel(new VecI(chunkSize + chunkSize / 2)));
         image.Dispose();
         Assert.Equal(0, Chunk.ChunkCounter);
     }
@@ -86,17 +88,17 @@ public class ChunkyImageTests
         const int chunkSize = ChunkyImage.FullChunkSize;
         ChunkyImage image = new ChunkyImage(new VecI(chunkSize * 2));
         image.EnqueueDrawRectangle
-            (new ShapeData(new VecD(chunkSize), new VecD(chunkSize * 2), 0, 0, SKColors.Transparent, SKColors.Red));
+            (new ShapeData(new VecD(chunkSize), new VecD(chunkSize * 2), 0, 0, Colors.Transparent, Colors.Red));
         image.CommitChanges();
-        image.SetBlendMode(SKBlendMode.SrcOver);
+        image.SetBlendMode(BlendMode.SrcOver);
         image.EnqueueDrawRectangle(new ShapeData(
             new VecD(chunkSize),
             new VecD(chunkSize * 2),
             0, 
             0,
-            SKColors.Transparent,
-            new SKColor(0, 255, 0, 128)));
-        Assert.Equal(new SKColor(127, 128, 0), image.GetMostUpToDatePixel(new VecI(chunkSize + chunkSize / 2)));
+            Colors.Transparent,
+            new Color(0, 255, 0, 128)));
+        Assert.Equal(new Color(127, 128, 0), image.GetMostUpToDatePixel(new VecI(chunkSize + chunkSize / 2)));
         image.Dispose();
         Assert.Equal(0, Chunk.ChunkCounter);
     }
@@ -111,8 +113,8 @@ public class ChunkyImageTests
                 new VecD(chunkSize * 10),
                 0,
                 0,
-                SKColors.Transparent,
-                SKColors.Red));
+                Colors.Transparent,
+                Colors.Red));
         image.CommitChanges();
         Assert.Collection(
             image.FindAllChunks(), 

+ 8 - 7
src/ChunkyImageLibTest/RectangleOperationTests.cs

@@ -2,6 +2,7 @@
 using ChunkyImageLib;
 using ChunkyImageLib.DataHolders;
 using ChunkyImageLib.Operations;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
 using PixiEditor.DrawingApi.Core.Numerics;
 using SkiaSharp;
 using Xunit;
@@ -17,7 +18,7 @@ public class RectangleOperationTests
     public void FindAffectedChunks_SmallStrokeOnly_FindsCorrectChunks()
     {
         var (x, y, w, h) = (chunkSize / 2, chunkSize / 2, chunkSize, chunkSize);
-        RectangleOperation operation = new(new(new(x, y), new(w, h), 0, 1, SKColors.Black, SKColors.Transparent));
+        RectangleOperation operation = new(new(new(x, y), new(w, h), 0, 1, Colors.Black, Colors.Transparent));
 
         HashSet<VecI> expected = new() { new(0, 0) };
         var actual = operation.FindAffectedChunks(new(chunkSize));
@@ -29,7 +30,7 @@ public class RectangleOperationTests
     public void FindAffectedChunks_2by2StrokeOnly_FindsCorrectChunks()
     {
         var (x, y, w, h) = (0, 0, chunkSize * 2, chunkSize * 2);
-        RectangleOperation operation = new(new(new(x, y), new(w, h), 0, 1, SKColors.Black, SKColors.Transparent));
+        RectangleOperation operation = new(new(new(x, y), new(w, h), 0, 1, Colors.Black, Colors.Transparent));
 
         HashSet<VecI> expected = new() { new(-1, -1), new(0, -1), new(-1, 0), new(0, 0) };
         var actual = operation.FindAffectedChunks(new(chunkSize));
@@ -41,7 +42,7 @@ public class RectangleOperationTests
     public void FindAffectedChunks_3x3PositiveStrokeOnly_FindsCorrectChunks()
     {
         var (x, y, w, h) = (2 * chunkSize + chunkSize / 2, 2 * chunkSize + chunkSize / 2, chunkSize * 2, chunkSize * 2);
-        RectangleOperation operation = new(new(new(x, y), new(w, h), 0, 1, SKColors.Black, SKColors.Transparent));
+        RectangleOperation operation = new(new(new(x, y), new(w, h), 0, 1, Colors.Black, Colors.Transparent));
 
         HashSet<VecI> expected = new()
         {
@@ -58,7 +59,7 @@ public class RectangleOperationTests
     public void FindAffectedChunks_3x3NegativeStrokeOnly_FindsCorrectChunks()
     {
         var (x, y, w, h) = (-chunkSize * 2 - chunkSize / 2, -chunkSize * 2 - chunkSize / 2, chunkSize * 2, chunkSize * 2);
-        RectangleOperation operation = new(new(new(x, y), new(w, h), 0, 1, SKColors.Black, SKColors.Transparent));
+        RectangleOperation operation = new(new(new(x, y), new(w, h), 0, 1, Colors.Black, Colors.Transparent));
 
         HashSet<VecI> expected = new()
         {
@@ -75,7 +76,7 @@ public class RectangleOperationTests
     public void FindAffectedChunks_3x3PositiveFilled_FindsCorrectChunks()
     {
         var (x, y, w, h) = (2 * chunkSize + chunkSize / 2, 2 * chunkSize + chunkSize / 2, chunkSize * 2, chunkSize * 2);
-        RectangleOperation operation = new(new(new(x, y), new(w, h), 0, 1, SKColors.Black, SKColors.White));
+        RectangleOperation operation = new(new(new(x, y), new(w, h), 0, 1, Colors.Black, Colors.White));
 
         HashSet<VecI> expected = new()
         {
@@ -92,7 +93,7 @@ public class RectangleOperationTests
     public void FindAffectedChunks_ThickPositiveStroke_FindsCorrectChunks()
     {
         var (x, y, w, h) = (2 * chunkSize + chunkSize / 2, 2 * chunkSize + chunkSize / 2, chunkSize * 4, chunkSize * 4);
-        RectangleOperation operation = new(new(new(x, y), new(w, h), 0, chunkSize, SKColors.Black, SKColors.Transparent));
+        RectangleOperation operation = new(new(new(x, y), new(w, h), 0, chunkSize, Colors.Black, Colors.Transparent));
 
         HashSet<VecI> expected = new()
         {
@@ -111,7 +112,7 @@ public class RectangleOperationTests
     public void FindAffectedChunks_SmallButThick_FindsCorrectChunks()
     {
         var (x, y, w, h) = (chunkSize / 2f - 0.5, chunkSize / 2f - 0.5, 1, 1);
-        RectangleOperation operation = new(new(new(x, y), new(w, h), 0, chunkSize, SKColors.Black, SKColors.White));
+        RectangleOperation operation = new(new(new(x, y), new(w, h), 0, chunkSize, Colors.Black, Colors.White));
 
         HashSet<VecI> expected = new() { new(0, 0) };
         var actual = operation.FindAffectedChunks(new(chunkSize));

+ 2 - 0
src/PixiEditor.DrawingApi.Core/Bridge/IDrawingBackend.cs

@@ -15,5 +15,7 @@ namespace PixiEditor.DrawingApi.Core.Bridge
         public IPixmapImplementation PixmapImplementation { get; set; }
         public ISurfaceOperations SurfaceOperations { get; set; }
         public IColorSpaceImplementation ColorSpaceImplementation { get; set; }
+        public IImgDataImplementation ImgDataImplementation { get; set; }
+        public IBitmapImplementation BitmapImplementation { get; set; }
     }
 }

+ 10 - 0
src/PixiEditor.DrawingApi.Core/Bridge/NativeObjectsImpl/IBitmapImplementation.cs

@@ -0,0 +1,10 @@
+using System;
+using PixiEditor.DrawingApi.Core.Surface;
+
+namespace PixiEditor.DrawingApi.Core.Bridge.NativeObjectsImpl;
+
+public interface IBitmapImplementation
+{
+    public void Dispose(IntPtr objectPointer);
+    public Bitmap Decode(ReadOnlySpan<byte> buffer);
+}

+ 1 - 1
src/PixiEditor.DrawingApi.Core/Bridge/Operations/IColorImplementation.cs → src/PixiEditor.DrawingApi.Core/Bridge/NativeObjectsImpl/IColorImplementation.cs

@@ -1,7 +1,7 @@
 using PixiEditor.DrawingApi.Core.ColorsImpl;
 using PixiEditor.DrawingApi.Core.Surface.ImageData;
 
-namespace PixiEditor.DrawingApi.Core.Bridge.Operations
+namespace PixiEditor.DrawingApi.Core.Bridge.NativeObjectsImpl
 {
     public interface IColorImplementation
     {

+ 12 - 0
src/PixiEditor.DrawingApi.Core/Bridge/NativeObjectsImpl/IImgDataImplementation.cs

@@ -0,0 +1,12 @@
+using System;
+using System.IO;
+using PixiEditor.DrawingApi.Core.Surface.ImageData;
+
+namespace PixiEditor.DrawingApi.Core.Bridge.NativeObjectsImpl;
+
+public interface IImgDataImplementation
+{
+    public void Dispose(IntPtr objectPointer);
+    public void SaveTo(ImgData imgData, FileStream stream);
+    public Stream AsStream(ImgData imgData);
+}

+ 4 - 0
src/PixiEditor.DrawingApi.Core/Bridge/NativeObjectsImpl/IPixmapImplementation.cs

@@ -1,4 +1,6 @@
 using System;
+using PixiEditor.DrawingApi.Core.Surface;
+using PixiEditor.DrawingApi.Core.Surface.ImageData;
 
 namespace PixiEditor.DrawingApi.Core.Bridge.NativeObjectsImpl;
 
@@ -6,4 +8,6 @@ public interface IPixmapImplementation
 {
     public void Dispose(IntPtr objectPointer);
     public IntPtr GetPixels(IntPtr objectPointer);
+    public Span<T> GetPixelSpan<T>(Pixmap pixmap);
+    public IntPtr Construct(IntPtr dataPtr, ImageInfo imgInfo);
 }

+ 2 - 0
src/PixiEditor.DrawingApi.Core/Bridge/Operations/ICanvasOperations.cs

@@ -29,5 +29,7 @@ namespace PixiEditor.DrawingApi.Core.Bridge.Operations
         public void RestoreToCount(int count);
         public void DrawColor(Color color, BlendMode paintBlendMode);
         public void RotateRadians(float dataAngle, float centerX, float centerY);
+        public void DrawImage(Image image, RectD rect, Paint paint);
+        public void DrawBitmap(Bitmap bitmap, int x, int y);
     }
 }

+ 1 - 0
src/PixiEditor.DrawingApi.Core/Bridge/Operations/IImageOperations.cs

@@ -9,5 +9,6 @@ namespace PixiEditor.DrawingApi.Core.Bridge.Operations
         public void DisposeImage(Image image);
         public Image FromEncodedData(string path);
         public void GetColorShifts(ref int platformColorAlphaShift, ref int platformColorRedShift, ref int platformColorGreenShift, ref int platformColorBlueShift);
+        public ImgData Encode(Image image);
     }
 }

+ 3 - 0
src/PixiEditor.DrawingApi.Core/Bridge/Operations/ISurfaceOperations.cs

@@ -10,4 +10,7 @@ public interface ISurfaceOperations
     public DrawingSurface Create(ImageInfo imageInfo, IntPtr pixels, int rowBytes);
     public bool ReadPixels(DrawingSurface drawingSurface, ImageInfo dstInfo, IntPtr dstPixels, int dstRowBytes, int srcX, int srcY);
     public void Draw(DrawingSurface drawingSurface, Canvas surfaceToDraw, int x, int y, Paint drawingPaint);
+    public DrawingSurface Create(ImageInfo imageInfo, IntPtr pixelBuffer);
+    public DrawingSurface Create(Pixmap pixmap);
+    public DrawingSurface Create(ImageInfo imageInfo);
 }

+ 21 - 0
src/PixiEditor.DrawingApi.Core/Surface/Bitmap.cs

@@ -0,0 +1,21 @@
+using System;
+using PixiEditor.DrawingApi.Core.Bridge;
+
+namespace PixiEditor.DrawingApi.Core.Surface;
+
+public class Bitmap : NativeObject
+{
+    internal Bitmap(IntPtr objPtr) : base(objPtr)
+    {
+    }
+
+    public override void Dispose()
+    {
+        DrawingBackendApi.Current.BitmapImplementation.Dispose(ObjectPointer);
+    }
+
+    public static Bitmap Decode(ReadOnlySpan<byte> buffer)
+    {
+        return DrawingBackendApi.Current.BitmapImplementation.Decode(buffer);
+    }
+}

+ 7 - 0
src/PixiEditor.DrawingApi.Core/Surface/Canvas.cs

@@ -23,6 +23,8 @@ namespace PixiEditor.DrawingApi.Core.Surface
         }
 
         public void DrawImage(Image image, int x, int y) => DrawingBackendApi.Current.CanvasOperations.DrawImage(image, x, y);
+        
+        public void DrawImage(Image image, RectD rect, Paint paint) => DrawingBackendApi.Current.CanvasOperations.DrawImage(image, rect, paint);
 
         public int Save()
         {
@@ -140,5 +142,10 @@ namespace PixiEditor.DrawingApi.Core.Surface
         {
             DrawingBackendApi.Current.CanvasOperations.RotateRadians(dataAngle, centerX, centerY);
         }
+
+        public void DrawBitmap(Bitmap bitmap, int x, int y)
+        {
+            DrawingBackendApi.Current.CanvasOperations.DrawBitmap(bitmap, x, y);
+        }
     }
 }

+ 11 - 1
src/PixiEditor.DrawingApi.Core/Surface/DrawingSurface.cs

@@ -18,7 +18,7 @@ namespace PixiEditor.DrawingApi.Core.Surface
         
         public DrawingSurface Create(Pixmap imageInfo)
         {
-            return DrawingBackendApi.Current.SurfaceOperations.Create(ObjectPointer, imageInfo);
+            return DrawingBackendApi.Current.SurfaceOperations.Create(imageInfo);
         }
         
         public void Draw(Canvas drawingSurfaceCanvas, int x, int y, Paint drawingPaint)
@@ -40,11 +40,21 @@ namespace PixiEditor.DrawingApi.Core.Surface
         {
             return DrawingBackendApi.Current.SurfaceOperations.ReadPixels(this, dstInfo, dstPixels, dstRowBytes, srcX, srcY);
         }
+        
+        public DrawingSurface Create(ImageInfo imageInfo)
+        {
+            return DrawingBackendApi.Current.SurfaceOperations.Create(imageInfo);
+        }
 
         public static DrawingSurface Create(ImageInfo imageInfo, IntPtr pixels, int rowBytes)
         {
             return DrawingBackendApi.Current.SurfaceOperations.Create(imageInfo, pixels, rowBytes);
         }
+        
+        public DrawingSurface Create(ImageInfo imageInfo, IntPtr pixelBuffer)
+        {
+            return DrawingBackendApi.Current.SurfaceOperations.Create(imageInfo, pixelBuffer);
+        }
 
         public override void Dispose()
         {

+ 10 - 1
src/PixiEditor.DrawingApi.Core/Surface/ImageData/Image.cs

@@ -1,4 +1,5 @@
-using PixiEditor.DrawingApi.Core.Bridge;
+using System;
+using PixiEditor.DrawingApi.Core.Bridge;
 
 namespace PixiEditor.DrawingApi.Core.Surface.ImageData
 {
@@ -12,6 +13,9 @@ namespace PixiEditor.DrawingApi.Core.Surface.ImageData
     /// </remarks>
     public class Image : PixelDataObject
     {
+        public int Width { get; set; }
+        public int Height { get; set; }
+        
         public override void Dispose()
         {
             DrawingBackendApi.Current.ImageOperations.DisposeImage(this);
@@ -21,5 +25,10 @@ namespace PixiEditor.DrawingApi.Core.Surface.ImageData
         {
             return DrawingBackendApi.Current.ImageOperations.FromEncodedData(path);
         }
+
+        public ImgData Encode()
+        {
+            return DrawingBackendApi.Current.ImageOperations.Encode(this);
+        }
     }
 }

+ 29 - 0
src/PixiEditor.DrawingApi.Core/Surface/ImageData/ImgData.cs

@@ -0,0 +1,29 @@
+using System;
+using System.IO;
+using PixiEditor.DrawingApi.Core.Bridge;
+using SkiaSharp;
+
+namespace PixiEditor.DrawingApi.Core.Surface.ImageData;
+
+/// <summary>The <see cref="ImgData" /> holds an immutable data buffer.</summary>
+public class ImgData : NativeObject
+{
+    public ImgData(IntPtr objPtr) : base(objPtr)
+    {
+    }
+
+    public override void Dispose()
+    {
+        DrawingBackendApi.Current.ImgDataImplementation.Dispose(ObjectPointer);
+    }
+
+    public void SaveTo(FileStream stream)
+    {
+        DrawingBackendApi.Current.ImgDataImplementation.SaveTo(this, stream);
+    }
+
+    public Stream AsStream()
+    {
+        return DrawingBackendApi.Current.ImgDataImplementation.AsStream(this);
+    }
+}

+ 12 - 0
src/PixiEditor.DrawingApi.Core/Surface/Pixmap.cs

@@ -1,5 +1,7 @@
 using System;
 using PixiEditor.DrawingApi.Core.Bridge;
+using PixiEditor.DrawingApi.Core.Surface.ImageData;
+using SkiaSharp;
 
 namespace PixiEditor.DrawingApi.Core.Surface;
 
@@ -8,6 +10,11 @@ public class Pixmap : NativeObject
     internal Pixmap(IntPtr objPtr) : base(objPtr)
     {
     }
+    
+    public Pixmap(ImageInfo imgInfo, IntPtr dataPtr) : base(dataPtr)
+    {
+        ObjectPointer = DrawingBackendApi.Current.PixmapImplementation.Construct(dataPtr, imgInfo);
+    }
 
     public int Width { get; set; }
     public int Height { get; set; }
@@ -21,4 +28,9 @@ public class Pixmap : NativeObject
     {
         return DrawingBackendApi.Current.PixmapImplementation.GetPixels(ObjectPointer);
     }
+
+    public Span<T> GetPixelSpan<T>()
+    {
+        return DrawingBackendApi.Current.PixmapImplementation.GetPixelSpan<T>(this);
+    }
 }

+ 7 - 9
src/PixiEditor/Helpers/Converters/SKColorToMediaColorConverter.cs → src/PixiEditor/Helpers/Converters/BackendColorToMediaColorConverter.cs

@@ -1,29 +1,27 @@
 using System.Globalization;
 using System.Windows.Media;
-using SkiaSharp;
+using BackendColor = PixiEditor.DrawingApi.Core.ColorsImpl.Color;
 
 namespace PixiEditor.Helpers.Converters;
 
-internal class SKColorToMediaColorConverter : SingleInstanceConverter<SKColorToMediaColorConverter>
+internal class BackendColorToMediaColorConverter : SingleInstanceConverter<BackendColorToMediaColorConverter>
 {
     public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
     {
-        var skcolor = (SKColor)value;
-        var color = Color.FromArgb(skcolor.Alpha, skcolor.Red, skcolor.Green, skcolor.Blue);
+        var backendColor = (BackendColor)value;
+        var color = Color.FromArgb(backendColor.A, backendColor.R, backendColor.G, backendColor.B);
 
         if (targetType == typeof(Brush))
         {
             return new SolidColorBrush(color);
         }
-        else
-        {
-            return color;
-        }
+
+        return color;
     }
 
     public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
     {
         var color = (Color)value;
-        return new SKColor(color.R, color.G, color.B, color.A);
+        return new BackendColor(color.R, color.G, color.B, color.A);
     }
 }

+ 3 - 5
src/PixiEditor/Helpers/DocumentViewModelBuilder.cs

@@ -1,10 +1,8 @@
 using System.Diagnostics.CodeAnalysis;
-using System.IO;
 using ChunkyImageLib;
-using ChunkyImageLib.DataHolders;
-using PixiEditor.ChangeableDocument.Enums;
 using PixiEditor.DrawingApi.Core.Numerics;
-using PixiEditor.ViewModels.SubViewModels.Document;
+using PixiEditor.DrawingApi.Core.Surface;
+using BlendMode = PixiEditor.ChangeableDocument.Enums.BlendMode;
 
 namespace PixiEditor.Helpers;
 
@@ -190,7 +188,7 @@ internal class DocumentViewModelBuilder : ChildrenBuilder
         
         public SurfaceBuilder WithImage(ReadOnlySpan<byte> buffer, int x, int y)
         {
-            Surface.DrawingSurface.Canvas.DrawBitmap(SKBitmap.Decode(buffer), 0, 0);
+            Surface.DrawingSurface.Canvas.DrawBitmap(Bitmap.Decode(buffer), 0, 0);
             return this;
         }
     }

+ 13 - 0
src/PixiEditor/Helpers/Extensions/ColorHelpers.cs

@@ -0,0 +1,13 @@
+using System.Windows.Media;
+using BackendColor = PixiEditor.DrawingApi.Core.ColorsImpl.Color;
+
+namespace PixiEditor.Helpers.Extensions;
+
+internal static class ColorHelpers
+{
+    public static BackendColor ToOpaqueColor(this Color color) => new(color.R, color.G, color.B);
+    public static BackendColor ToColor(this Color color) => new(color.R, color.G, color.B, color.A);
+
+    public static Color ToOpaqueMediaColor(this BackendColor color) => Color.FromRgb(color.R, color.G, color.B);
+    public static Color ToColor(this BackendColor color) => Color.FromArgb(color.A, color.R, color.G, color.B);
+}

+ 41 - 32
src/PixiEditor/Helpers/Extensions/PixelFormatHelper.cs

@@ -1,71 +1,80 @@
 using System.Windows.Media;
-using SkiaSharp;
+using PixiEditor.DrawingApi.Core.Surface.ImageData;
 
 namespace PixiEditor.Helpers.Extensions;
 
 internal static class PixelFormatHelper
 {
-    public static SKColorType ToSkia(this PixelFormat format, out SKAlphaType alphaType)
+    public static ColorType ToColorType(this PixelFormat format, out AlphaType alphaType)
     {
-        if (TryToSkia(format, out SKColorType color, out alphaType))
+        if (TryConvertToColorType(format, out var color, out alphaType))
         {
             return color;
         }
-        else
-        {
-            throw new NotImplementedException($"Skia does not support the '{format}' format");
-        }
+
+        throw new NotImplementedException($"Skia does not support the '{format}' format");
     }
 
-    public static bool TryToSkia(this PixelFormat format, out SKColorType colorType, out SKAlphaType alphaType)
+    public static bool TryConvertToColorType(this PixelFormat format, out ColorType colorType, out AlphaType alphaType)
     {
         if (format == PixelFormats.Rgba64)
         {
-            alphaType = SKAlphaType.Unpremul;
-            colorType = SKColorType.Rgba16161616;
+            alphaType = AlphaType.Unpremul;
+            colorType = ColorType.Rgba16161616;
             return true;
         }
-        else if (format == PixelFormats.Bgra32)
+
+        if (format == PixelFormats.Bgra32)
         {
-            alphaType = SKAlphaType.Unpremul;
-            colorType = SKColorType.Bgra8888;
+            alphaType = AlphaType.Unpremul;
+            colorType = ColorType.Bgra8888;
             return true;
         }
-        else if (format == PixelFormats.Default)
+
+        if (format == PixelFormats.Default)
         {
-            alphaType = SKAlphaType.Unpremul;
-            colorType = SKColorType.RgbaF16;
+            alphaType = AlphaType.Unpremul;
+            colorType = ColorType.RgbaF16;
             return true;
         }
-        else if (format == PixelFormats.Gray8)
+
+        if (format == PixelFormats.Gray8)
         {
-            alphaType = SKAlphaType.Opaque;
-            colorType = SKColorType.Gray8;
+            alphaType = AlphaType.Opaque;
+            colorType = ColorType.Gray8;
             return true;
         }
-        else if (format == PixelFormats.Pbgra32)
+
+        if (format == PixelFormats.Pbgra32)
         {
-            alphaType = SKAlphaType.Premul;
-            colorType = SKColorType.Bgra8888;
+            alphaType = AlphaType.Premul;
+            colorType = ColorType.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)
+
+        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;
+            alphaType = AlphaType.Unknown;
+            colorType = ColorType.Unknown;
             return false;
         }
 
-        throw new NotImplementedException($"'{format}' has not been implemented by {nameof(PixelFormatHelper)}.{nameof(TryToSkia)}()");
+        throw new NotImplementedException(
+            $"'{format}' has not been implemented by {nameof(PixelFormatHelper)}.{nameof(TryConvertToColorType)}()");
     }
 
     public static bool IsSkiaSupported(this PixelFormat format)
     {
-        return TryToSkia(format, out _, out _);
+        return TryConvertToColorType(format, out _, out _);
     }
 }

+ 0 - 13
src/PixiEditor/Helpers/Extensions/SkiaWPFHelpers.cs

@@ -1,13 +0,0 @@
-using System.Windows.Media;
-using SkiaSharp;
-
-namespace PixiEditor.Helpers.Extensions;
-
-internal static class SkiaWPFHelpers
-{
-    public static SKColor ToOpaqueSKColor(this Color color) => new(color.R, color.G, color.B);
-    public static SKColor ToSKColor(this Color color) => new(color.R, color.G, color.B, color.A);
-
-    public static Color ToOpaqueColor(this SKColor color) => Color.FromRgb(color.Red, color.Green, color.Blue);
-    public static Color ToColor(this SKColor color) => Color.FromArgb(color.Alpha, color.Red, color.Green, color.Blue);
-}

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

@@ -13,7 +13,7 @@ public static class SurfaceHelpers
 {
     public static Surface FromBitmapSource(BitmapSource original)
     {
-        SKColorType color = original.Format.ToSkia(out SKAlphaType alpha);
+        ColorType color = original.Format.ToColorType(out AlphaType alpha);
         if (original.PixelWidth <= 0 || original.PixelHeight <= 0)
             throw new ArgumentException("Surface dimensions must be non-zero");
 

+ 8 - 8
src/PixiEditor/Models/Commands/Search/ColorSearchResult.cs

@@ -8,14 +8,14 @@ namespace PixiEditor.Models.Commands.Search;
 internal class ColorSearchResult : SearchResult
 {
     private readonly DrawingImage icon;
-    private readonly SKColor color;
+    private readonly DrawingApi.Core.ColorsImpl.Color color;
     private string text;
     private bool requiresDocument;
-    private readonly Action<SKColor> target;
+    private readonly Action<DrawingApi.Core.ColorsImpl.Color> target;
 
     public override string Text => text;
 
-    public override string Description => $"{color} rgba({color.Red}, {color.Green}, {color.Blue}, {color.Alpha})";
+    public override string Description => $"{color} rgba({color.R}, {color.G}, {color.B}, {color.A})";
 
     //public override bool CanExecute => !requiresDocument || (requiresDocument && ViewModelMain.Current.BitmapManager.ActiveDocument != null);
     public override bool CanExecute => false;
@@ -24,19 +24,19 @@ internal class ColorSearchResult : SearchResult
 
     public override void Execute() => target(color);
 
-    private ColorSearchResult(SKColor color, Action<SKColor> target)
+    private ColorSearchResult(DrawingApi.Core.ColorsImpl.Color color, Action<DrawingApi.Core.ColorsImpl.Color> target)
     {
         this.color = color;
         icon = GetIcon(color);
         this.target = target;
     }
 
-    public ColorSearchResult(SKColor color) : this(color, x => ViewModelMain.Current.ColorsSubViewModel.PrimaryColor = x)
+    public ColorSearchResult(DrawingApi.Core.ColorsImpl.Color color) : this(color, x => ViewModelMain.Current.ColorsSubViewModel.PrimaryColor = x)
     {
         text = $"Set color to {color}";
     }
 
-    public static ColorSearchResult PastePalette(SKColor color, string searchTerm = null)
+    public static ColorSearchResult PastePalette(DrawingApi.Core.ColorsImpl.Color color, string searchTerm = null)
     {
         //var result = new ColorSearchResult(color, x => ViewModelMain.Current.BitmapManager.ActiveDocument.Palette.Add(x))
         var result = new ColorSearchResult(color, x => { })
@@ -49,9 +49,9 @@ internal class ColorSearchResult : SearchResult
         return result;
     }
 
-    public static DrawingImage GetIcon(SKColor color)
+    public static DrawingImage GetIcon(DrawingApi.Core.ColorsImpl.Color color)
     {
-        var drawing = new GeometryDrawing() { Brush = new SolidColorBrush(color.ToOpaqueColor()), Pen = new(Brushes.White, 1) };
+        var drawing = new GeometryDrawing() { Brush = new SolidColorBrush(color.ToOpaqueMediaColor()), Pen = new(Brushes.White, 1) };
         var geometry = new EllipseGeometry(new(5, 5), 5, 5) { };
         drawing.Geometry = geometry;
         return new DrawingImage(drawing);

+ 2 - 1
src/PixiEditor/Models/Controllers/ClipboardController.cs

@@ -8,6 +8,7 @@ using System.Windows.Media.Imaging;
 using ChunkyImageLib;
 using ChunkyImageLib.DataHolders;
 using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.DrawingApi.Core.Surface.ImageData;
 using PixiEditor.Helpers;
 using PixiEditor.Models.Dialogs;
 using PixiEditor.Models.IO;
@@ -42,7 +43,7 @@ internal static class ClipboardController
         var (actuallySurface, _) = surface.AsT2;
         DataObject data = new DataObject();
 
-        using (SKData pngData = actuallySurface.DrawingSurface.Snapshot().Encode())
+        using (ImgData pngData = actuallySurface.DrawingSurface.Snapshot().Encode())
         {
             // Stream should not be disposed
             MemoryStream pngStream = new MemoryStream();

+ 2 - 1
src/PixiEditor/Models/DataProviders/LocalPalettesFetcher.cs

@@ -1,4 +1,5 @@
 using System.IO;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
 using PixiEditor.Helpers.Extensions;
 using PixiEditor.Models.DataHolders;
 using PixiEditor.Models.DataHolders.Palettes;
@@ -106,7 +107,7 @@ internal class LocalPalettesFetcher : PaletteListDataSource
         return newName;
     }
 
-    public async Task SavePalette(string fileName, SKColor[] colors)
+    public async Task SavePalette(string fileName, Color[] colors)
     {
         watcher.EnableRaisingEvents = false;
         string path = Path.Join(PathToPalettesFolder, fileName);

+ 12 - 10
src/PixiEditor/Models/DocumentModels/DocumentUpdater.cs

@@ -8,6 +8,8 @@ using PixiEditor.ChangeableDocument.ChangeInfos.Root;
 using PixiEditor.ChangeableDocument.ChangeInfos.Structure;
 using PixiEditor.ChangeableDocument.Enums;
 using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.DrawingApi.Core.Surface;
+using PixiEditor.DrawingApi.Core.Surface.ImageData;
 using PixiEditor.Models.Controllers;
 using PixiEditor.Models.DocumentPassthroughActions;
 using PixiEditor.Models.Enums;
@@ -225,7 +227,7 @@ internal class DocumentUpdater
         {
             VecI size = StructureMemberViewModel.CalculatePreviewSize(doc.SizeBindable);
             memberVm.MaskPreviewBitmap = CreateBitmap(size);
-            memberVm.MaskPreviewSurface = CreateSKSurface(memberVm.MaskPreviewBitmap);
+            memberVm.MaskPreviewSurface = CreateDrawingSurface(memberVm.MaskPreviewBitmap);
         }
         memberVm.InternalSetHasMask(info.HasMask);
         memberVm.RaisePropertyChanged(nameof(memberVm.MaskPreviewBitmap));
@@ -249,7 +251,7 @@ internal class DocumentUpdater
         {
             member.PreviewSurface.Dispose();
             member.PreviewBitmap = CreateBitmap(newSize);
-            member.PreviewSurface = CreateSKSurface(member.PreviewBitmap);
+            member.PreviewSurface = CreateDrawingSurface(member.PreviewBitmap);
             member.RaisePropertyChanged(nameof(member.PreviewBitmap));
 
             member.MaskPreviewSurface?.Dispose();
@@ -258,7 +260,7 @@ internal class DocumentUpdater
             if (member.HasMaskBindable)
             {
                 member.MaskPreviewBitmap = CreateBitmap(newSize);
-                member.MaskPreviewSurface = CreateSKSurface(member.MaskPreviewBitmap);
+                member.MaskPreviewSurface = CreateDrawingSurface(member.MaskPreviewBitmap);
             }
             member.RaisePropertyChanged(nameof(member.MaskPreviewBitmap));
 
@@ -274,11 +276,11 @@ internal class DocumentUpdater
         VecI oldSize = doc.SizeBindable;
 
         Dictionary<ChunkResolution, WriteableBitmap> newBitmaps = new();
-        foreach ((ChunkResolution res, SKSurface surf) in doc.Surfaces)
+        foreach ((ChunkResolution res, DrawingSurface surf) in doc.Surfaces)
         {
             surf.Dispose();
             newBitmaps[res] = CreateBitmap((VecI)(info.Size * res.Multiplier()));
-            doc.Surfaces[res] = CreateSKSurface(newBitmaps[res]);
+            doc.Surfaces[res] = CreateDrawingSurface(newBitmaps[res]);
         }
 
         doc.Bitmaps = newBitmaps;
@@ -290,7 +292,7 @@ internal class DocumentUpdater
         VecI previewSize = StructureMemberViewModel.CalculatePreviewSize(info.Size);
         doc.PreviewSurface.Dispose();
         doc.PreviewBitmap = CreateBitmap(previewSize);
-        doc.PreviewSurface = CreateSKSurface(doc.PreviewBitmap);
+        doc.PreviewSurface = CreateDrawingSurface(doc.PreviewBitmap);
 
         doc.RaisePropertyChanged(nameof(doc.Bitmaps));
         doc.RaisePropertyChanged(nameof(doc.PreviewBitmap));
@@ -305,10 +307,10 @@ internal class DocumentUpdater
         return new WriteableBitmap(Math.Max(size.X, 1), Math.Max(size.Y, 1), 96, 96, PixelFormats.Pbgra32, null);
     }
 
-    private SKSurface CreateSKSurface(WriteableBitmap bitmap)
+    private DrawingSurface CreateDrawingSurface(WriteableBitmap bitmap)
     {
-        return SKSurface.Create(
-            new SKImageInfo(bitmap.PixelWidth, bitmap.PixelHeight, SKColorType.Bgra8888, SKAlphaType.Premul, SKColorSpace.CreateSrgb()),
+        return DrawingSurface.Create(
+            new ImageInfo(bitmap.PixelWidth, bitmap.PixelHeight, ColorType.Bgra8888, AlphaType.Premul, ColorSpace.CreateSrgb()),
             bitmap.BackBuffer,
             bitmap.BackBufferStride);
     }
@@ -343,7 +345,7 @@ internal class DocumentUpdater
         {
             VecI size = StructureMemberViewModel.CalculatePreviewSize(doc.SizeBindable);
             memberVM.MaskPreviewBitmap = CreateBitmap(size);
-            memberVM.MaskPreviewSurface = CreateSKSurface(memberVM.MaskPreviewBitmap);
+            memberVM.MaskPreviewSurface = CreateDrawingSurface(memberVM.MaskPreviewBitmap);
         }
 
         parentFolderVM.Children.Insert(info.Index, memberVM);

+ 2 - 1
src/PixiEditor/Models/DocumentModels/Public/DocumentOperationsModule.cs

@@ -2,6 +2,7 @@
 using ChunkyImageLib.DataHolders;
 using PixiEditor.ChangeableDocument.Actions.Undo;
 using PixiEditor.ChangeableDocument.Enums;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.Models.DocumentModels.UpdateableChangeExecutors;
 using PixiEditor.Models.DocumentPassthroughActions;
@@ -136,7 +137,7 @@ internal class DocumentOperationsModule
         Internals.ActionAccumulator.AddFinishedActions(new ResizeImage_Action(newSize, resampling));
     }
 
-    public void ReplaceColor(SKColor oldColor, SKColor newColor)
+    public void ReplaceColor(Color oldColor, Color newColor)
     {
         if (Internals.ChangeController.IsChangeActive || oldColor == newColor)
             return;

+ 4 - 4
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/EraserToolExecutor.cs

@@ -1,6 +1,6 @@
 #nullable enable
-using ChunkyImageLib.DataHolders;
 using PixiEditor.ChangeableDocument.Actions;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.Models.Enums;
 using PixiEditor.ViewModels.SubViewModels.Document;
@@ -12,7 +12,7 @@ namespace PixiEditor.Models.DocumentModels.UpdateableChangeExecutors;
 internal class EraserToolExecutor : UpdateableChangeExecutor
 {
     private Guid guidValue;
-    private SKColor color;
+    private Color color;
     private int toolSize;
     private bool drawOnMask;
 
@@ -35,7 +35,7 @@ internal class EraserToolExecutor : UpdateableChangeExecutor
         toolSize = toolbar.ToolSize;
 
         vm.ColorsSubViewModel.AddSwatch(color);
-        IAction? action = new LineBasedPen_Action(guidValue, SKColors.Transparent, controller!.LastPixelPosition, toolSize, true,
+        IAction? action = new LineBasedPen_Action(guidValue, DrawingApi.Core.ColorsImpl.Colors.Transparent, controller!.LastPixelPosition, toolSize, true,
             drawOnMask);
         internals!.ActionAccumulator.AddActions(action);
 
@@ -44,7 +44,7 @@ internal class EraserToolExecutor : UpdateableChangeExecutor
 
     public override void OnPixelPositionChange(VecI pos)
     {
-        IAction? action = new LineBasedPen_Action(guidValue, SKColors.Transparent, pos, toolSize, true, drawOnMask);
+        IAction? action = new LineBasedPen_Action(guidValue, DrawingApi.Core.ColorsImpl.Colors.Transparent, pos, toolSize, true, drawOnMask);
         internals!.ActionAccumulator.AddActions(action);
     }
 

+ 3 - 3
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/FloodFillToolExecutor.cs

@@ -1,5 +1,5 @@
-using ChunkyImageLib.DataHolders;
-using PixiEditor.ChangeableDocument.Actions.Undo;
+using PixiEditor.ChangeableDocument.Actions.Undo;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.Models.Enums;
 using PixiEditor.ViewModels.SubViewModels.Document;
@@ -12,7 +12,7 @@ internal class FloodFillToolExecutor : UpdateableChangeExecutor
     private bool considerAllLayers;
     private bool drawOnMask;
     private Guid memberGuid;
-    private SKColor color;
+    private Color color;
 
     public override ExecutionState Start()
     {

+ 3 - 2
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/LineToolExecutor.cs

@@ -1,6 +1,7 @@
 using ChunkyImageLib.DataHolders;
 using PixiEditor.ChangeableDocument.Actions;
 using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.DrawingApi.Core.Surface;
 using PixiEditor.Models.Enums;
 using PixiEditor.ViewModels.SubViewModels.Document;
 using PixiEditor.ViewModels.SubViewModels.Tools.Tools;
@@ -45,14 +46,14 @@ internal class LineToolExecutor : ShapeToolExecutor<LineToolViewModel>
 
         lastRect = rect;
 
-        internals!.ActionAccumulator.AddActions(new DrawLine_Action(memberGuid, startPos, curPos, strokeWidth, strokeColor, SKStrokeCap.Butt, drawOnMask));
+        internals!.ActionAccumulator.AddActions(new DrawLine_Action(memberGuid, startPos, curPos, strokeWidth, strokeColor, StrokeCap.Butt, drawOnMask));
     }
 
     protected override void DrawShape(VecI currentPos, bool firstDraw) => DrawLine(currentPos, firstDraw);
 
     protected override IAction TransformMovedAction(ShapeData data, ShapeCorners corners)
     {
-        return new DrawLine_Action(memberGuid, (VecI)corners.TopLeft, (VecI)corners.BottomRight.Ceiling(), strokeWidth, strokeColor, SKStrokeCap.Butt,
+        return new DrawLine_Action(memberGuid, (VecI)corners.TopLeft, (VecI)corners.BottomRight.Ceiling(), strokeWidth, strokeColor, StrokeCap.Butt,
             drawOnMask);
     }
 

+ 2 - 1
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/PenToolExecutor.cs

@@ -1,5 +1,6 @@
 using ChunkyImageLib.DataHolders;
 using PixiEditor.ChangeableDocument.Actions;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.Models.Enums;
 using PixiEditor.ViewModels.SubViewModels.Document;
@@ -11,7 +12,7 @@ namespace PixiEditor.Models.DocumentModels.UpdateableChangeExecutors;
 internal class PenToolExecutor : UpdateableChangeExecutor
 {
     private Guid guidValue;
-    private SKColor color;
+    private Color color;
     private int toolSize;
     private bool drawOnMask;
     private bool pixelPerfect;

+ 4 - 3
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/ShapeToolExecutor.cs

@@ -1,5 +1,6 @@
 using ChunkyImageLib.DataHolders;
 using PixiEditor.ChangeableDocument.Actions;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.Models.Enums;
 using PixiEditor.ViewModels.SubViewModels.Document;
@@ -13,8 +14,8 @@ namespace PixiEditor.Models.DocumentModels.UpdateableChangeExecutors;
 internal abstract class ShapeToolExecutor<T> : UpdateableChangeExecutor where T : ShapeTool
 {
     protected int strokeWidth;
-    protected SKColor fillColor;
-    protected SKColor strokeColor;
+    protected Color fillColor;
+    protected Color strokeColor;
     protected Guid memberGuid;
     protected bool drawOnMask;
 
@@ -39,7 +40,7 @@ internal abstract class ShapeToolExecutor<T> : UpdateableChangeExecutor where T
         if (!drawOnMask && member is not LayerViewModel)
             return ExecutionState.Error;
 
-        fillColor = toolbar.Fill ? toolbar.FillColor.ToSKColor() : SKColors.Transparent;
+        fillColor = toolbar.Fill ? toolbar.FillColor.ToColor() : DrawingApi.Core.ColorsImpl.Colors.Transparent;
         startPos = controller!.LastPixelPosition;
         strokeColor = colorsVM.PrimaryColor;
         strokeWidth = toolbar.ToolSize;

+ 7 - 6
src/PixiEditor/Models/IO/PaletteFileData.cs

@@ -1,14 +1,15 @@
-using SkiaSharp;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
+using SkiaSharp;
 
 namespace PixiEditor.Models.IO;
 
 internal class PaletteFileData
 {
     public string Title { get; set; }
-    public SKColor[] Colors { get; set; }
+    public Color[] Colors { get; set; }
     public bool IsCorrupted { get; set; } = false;
 
-    public PaletteFileData(SKColor[] colors)
+    public PaletteFileData(Color[] colors)
     {
         Colors = colors;
         Title = "";
@@ -16,16 +17,16 @@ internal class PaletteFileData
 
     public PaletteFileData(List<string> colors)
     {
-        Colors = new SKColor[colors.Count];
+        Colors = new Color[colors.Count];
         for (int i = 0; i < colors.Count; i++)
         {
-            Colors[i] = SKColor.Parse(colors[i]);
+            Colors[i] = Color.Parse(colors[i]);
         }
 
         Title = "";
     }
 
-    public PaletteFileData(string title, SKColor[] colors)
+    public PaletteFileData(string title, Color[] colors)
     {
         Title = title;
         Colors = colors;

+ 3 - 3
src/PixiEditor/ViewModels/SubViewModels/Document/DocumentViewModel.cs

@@ -147,8 +147,8 @@ internal class DocumentViewModel : NotifyableObject
     private VectorPath selectionPath = new VectorPath();
     public VectorPath SelectionPathBindable => selectionPath;
 
-    public WpfObservableRangeCollection<SKColor> Swatches { get; set; } = new WpfObservableRangeCollection<SKColor>();
-    public WpfObservableRangeCollection<SKColor> Palette { get; set; } = new WpfObservableRangeCollection<SKColor>();
+    public WpfObservableRangeCollection<Color> Swatches { get; set; } = new WpfObservableRangeCollection<Color>();
+    public WpfObservableRangeCollection<Color> Palette { get; set; } = new WpfObservableRangeCollection<Color>();
 
     public DocumentTransformViewModel TransformViewModel { get; }
 
@@ -387,7 +387,7 @@ internal class DocumentViewModel : NotifyableObject
         RaisePropertyChanged(nameof(Height));
     }
 
-    public void InternalUpdateSelectionPath(SKPath VectorPath)
+    public void InternalUpdateSelectionPath(VectorPath vectorPath)
     {
         (VectorPath? toDispose, this.selectionPath) = (this.selectionPath, selectionPath);
         toDispose.Dispose();

+ 3 - 3
src/PixiEditor/ViewModels/SubViewModels/Main/ClipboardViewModel.cs

@@ -36,7 +36,7 @@ internal class ClipboardViewModel : SubViewModel<ViewModelMain>
     [Command.Basic("PixiEditor.Clipboard.PasteColor", "Paste color", "Paste color from clipboard", CanExecute = "PixiEditor.Clipboard.CanPasteColor", IconEvaluator = "PixiEditor.Clipboard.PasteColorIcon")]
     public void PasteColor()
     {
-        Owner.ColorsSubViewModel.PrimaryColor = SKColor.Parse(Clipboard.GetText().Trim());
+        Owner.ColorsSubViewModel.PrimaryColor = DrawingApi.Core.ColorsImpl.Color.Parse(Clipboard.GetText().Trim());
     }
 
     [Command.Basic("PixiEditor.Clipboard.Copy", "Copy", "Copy to clipboard", CanExecute = "PixiEditor.Selection.IsNotEmpty", Key = Key.C, Modifiers = ModifierKeys.Control)]
@@ -64,13 +64,13 @@ internal class ClipboardViewModel : SubViewModel<ViewModelMain>
 
         if (CanPasteColor())
         {
-            color = SKColor.Parse(Clipboard.GetText().Trim()).ToOpaqueColor();
+            color = DrawingApi.Core.ColorsImpl.Color.Parse(Clipboard.GetText().Trim()).ToOpaqueMediaColor();
         }
         else
         {
             color = Colors.Transparent;
         }
 
-        return ColorSearchResult.GetIcon(color.ToOpaqueSKColor());
+        return ColorSearchResult.GetIcon(color.ToOpaqueColor());
     }
 }

+ 16 - 19
src/PixiEditor/ViewModels/SubViewModels/Main/ColorsViewModel.cs

@@ -2,10 +2,7 @@
 using System.Windows.Media;
 using Microsoft.Extensions.DependencyInjection;
 using PixiEditor.Helpers;
-using PixiEditor.Models.Commands.Attributes;
 using PixiEditor.Models.Commands.Attributes.Commands;
-using PixiEditor.Models.Commands.Attributes.Evaluators;
-using PixiEditor.Models.Commands.Search;
 using PixiEditor.Models.Controllers;
 using PixiEditor.Models.DataHolders;
 using PixiEditor.Models.DataHolders.Palettes;
@@ -14,9 +11,9 @@ using PixiEditor.Models.Dialogs;
 using PixiEditor.Models.Enums;
 using PixiEditor.Models.ExternalServices;
 using PixiEditor.Models.IO;
-using PixiEditor.ViewModels.SubViewModels.Document;
 using PixiEditor.Views.Dialogs;
-using SkiaSharp;
+using Color = PixiEditor.DrawingApi.Core.ColorsImpl.Color;
+using Colors = PixiEditor.DrawingApi.Core.ColorsImpl.Colors;
 
 namespace PixiEditor.ViewModels.SubViewModels.Main;
 
@@ -31,10 +28,10 @@ internal class ColorsViewModel : SubViewModel<ViewModelMain>
     public LocalPalettesFetcher LocalPaletteFetcher => _localPaletteFetcher ??=
         (LocalPalettesFetcher)PaletteDataSources.FirstOrDefault(x => x is LocalPalettesFetcher)!;
 
-    private SKColor primaryColor = SKColors.Black;
+    private Color primaryColor = Colors.Black;
     private LocalPalettesFetcher _localPaletteFetcher;
 
-    public SKColor PrimaryColor // Primary color, hooked with left mouse button
+    public Color PrimaryColor // Primary color, hooked with left mouse button
     {
         get => primaryColor;
         set
@@ -47,9 +44,9 @@ internal class ColorsViewModel : SubViewModel<ViewModelMain>
         }
     }
 
-    private SKColor secondaryColor = SKColors.White;
+    private Color secondaryColor = Colors.White;
 
-    public SKColor SecondaryColor
+    public Color SecondaryColor
     {
         get => secondaryColor;
         set
@@ -76,7 +73,7 @@ internal class ColorsViewModel : SubViewModel<ViewModelMain>
     }
 
     [Command.Internal("PixiEditor.Colors.ReplaceColors")]
-    public void ReplaceColors((SKColor oldColor, SKColor newColor) colors)
+    public void ReplaceColors((Color oldColor, Color newColor) colors)
     {
         var doc = Owner.DocumentManagerSubViewModel.ActiveDocument;
         if (doc is null || colors.oldColor == colors.newColor)
@@ -105,7 +102,7 @@ internal class ColorsViewModel : SubViewModel<ViewModelMain>
         if (lospecPaletteArg != null)
         {
             var browser = PalettesBrowser.Open(PaletteDataSources, ImportPaletteCommand,
-                new WpfObservableRangeCollection<SKColor>());
+                new WpfObservableRangeCollection<Color>());
 
             browser.IsFetching = true;
             var palette = await LospecPaletteFetcher.FetchPalette(lospecPaletteArg.Split(@"://")[1].Replace("/", ""));
@@ -141,7 +138,7 @@ internal class ColorsViewModel : SubViewModel<ViewModelMain>
 
         await LocalPaletteFetcher.SavePalette(
             palette.FileName,
-            palette.Colors.Select(SKColor.Parse).ToArray());
+            palette.Colors.Select(Color.Parse).ToArray());
 
         await browser.UpdatePaletteList();
         if (browser.SortedResults.Any(x => x.FileName == palette.FileName))
@@ -173,10 +170,10 @@ internal class ColorsViewModel : SubViewModel<ViewModelMain>
         {
             if (doc.Palette is null)
             {
-                doc.Palette = new WpfObservableRangeCollection<SKColor>();
+                doc.Palette = new WpfObservableRangeCollection<DrawingApi.Core.ColorsImpl.Color>();
             }
 
-            doc.Palette.ReplaceRange(palette.Select(x => SKColor.Parse(x)));
+            doc.Palette.ReplaceRange(palette.Select(x => Color.Parse(x)));
         }
     }
 
@@ -213,9 +210,9 @@ internal class ColorsViewModel : SubViewModel<ViewModelMain>
     {
         var document = Owner.DocumentManagerSubViewModel.ActiveDocument;
 
-        SKColor color;
+        Color color;
         if (document?.Palette is null || document.Palette.Count <= index)
-            color = SKColors.Gray;
+            color = Colors.Gray;
         else
             color = document.Palette[index];
 
@@ -247,7 +244,7 @@ internal class ColorsViewModel : SubViewModel<ViewModelMain>
         (PrimaryColor, SecondaryColor) = (SecondaryColor, PrimaryColor);
     }
 
-    public void AddSwatch(SKColor color)
+    public void AddSwatch(Color color)
     {
         var doc = Owner.DocumentManagerSubViewModel.ActiveDocument;
         if (doc is null)
@@ -259,7 +256,7 @@ internal class ColorsViewModel : SubViewModel<ViewModelMain>
     }
 
     [Command.Internal("PixiEditor.Colors.RemoveSwatch")]
-    public void RemoveSwatch(SKColor color)
+    public void RemoveSwatch(Color color)
     {
         var doc = Owner.DocumentManagerSubViewModel.ActiveDocument;
         if (doc is null)
@@ -271,7 +268,7 @@ internal class ColorsViewModel : SubViewModel<ViewModelMain>
     }
 
     [Command.Internal("PixiEditor.Colors.SelectColor")]
-    public void SelectColor(SKColor color)
+    public void SelectColor(Color color)
     {
         PrimaryColor = color;
     }

+ 2 - 1
src/PixiEditor/ViewModels/ViewModelMain.cs

@@ -1,5 +1,6 @@
 using System.ComponentModel;
 using Microsoft.Extensions.DependencyInjection;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
 using PixiEditor.Helpers;
 using PixiEditor.Models.Commands;
 using PixiEditor.Models.Controllers;
@@ -160,7 +161,7 @@ internal class ViewModelMain : ViewModelBase
         return DocumentManagerSubViewModel.ActiveDocument is not null;
     }
 
-    public bool DocumentIsNotNull((SKColor oldColor, SKColor newColor) obj)
+    public bool DocumentIsNotNull((Color oldColor, Color newColor) obj)
     {
         return DocumentIsNotNull(null);
     }

+ 3 - 2
src/PixiEditor/Views/Dialogs/PalettesBrowser.xaml.cs

@@ -5,6 +5,7 @@ using System.Windows.Controls;
 using System.Windows.Input;
 using System.Windows.Navigation;
 using Microsoft.Win32;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
 using PixiEditor.Helpers;
 using PixiEditor.Models.DataHolders;
 using PixiEditor.Models.DataHolders.Palettes;
@@ -136,7 +137,7 @@ internal partial class PalettesBrowser : Window
     private char[] separators = new char[] { ' ', ',' };
 
     private SortingType InternalSortingType => (SortingType)Enum.Parse(typeof(SortingType), SortingType.Replace(" ", ""));
-    public WpfObservableRangeCollection<SKColor> CurrentEditingPalette { get; set; }
+    public WpfObservableRangeCollection<Color> CurrentEditingPalette { get; set; }
     public static PalettesBrowser Instance { get; internal set; }
 
     private LocalPalettesFetcher LocalPalettesFetcher
@@ -167,7 +168,7 @@ internal partial class PalettesBrowser : Window
         };
     }
 
-    public static PalettesBrowser Open(WpfObservableRangeCollection<PaletteListDataSource> dataSources, ICommand importPaletteCommand, WpfObservableRangeCollection<SKColor> currentEditingPalette)
+    public static PalettesBrowser Open(WpfObservableRangeCollection<PaletteListDataSource> dataSources, ICommand importPaletteCommand, WpfObservableRangeCollection<Color> currentEditingPalette)
     {
         if (Instance != null) return Instance;
         PalettesBrowser browser = new PalettesBrowser

+ 7 - 7
src/PixiEditor/Views/MainWindow.xaml

@@ -53,8 +53,8 @@
                 x:Key="NotNullToBoolConverter" />
             <converters:DoubleToIntConverter
                 x:Key="DoubleToIntConverter" />
-            <converters:SKColorToMediaColorConverter
-                x:Key="SKColorToMediaColorConverter" />
+            <converters:BackendColorToMediaColorConverter
+                x:Key="BackendColorToMediaColorConverter" />
             <ResourceDictionary.MergedDictionaries>
                 <ResourceDictionary
                     Source="pack://application:,,,/ColorPicker;component/Styles/DefaultColorPickerStyle.xaml" />
@@ -614,8 +614,8 @@
                                         <LayoutAnchorable ContentId="colorPicker" Title="Color Picker" CanHide="False"
                                                       CanClose="False" CanAutoHide="False" x:Name="colorPickerPanel"
                                                       CanDockAsTabbedDocument="False" CanFloat="True">
-                                            <usercontrols:SmallColorPicker SelectedColor="{Binding ColorsSubViewModel.PrimaryColor, Mode=TwoWay, Converter={StaticResource SKColorToMediaColorConverter}}"
-                                                                         SecondaryColor="{Binding ColorsSubViewModel.SecondaryColor, Mode=TwoWay, Converter={StaticResource SKColorToMediaColorConverter}}" 
+                                            <usercontrols:SmallColorPicker SelectedColor="{Binding ColorsSubViewModel.PrimaryColor, Mode=TwoWay, Converter={StaticResource BackendColorToMediaColorConverter}}"
+                                                                         SecondaryColor="{Binding ColorsSubViewModel.SecondaryColor, Mode=TwoWay, Converter={StaticResource BackendColorToMediaColorConverter}}" 
                                                                          Style="{StaticResource DefaultColorPickerStyle}" x:Name="mainColorPicker">
                                                 <b:Interaction.Behaviors>
                                                     <behaviours:GlobalShortcutFocusBehavior/>
@@ -646,7 +646,7 @@
                                                     Colors="{Binding DocumentManagerSubViewModel.ActiveDocument.Palette}"
                                                     Swatches="{Binding DocumentManagerSubViewModel.ActiveDocument.Swatches}"
                                                     SelectColorCommand="{cmds:Command PixiEditor.Colors.SelectColor, UseProvided=True}"
-                                                    HintColor="{Binding Path=ColorsSubViewModel.PrimaryColor,Converter={converters:SKColorToMediaColorConverter}}"
+                                                    HintColor="{Binding Path=ColorsSubViewModel.PrimaryColor,Converter={converters:BackendColorToMediaColorConverter}}"
                                                     DataSources="{Binding ColorsSubViewModel.PaletteDataSources}"
                                                     FileParsers="{Binding ColorsSubViewModel.PaletteParsers}"
                                                     Visibility="{Binding RelativeSource={RelativeSource Mode=Self}, Path=ActualWidth, Converter={converters:PaletteViewerWidthToVisibilityConverter}, ConverterParameter=Hidden}"
@@ -690,7 +690,7 @@
                                             CanFloat="True">
                                             <usercontrols:PreviewWindow
                                                 Document="{Binding DataContext.DocumentManagerSubViewModel.ActiveDocument, ElementName=mainWindow}"
-                                                PrimaryColor="{Binding ColorsSubViewModel.PrimaryColor, Mode=TwoWay, Converter={StaticResource SKColorToMediaColorConverter}}" />
+                                                PrimaryColor="{Binding ColorsSubViewModel.PrimaryColor, Mode=TwoWay, Converter={StaticResource BackendColorToMediaColorConverter}}" />
                                         </LayoutAnchorable>
                                     </LayoutAnchorablePane>
                                 </LayoutAnchorablePaneGroup>
@@ -741,7 +741,7 @@
                             </DataTemplate>
                         </ItemsControl.ItemTemplate>
                     </ItemsControl>
-                    <Border Background="{Binding ColorsSubViewModel.PrimaryColor, Mode=TwoWay, Converter={converters:SKColorToMediaColorConverter}}"
+                    <Border Background="{Binding ColorsSubViewModel.PrimaryColor, Mode=TwoWay, Converter={converters:BackendColorToMediaColorConverter}}"
                             BorderBrush="Gray" BorderThickness="1" CornerRadius="0,0,5,5"
                             Grid.Row="1" Height="30"/>
                 </Grid>

+ 5 - 4
src/PixiEditor/Views/UserControls/CommandSearch/CommandSearchControlHelper.cs

@@ -7,6 +7,7 @@ using PixiEditor.ViewModels;
 using SkiaSharp;
 using System.IO;
 using System.Text.RegularExpressions;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
 
 namespace PixiEditor.Views.UserControls.CommandSearch;
 
@@ -131,11 +132,11 @@ internal static class CommandSearchControlHelper
         return Directory.Exists(directory);
     }
 
-    public static OneOf<SKColor, Error, None> MaybeParseColor(string query)
+    public static OneOf<Color, Error, None> MaybeParseColor(string query)
     {
         if (query.StartsWith('#'))
         {
-            if (!SKColor.TryParse(query, out var color))
+            if (!Color.TryParse(query, out var color))
                 return new Error();
             return color;
         }
@@ -161,7 +162,7 @@ internal static class CommandSearchControlHelper
         return new None();
     }
 
-    private static SKColor? ParseRGB(Match match)
+    private static Color? ParseRGB(Match match)
     {
         bool invalid = !(
             byte.TryParse(match.Groups["r"].ValueSpan, out var r) &
@@ -177,6 +178,6 @@ internal static class CommandSearchControlHelper
         if (!string.IsNullOrEmpty(aText) && !byte.TryParse(aText, out a))
             return null;
 
-        return new SKColor(r, g, b, a);
+        return new Color(r, g, b, a);
     }
 }

+ 8 - 7
src/PixiEditor/Views/UserControls/Palettes/ColorReplacer.xaml.cs

@@ -2,21 +2,22 @@
 using System.Windows.Controls;
 using System.Windows.Input;
 using System.Windows.Media;
-using SkiaSharp;
+using BackendColor = PixiEditor.DrawingApi.Core.ColorsImpl.Color;
+using BackendColors = PixiEditor.DrawingApi.Core.ColorsImpl.Colors;
 
 namespace PixiEditor.Views.UserControls.Palettes;
 
 internal partial class ColorReplacer : UserControl
 {
-    public SKColor ColorToReplace
+    public BackendColor ColorToReplace
     {
-        get { return (SKColor)GetValue(ColorToReplaceProperty); }
+        get { return (BackendColor)GetValue(ColorToReplaceProperty); }
         set { SetValue(ColorToReplaceProperty, value); }
     }
 
 
     public static readonly DependencyProperty ColorToReplaceProperty =
-        DependencyProperty.Register(nameof(ColorToReplace), typeof(SKColor), typeof(ColorReplacer), new PropertyMetadata(SKColors.White));
+        DependencyProperty.Register(nameof(ColorToReplace), typeof(BackendColor), typeof(ColorReplacer), new PropertyMetadata(BackendColors.White));
 
 
     public Color HintColor
@@ -68,7 +69,7 @@ internal partial class ColorReplacer : UserControl
         if (e.Data.GetDataPresent(PaletteColor.PaletteColorDaoFormat))
         {
             string hex = (string)e.Data.GetData(PaletteColor.PaletteColorDaoFormat);
-            ColorToReplace = SKColor.Parse(hex).WithAlpha(255);
+            ColorToReplace = BackendColor.Parse(hex).WithAlpha(255);
         }
     }
 
@@ -79,7 +80,7 @@ internal partial class ColorReplacer : UserControl
 
     private void ReplaceButton_OnClick(object sender, RoutedEventArgs e)
     {
-        SKColor first = ColorToReplace.WithAlpha(255);
+        BackendColor first = ColorToReplace.WithAlpha(255);
         Color rawSecond = NewColor;
 
         SKColor second = new SKColor(rawSecond.R, rawSecond.G, rawSecond.B, 255);
@@ -90,6 +91,6 @@ internal partial class ColorReplacer : UserControl
             ReplaceColorsCommand.Execute(pack);
         }
 
-        ColorToReplace = SKColors.White;
+        ColorToReplace = BackendColors.White;
     }
 }

+ 2 - 2
src/PixiEditor/Views/UserControls/Palettes/PaletteColor.xaml

@@ -9,7 +9,7 @@
              mc:Ignorable="d" MouseDown="PaletteColor_OnMouseDown"
              d:DesignHeight="45" d:DesignWidth="45" Name="uc" MouseMove="PaletteColor_OnMouseMove">
     <UserControl.Resources>
-        <converters:SKColorToMediaColorConverter x:Key="SKColorToMediaColorConverter" />
+        <converters:BackendColorToMediaColorConverter x:Key="BackendColorToMediaColorConverter" />
         <BooleanToVisibilityConverter x:Key="BoolToVisibilityConverter" />
     </UserControl.Resources>
     <UserControl.Style>
@@ -30,7 +30,7 @@
         </Border>
         <Border CornerRadius="{Binding ElementName=uc, Path=CornerRadius}" BorderThickness="0 0 0 0.1" BorderBrush="White">
             <Border.Background>
-                <SolidColorBrush Color="{Binding Color, Converter={StaticResource SKColorToMediaColorConverter}, ElementName=uc}" />
+                <SolidColorBrush Color="{Binding Color, Converter={StaticResource BackendColorToMediaColorConverter}, ElementName=uc}" />
             </Border.Background>
         </Border>
         <Border HorizontalAlignment="Right" VerticalAlignment="Bottom" Width="15" Margin="0 0 0 -1"

+ 4 - 4
src/PixiEditor/Views/UserControls/Palettes/PaletteColor.xaml.cs

@@ -1,7 +1,7 @@
 using System.Windows;
 using System.Windows.Controls;
 using System.Windows.Input;
-using SkiaSharp;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
 
 namespace PixiEditor.Views.UserControls.Palettes;
 
@@ -9,11 +9,11 @@ internal partial class PaletteColor : UserControl
 {
     public const string PaletteColorDaoFormat = "PixiEditor.PaletteColor";
 
-    public static readonly DependencyProperty ColorProperty = DependencyProperty.Register(nameof(Color), typeof(SKColor), typeof(PaletteColor), new PropertyMetadata(default(SKColor)));
+    public static readonly DependencyProperty ColorProperty = DependencyProperty.Register(nameof(Color), typeof(Color), typeof(PaletteColor), new PropertyMetadata(default(Color)));
 
-    public SKColor Color
+    public Color Color
     {
-        get { return (SKColor)GetValue(ColorProperty); }
+        get { return (Color)GetValue(ColorProperty); }
         set { SetValue(ColorProperty, value); }
     }
 

+ 13 - 13
src/PixiEditor/Views/UserControls/Palettes/PaletteColorAdder.xaml.cs

@@ -3,7 +3,7 @@ using System.Windows;
 using System.Windows.Controls;
 using System.Windows.Media;
 using PixiEditor.Models.DataHolders;
-using SkiaSharp;
+using BackendColor = PixiEditor.DrawingApi.Core.ColorsImpl.Color;
 
 namespace PixiEditor.Views.UserControls.Palettes;
 
@@ -12,9 +12,9 @@ namespace PixiEditor.Views.UserControls.Palettes;
 /// </summary>
 internal partial class PaletteColorAdder : UserControl
 {
-    public WpfObservableRangeCollection<SKColor> Colors
+    public WpfObservableRangeCollection<BackendColor> Colors
     {
-        get { return (WpfObservableRangeCollection<SKColor>)GetValue(ColorsProperty); }
+        get { return (WpfObservableRangeCollection<BackendColor>)GetValue(ColorsProperty); }
         set { SetValue(ColorsProperty, value); }
     }
 
@@ -38,11 +38,11 @@ internal partial class PaletteColorAdder : UserControl
         }
     }
 
-    public static readonly DependencyProperty SwatchesProperty = DependencyProperty.Register(nameof(Swatches), typeof(WpfObservableRangeCollection<SKColor>), typeof(PaletteColorAdder), new PropertyMetadata(default(WpfObservableRangeCollection<SKColor>), OnSwatchesChanged));
+    public static readonly DependencyProperty SwatchesProperty = DependencyProperty.Register(nameof(Swatches), typeof(WpfObservableRangeCollection<BackendColor>), typeof(PaletteColorAdder), new PropertyMetadata(default(WpfObservableRangeCollection<BackendColor>), OnSwatchesChanged));
 
-    public WpfObservableRangeCollection<SKColor> Swatches
+    public WpfObservableRangeCollection<BackendColor> Swatches
     {
-        get { return (WpfObservableRangeCollection<SKColor>)GetValue(SwatchesProperty); }
+        get { return (WpfObservableRangeCollection<BackendColor>)GetValue(SwatchesProperty); }
         set { SetValue(SwatchesProperty, value); }
     }
 
@@ -60,7 +60,7 @@ internal partial class PaletteColorAdder : UserControl
 
 
     public static readonly DependencyProperty ColorsProperty =
-        DependencyProperty.Register(nameof(Colors), typeof(WpfObservableRangeCollection<SKColor>), typeof(PaletteColorAdder), new PropertyMetadata(default(WpfObservableRangeCollection<SKColor>), OnColorsChanged));
+        DependencyProperty.Register(nameof(Colors), typeof(WpfObservableRangeCollection<BackendColor>), typeof(PaletteColorAdder), new PropertyMetadata(default(WpfObservableRangeCollection<BackendColor>), OnColorsChanged));
 
     private static void OnColorsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
     {
@@ -85,7 +85,7 @@ internal partial class PaletteColorAdder : UserControl
 
     private void UpdateAddButton()
     {
-        AddButton.IsEnabled = !Colors.Contains(ToSKColor(SelectedColor)) && SelectedColor.A == 255;
+        AddButton.IsEnabled = !Colors.Contains(ToBackendColor(SelectedColor)) && SelectedColor.A == 255;
     }
 
     private static void OnSwatchesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
@@ -110,7 +110,7 @@ internal partial class PaletteColorAdder : UserControl
 
     private void UpdateAddSwatchesButton()
     {
-        AddFromSwatches.IsEnabled = Swatches != null && Swatches.Where(x => x.Alpha == 255).Any(x => !Colors.Contains(x));
+        AddFromSwatches.IsEnabled = Swatches != null && Swatches.Where(x => x.A == 255).Any(x => !Colors.Contains(x));
     }
 
     public PaletteColorAdder()
@@ -120,7 +120,7 @@ internal partial class PaletteColorAdder : UserControl
 
     private void Button_Click(object sender, RoutedEventArgs e)
     {
-        SKColor color = ToSKColor(SelectedColor);
+        BackendColor color = ToBackendColor(SelectedColor);
         if (!Colors.Contains(color))
         {
             Colors.Add(color.WithAlpha(255));
@@ -129,9 +129,9 @@ internal partial class PaletteColorAdder : UserControl
     }
 
     private void PortableColorPicker_ColorChanged(object sender, RoutedEventArgs e) =>
-        AddButton.IsEnabled = !Colors.Contains(ToSKColor(SelectedColor));
+        AddButton.IsEnabled = !Colors.Contains(ToBackendColor(SelectedColor));
 
-    private static SKColor ToSKColor(Color color) => new SKColor(color.R, color.G, color.B, color.A);
+    private static BackendColor ToBackendColor(Color color) => new BackendColor(color.R, color.G, color.B, color.A);
 
     private void AddFromSwatches_OnClick(object sender, RoutedEventArgs e)
     {
@@ -139,7 +139,7 @@ internal partial class PaletteColorAdder : UserControl
 
         foreach (var color in Swatches)
         {
-            if (color.Alpha < 255) continue; // No alpha support for now, palette colors shouldn't be transparent
+            if (color.A < 255) continue; // No alpha support for now, palette colors shouldn't be transparent
 
             if (!Colors.Contains(color))
             {

+ 3 - 3
src/PixiEditor/Views/UserControls/PreviewWindow.xaml.cs

@@ -2,7 +2,7 @@
 using System.Windows.Controls;
 using System.Windows.Input;
 using System.Windows.Media;
-using ChunkyImageLib.DataHolders;
+using BackendColor = PixiEditor.DrawingApi.Core.ColorsImpl.Color;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.ViewModels.SubViewModels.Document;
 
@@ -136,7 +136,7 @@ internal partial class PreviewWindow : UserControl
 
         ColorCursorPosition = newPos;
 
-        SKColor color = Document.PickColor(new(x, y), true);
-        ColorCursorColor = Color.FromArgb(color.Alpha, color.Red, color.Green, color.Blue);
+        BackendColor color = Document.PickColor(new(x, y), true);
+        ColorCursorColor = Color.FromArgb(color.A, color.R, color.G, color.B);
     }
 }

+ 1 - 1
src/PixiEditor/Views/UserControls/SwatchesView.xaml

@@ -13,7 +13,7 @@
              d:DesignHeight="450" d:DesignWidth="300">
     <UserControl.Resources>
         <ResourceDictionary>
-            <conv:SKColorToMediaColorConverter x:Key="SKColorToMediaColorConverter"/>
+            <conv:BackendColorToMediaColorConverter x:Key="BackendColorToMediaColorConverter"/>
         </ResourceDictionary>
     </UserControl.Resources>
     <ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">

+ 4 - 3
src/PixiEditor/Views/UserControls/SwatchesView.xaml.cs

@@ -2,6 +2,7 @@
 using System.Windows;
 using System.Windows.Controls;
 using System.Windows.Input;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
 using SkiaSharp;
 
 namespace PixiEditor.Views.UserControls;
@@ -9,11 +10,11 @@ namespace PixiEditor.Views.UserControls;
 internal partial class SwatchesView : UserControl
 {
     public static readonly DependencyProperty SwatchesProperty =
-        DependencyProperty.Register(nameof(Swatches), typeof(ObservableCollection<SKColor>), typeof(SwatchesView));
+        DependencyProperty.Register(nameof(Swatches), typeof(ObservableCollection<Color>), typeof(SwatchesView));
 
-    public ObservableCollection<SKColor> Swatches
+    public ObservableCollection<Color> Swatches
     {
-        get => (ObservableCollection<SKColor>)GetValue(SwatchesProperty);
+        get => (ObservableCollection<Color>)GetValue(SwatchesProperty);
         set => SetValue(SwatchesProperty, value);
     }
 

+ 1 - 1
src/PixiEditor/Views/UserControls/ToolSettingColorPicker.xaml

@@ -14,6 +14,6 @@
     <colorpicker:PortableColorPicker Width="40" Height="20" x:Name="ColorPicker" UseHintColor="True"
                                      HintColor="{Binding DataContext.ColorsSubViewModel.PrimaryColor, 
         RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type views:MainWindow}, AncestorLevel=1},
-        Converter={converters:SKColorToMediaColorConverter}}"
+        Converter={converters:BackendColorToMediaColorConverter}}"
                                      SelectedColor="{Binding SelectedColor, ElementName=uc, Mode=TwoWay}"/>
 </UserControl>