Browse Source

Added Sepia node and fixed filters color spaces

Krzysztof Krysiński 5 months ago
parent
commit
e81a77b0dc

+ 1 - 1
src/Drawie

@@ -1 +1 @@
-Subproject commit 157b999633b2c08dd5bd9bd09e48adea59075481
+Subproject commit da050628e8cae779f9b31fe43ce58663b98a7c8e

+ 4 - 3
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/FilterNodes/ColorMatrixFilterNode.cs

@@ -1,4 +1,5 @@
-using Drawie.Backend.Core.Surfaces.PaintImpl;
+using Drawie.Backend.Core.Surfaces.ImageData;
+using Drawie.Backend.Core.Surfaces.PaintImpl;
 using Drawie.Numerics;
 using Drawie.Numerics;
 
 
 namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes.FilterNodes;
 namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes.FilterNodes;
@@ -16,7 +17,7 @@ public class ColorMatrixFilterNode : FilterNode
         Matrix = CreateInput(nameof(Matrix), "MATRIX", ColorMatrix.Identity);
         Matrix = CreateInput(nameof(Matrix), "MATRIX", ColorMatrix.Identity);
     }
     }
 
 
-    protected override ColorFilter? GetColorFilter()
+    protected override ColorFilter? GetColorFilter(ColorSpace colorSpace)
     {
     {
         if (Matrix.Value.Equals(lastMatrix))
         if (Matrix.Value.Equals(lastMatrix))
         {
         {
@@ -26,7 +27,7 @@ public class ColorMatrixFilterNode : FilterNode
         lastMatrix = Matrix.Value;
         lastMatrix = Matrix.Value;
         filter?.Dispose();
         filter?.Dispose();
         
         
-        filter = ColorFilter.CreateColorMatrix(Matrix.Value);
+        filter = ColorFilter.CreateColorMatrix(AdjustMatrixForColorSpace(Matrix.Value));
         return filter;
         return filter;
     }
     }
 
 

+ 21 - 6
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/FilterNodes/FilterNode.cs

@@ -1,24 +1,27 @@
 using PixiEditor.ChangeableDocument.Rendering;
 using PixiEditor.ChangeableDocument.Rendering;
 using Drawie.Backend.Core;
 using Drawie.Backend.Core;
+using Drawie.Backend.Core.Numerics;
+using Drawie.Backend.Core.Surfaces.ImageData;
 using Drawie.Backend.Core.Surfaces.PaintImpl;
 using Drawie.Backend.Core.Surfaces.PaintImpl;
+using Drawie.Numerics;
 
 
 namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes.FilterNodes;
 namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes.FilterNodes;
 
 
 public abstract class FilterNode : Node
 public abstract class FilterNode : Node
 {
 {
     public OutputProperty<Filter> Output { get; }
     public OutputProperty<Filter> Output { get; }
-    
+
     public InputProperty<Filter?> Input { get; }
     public InputProperty<Filter?> Input { get; }
-    
+
     public FilterNode()
     public FilterNode()
     {
     {
         Output = CreateOutput<Filter>(nameof(Output), "FILTERS", null);
         Output = CreateOutput<Filter>(nameof(Output), "FILTERS", null);
         Input = CreateInput<Filter>(nameof(Input), "PREVIOUS", null);
         Input = CreateInput<Filter>(nameof(Input), "PREVIOUS", null);
     }
     }
-    
+
     protected override void OnExecute(RenderContext context)
     protected override void OnExecute(RenderContext context)
     {
     {
-        var colorFilter = GetColorFilter();
+        var colorFilter = GetColorFilter(context.ProcessingColorSpace);
         var imageFilter = GetImageFilter();
         var imageFilter = GetImageFilter();
 
 
         if (colorFilter == null && imageFilter == null)
         if (colorFilter == null && imageFilter == null)
@@ -32,7 +35,19 @@ public abstract class FilterNode : Node
         Output.Value = filter == null ? new Filter(colorFilter, imageFilter) : filter.Add(colorFilter, imageFilter);
         Output.Value = filter == null ? new Filter(colorFilter, imageFilter) : filter.Add(colorFilter, imageFilter);
     }
     }
 
 
-    protected virtual ColorFilter? GetColorFilter() => null;
-    
+    protected virtual ColorFilter? GetColorFilter(ColorSpace colorSpace) => null;
+
     protected virtual ImageFilter? GetImageFilter() => null;
     protected virtual ImageFilter? GetImageFilter() => null;
+
+    protected ColorMatrix AdjustMatrixForColorSpace(ColorMatrix matrix)
+    {
+        float[] adjusted = new float[20];
+        var transformFn = ColorSpace.CreateSrgb().GetTransformFunction();
+        for (int i = 0; i < 20; i++)
+        {
+            adjusted[i] = transformFn.Transform(matrix[i]);
+        }
+
+        return new ColorMatrix(adjusted);
+    }
 }
 }

+ 11 - 5
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/FilterNodes/GrayscaleNode.cs

@@ -1,4 +1,5 @@
-using Drawie.Backend.Core.Surfaces.PaintImpl;
+using Drawie.Backend.Core.Surfaces.ImageData;
+using Drawie.Backend.Core.Surfaces.PaintImpl;
 using Drawie.Numerics;
 using Drawie.Numerics;
 
 
 namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes.FilterNodes;
 namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes.FilterNodes;
@@ -21,6 +22,7 @@ public class GrayscaleNode : FilterNode
     private double lastFactor;
     private double lastFactor;
     private bool lastNormalize;
     private bool lastNormalize;
     private Vec3D lastCustomWeight;
     private Vec3D lastCustomWeight;
+    private ColorSpace lastColorSpace;
     
     
     private ColorFilter? filter;
     private ColorFilter? filter;
     
     
@@ -33,12 +35,13 @@ public class GrayscaleNode : FilterNode
         CustomWeight = CreateInput("CustomWeight", "WEIGHT_FACTOR", new Vec3D(1, 1, 1));
         CustomWeight = CreateInput("CustomWeight", "WEIGHT_FACTOR", new Vec3D(1, 1, 1));
     }
     }
 
 
-    protected override ColorFilter GetColorFilter()
+    protected override ColorFilter? GetColorFilter(ColorSpace colorSpace)
     {
     {
         if (Mode.Value == lastMode 
         if (Mode.Value == lastMode 
             && Factor.Value == lastFactor 
             && Factor.Value == lastFactor 
             && Normalize.Value == lastNormalize &&
             && Normalize.Value == lastNormalize &&
-            CustomWeight.Value == lastCustomWeight)
+            CustomWeight.Value == lastCustomWeight
+            && colorSpace == lastColorSpace)
         {
         {
             return filter;
             return filter;
         }
         }
@@ -47,16 +50,19 @@ public class GrayscaleNode : FilterNode
         lastFactor = Factor.Value;
         lastFactor = Factor.Value;
         lastNormalize = Normalize.Value;
         lastNormalize = Normalize.Value;
         lastCustomWeight = CustomWeight.Value;
         lastCustomWeight = CustomWeight.Value;
+        lastColorSpace = colorSpace;
         
         
         filter?.Dispose();
         filter?.Dispose();
         
         
-        filter = ColorFilter.CreateColorMatrix(Mode.Value switch
+        var matrix = Mode.Value switch
         {
         {
             GrayscaleMode.Weighted => UseFactor(WeightedMatrix),
             GrayscaleMode.Weighted => UseFactor(WeightedMatrix),
             GrayscaleMode.Average => UseFactor(AverageMatrix),
             GrayscaleMode.Average => UseFactor(AverageMatrix),
             GrayscaleMode.Custom => UseFactor(ColorMatrix.WeightedGrayscale(GetAdjustedCustomWeight()) +
             GrayscaleMode.Custom => UseFactor(ColorMatrix.WeightedGrayscale(GetAdjustedCustomWeight()) +
                                               ColorMatrix.UseAlpha)
                                               ColorMatrix.UseAlpha)
-        });
+        };
+
+        filter = ColorFilter.CreateColorMatrix(AdjustMatrixForColorSpace(matrix));
         
         
         return filter;
         return filter;
     }
     }

+ 47 - 0
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/FilterNodes/SepiaFilterNode.cs

@@ -0,0 +1,47 @@
+using Drawie.Backend.Core.Numerics;
+using Drawie.Backend.Core.Surfaces.ImageData;
+using Drawie.Backend.Core.Surfaces.PaintImpl;
+using Drawie.Numerics;
+
+namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes.FilterNodes;
+
+[NodeInfo("Sepia")]
+public class SepiaFilterNode : FilterNode
+{
+    private ColorMatrix srgbSepiaMatrix;
+    private ColorMatrix linearSepiaMatrix;
+    private ColorFilter linearSepiaFilter;
+    private ColorFilter sepiaColorFilter;
+
+    public SepiaFilterNode()
+    {
+        srgbSepiaMatrix = new ColorMatrix(
+            [
+                0.393f, 0.769f, 0.189f, 0.0f, 0.0f,
+                0.349f, 0.686f, 0.168f, 0.0f, 0.0f,
+                0.272f, 0.534f, 0.131f, 0.0f, 0.0f,
+                0.0f, 0.0f, 0.0f, 1.0f, 0.0f
+            ]
+        );
+
+        sepiaColorFilter = ColorFilter.CreateColorMatrix(srgbSepiaMatrix);
+
+        linearSepiaMatrix = AdjustMatrixForColorSpace(srgbSepiaMatrix);
+        linearSepiaFilter = ColorFilter.CreateColorMatrix(linearSepiaMatrix);
+    }
+
+    protected override ColorFilter? GetColorFilter(ColorSpace colorSpace)
+    {
+        if (colorSpace.IsSrgb)
+        {
+            return sepiaColorFilter;
+        }
+
+        return linearSepiaFilter;
+    }
+
+    public override Node CreateCopy()
+    {
+        return new SepiaFilterNode();
+    }
+}

+ 5 - 4
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/LayerNode.cs

@@ -4,6 +4,7 @@ using PixiEditor.ChangeableDocument.Rendering;
 using Drawie.Backend.Core;
 using Drawie.Backend.Core;
 using Drawie.Backend.Core.ColorsImpl;
 using Drawie.Backend.Core.ColorsImpl;
 using Drawie.Backend.Core.Surfaces;
 using Drawie.Backend.Core.Surfaces;
+using Drawie.Backend.Core.Surfaces.ImageData;
 using Drawie.Backend.Core.Surfaces.PaintImpl;
 using Drawie.Backend.Core.Surfaces.PaintImpl;
 using Drawie.Numerics;
 using Drawie.Numerics;
 
 
@@ -48,7 +49,7 @@ public abstract class LayerNode : StructureNode, IReadOnlyLayerNode, IClipSource
             return;
             return;
         }
         }
 
 
-        var outputWorkingSurface = TryInitWorkingSurface(size, context.ChunkResolution, 1);
+        var outputWorkingSurface = TryInitWorkingSurface(size, context.ChunkResolution, context.ProcessingColorSpace, 1);
         outputWorkingSurface.DrawingSurface.Canvas.Clear();
         outputWorkingSurface.DrawingSurface.Canvas.Clear();
 
 
         DrawLayerOnTexture(context, outputWorkingSurface.DrawingSurface, useFilters);
         DrawLayerOnTexture(context, outputWorkingSurface.DrawingSurface, useFilters);
@@ -57,7 +58,7 @@ public abstract class LayerNode : StructureNode, IReadOnlyLayerNode, IClipSource
 
 
         if (Background.Value != null)
         if (Background.Value != null)
         {
         {
-            Texture tempSurface = TryInitWorkingSurface(size, context.ChunkResolution, 4);
+            Texture tempSurface = TryInitWorkingSurface(size, context.ChunkResolution, context.ProcessingColorSpace, 4);
             tempSurface.DrawingSurface.Canvas.Clear();
             tempSurface.DrawingSurface.Canvas.Clear();
             if (Background.Connection is { Node: IClipSource clipSource } && ClipToPreviousMember)
             if (Background.Connection is { Node: IClipSource clipSource } && ClipToPreviousMember)
             {
             {
@@ -123,7 +124,7 @@ public abstract class LayerNode : StructureNode, IReadOnlyLayerNode, IClipSource
     protected abstract void DrawWithFilters(SceneObjectRenderContext ctx, DrawingSurface workingSurface,
     protected abstract void DrawWithFilters(SceneObjectRenderContext ctx, DrawingSurface workingSurface,
         Paint paint);
         Paint paint);
 
 
-    protected Texture TryInitWorkingSurface(VecI imageSize, ChunkResolution resolution, int id)
+    protected Texture TryInitWorkingSurface(VecI imageSize, ChunkResolution resolution, ColorSpace processingCs, int id)
     {
     {
         ChunkResolution targetResolution = resolution;
         ChunkResolution targetResolution = resolution;
         bool hasSurface = workingSurfaces.TryGetValue((targetResolution, id), out Texture workingSurface);
         bool hasSurface = workingSurfaces.TryGetValue((targetResolution, id), out Texture workingSurface);
@@ -133,7 +134,7 @@ public abstract class LayerNode : StructureNode, IReadOnlyLayerNode, IClipSource
 
 
         if (!hasSurface || workingSurface.Size != targetSize || workingSurface.IsDisposed)
         if (!hasSurface || workingSurface.Size != targetSize || workingSurface.IsDisposed)
         {
         {
-            workingSurfaces[(targetResolution, id)] = new Texture(targetSize);
+            workingSurfaces[(targetResolution, id)] = Texture.ForProcessing(targetSize, processingCs);
             workingSurface = workingSurfaces[(targetResolution, id)];
             workingSurface = workingSurfaces[(targetResolution, id)];
         }
         }
 
 

+ 8 - 0
src/PixiEditor/ViewModels/Document/Nodes/FilterNodes/SepiaFilterNodeViewModel.cs

@@ -0,0 +1,8 @@
+using PixiEditor.ChangeableDocument.Changeables.Graph.Nodes.FilterNodes;
+using PixiEditor.UI.Common.Fonts;
+using PixiEditor.ViewModels.Nodes;
+
+namespace PixiEditor.ViewModels.Document.Nodes.FilterNodes;
+
+[NodeViewModel("SEPIA_NODE", "FILTERS", "")]
+internal class SepiaFilterNodeViewModel : NodeViewModel<SepiaFilterNode>;