Переглянути джерело

Fixed color spaces getting mixed

flabbet 8 місяців тому
батько
коміт
f2f663c2a5

+ 1 - 1
src/ChunkyImageLib/ChunkyImage.cs

@@ -75,7 +75,7 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable, ICloneable, ICache
     private static Paint AddingPaint { get; } = new Paint() { BlendMode = BlendMode.Plus };
     private readonly Paint blendModePaint = new Paint() { BlendMode = BlendMode.Src };
 
-    public ColorSpace ProcessingColorSpace { get; set; } = ColorSpace.CreateSrgbLinear();
+    public ColorSpace ProcessingColorSpace { get; set; }
     
     public int CommitCounter => commitCounter;
 

+ 1 - 1
src/Drawie

@@ -1 +1 @@
-Subproject commit bfb22ae2b5f17e0f750c8106ec4677614c697428
+Subproject commit d1037e37ec4319597db8aac4d9b13c7fd85c7fa8

+ 16 - 10
src/PixiEditor.ChangeableDocument/Changeables/Document.cs

@@ -90,13 +90,13 @@ internal class Document : IChangeable, IReadOnlyDocument
         using var paint = new Paint();
 
         Surface image;
-        
+
         if (layer is IReadOnlyImageNode imageNode)
         {
             var chunkyImage = imageNode.GetLayerImageAtFrame(frame);
             using Surface chunkSurface = new Surface(chunkyImage.CommittedSize);
             chunkyImage.DrawCommittedRegionOn(
-                new RectI(0, 0, chunkyImage.CommittedSize.X, chunkyImage.CommittedSize.Y), 
+                new RectI(0, 0, chunkyImage.CommittedSize.X, chunkyImage.CommittedSize.Y),
                 ChunkResolution.Full,
                 chunkSurface.DrawingSurface,
                 VecI.Zero);
@@ -109,7 +109,7 @@ internal class Document : IChangeable, IReadOnlyDocument
             /*TODO: this*/
             // image = new Surface(layer.Execute(new RenderingContext(frame, Size)));
         }
-        
+
         //todo: idk if it's correct
         surface.DrawingSurface.Canvas.DrawSurface(image.DrawingSurface, 0, 0, paint);
 
@@ -139,6 +139,11 @@ internal class Document : IChangeable, IReadOnlyDocument
     /// </summary>
     public void ForEveryMember(Action<StructureNode> action) => ForEveryMember(NodeGraph, action);
 
+    public void InitProcessingColorSpace(ColorSpace processingColorSpace)
+    {
+        ProcessingColorSpace = processingColorSpace;
+    }
+
     private void ForEveryReadonlyMember(IReadOnlyNodeGraph graph, Action<IReadOnlyStructureNode> action)
     {
         graph.TryTraverse((node) =>
@@ -174,7 +179,7 @@ internal class Document : IChangeable, IReadOnlyDocument
     {
         return NodeGraph.Nodes.Any(x => x.Id == id);
     }
-    
+
     /// <summary>
     ///     Checks if a node in NodeGraph with the given <paramref name="id"/> exists and is of type <typeparamref name="T"/>.
     /// </summary>
@@ -193,7 +198,7 @@ internal class Document : IChangeable, IReadOnlyDocument
     /// <returns>True if the member can be found, otherwise false</returns>
     public bool HasMember(Guid guid)
     {
-        return HasNode<StructureNode>(guid); 
+        return HasNode<StructureNode>(guid);
     }
 
     /// <summary>
@@ -248,7 +253,7 @@ internal class Document : IChangeable, IReadOnlyDocument
     {
         return NodeGraph.Nodes.FirstOrDefault(x => x.Id == guid);
     }
-    
+
     IReadOnlyNode IReadOnlyDocument.FindNode(Guid guid) => FindNodeOrThrow<Node>(guid);
 
     public T? FindNode<T>(Guid guid) where T : Node
@@ -278,7 +283,7 @@ internal class Document : IChangeable, IReadOnlyDocument
     public bool TryFindMember(Guid guid, [NotNullWhen(true)] out StructureNode? member)
     {
         member = FindMember(guid);
-        return member != null; 
+        return member != null;
     }
 
     /// <summary>
@@ -342,13 +347,13 @@ internal class Document : IChangeable, IReadOnlyDocument
         if (NodeGraph.OutputNode == null) return [];
 
         var list = new List<Node>();
-        
+
         var targetNode = FindNode(guid);
         if (targetNode == null)
         {
             return [];
         }
-        
+
         FillNodePath(targetNode, list);
         return list;
     }
@@ -367,6 +372,7 @@ internal class Document : IChangeable, IReadOnlyDocument
         {
             return [];
         }
+
         FillNodePath<StructureNode>(targetNode, list);
         return list.ToList();
     }
@@ -382,7 +388,7 @@ internal class Document : IChangeable, IReadOnlyDocument
 
             return true;
         });
-        
+
         return true;
     }
 

+ 1 - 0
src/PixiEditor.ChangeableDocument/Changeables/Interfaces/IReadOnlyDocument.cs

@@ -103,4 +103,5 @@ public interface IReadOnlyDocument : IDisposable
     IReadOnlyReferenceLayer? ReferenceLayer { get; }
     public DocumentRenderer Renderer { get; }
     public ColorSpace ProcessingColorSpace { get; }
+    public void InitProcessingColorSpace(ColorSpace processingColorSpace);
 }

+ 1 - 1
src/PixiEditor.ChangeableDocument/Changes/Drawing/LineBasedPen_UpdateableChange.cs

@@ -151,7 +151,7 @@ internal class LineBasedPen_UpdateableChange : UpdateableChange
         radius = MathF.Max(1, radius);
         srcPaint.Shader = Shader.CreateRadialGradient(
             pos, radius, [color, color.WithAlpha(0)],
-            [Math.Max(hardness - 0.04f, 0), 1f], ShaderTileMode.Clamp);
+            [Math.Max(hardness + 0.04f, 0), 1f], ShaderTileMode.Clamp);
     }
 
     public override OneOf<None, IChangeInfo, List<IChangeInfo>> Apply(Document target, bool firstApply,

+ 33 - 5
src/PixiEditor.ChangeableDocument/Changes/Properties/ChangeProcessingColorSpace_Change.cs

@@ -1,4 +1,6 @@
 using Drawie.Backend.Core.Surfaces.ImageData;
+using Drawie.Numerics;
+using PixiEditor.ChangeableDocument.Changeables.Graph.Nodes;
 using PixiEditor.ChangeableDocument.ChangeInfos.Properties;
 
 namespace PixiEditor.ChangeableDocument.Changes.Properties;
@@ -7,31 +9,57 @@ internal class ChangeProcessingColorSpace_Change : Change
 {
     private ColorSpace toColorSpace;
     private ColorSpace original;
-    
+
     [GenerateMakeChangeAction]
     public ChangeProcessingColorSpace_Change(ColorSpace newColorSpace)
     {
         this.toColorSpace = newColorSpace;
     }
-    
+
     public override bool InitializeAndValidate(Document target)
     {
         original = target.ProcessingColorSpace;
-        return true;  
+        return true;
     }
 
-    public override OneOf<None, IChangeInfo, List<IChangeInfo>> Apply(Document target, bool firstApply, out bool ignoreInUndo)
+    public override OneOf<None, IChangeInfo, List<IChangeInfo>> Apply(Document target, bool firstApply,
+        out bool ignoreInUndo)
     {
         ignoreInUndo = false;
         target.ProcessingColorSpace = toColorSpace;
 
+        ConvertImageNodes(target, toColorSpace);
+
         return new ProcessingColorSpace_ChangeInfo(toColorSpace);
     }
 
     public override OneOf<None, IChangeInfo, List<IChangeInfo>> Revert(Document target)
     {
         target.ProcessingColorSpace = original;
-        
+
+        ConvertImageNodes(target, original);
+
         return new ProcessingColorSpace_ChangeInfo(original);
     }
+
+    private void ConvertImageNodes(Document target, ColorSpace newColorSpace)
+    {
+        foreach (var node in target.NodeGraph.Nodes)
+        {
+            if (node is ImageLayerNode imageLayerNode)
+            {
+                foreach (var keyFrame in imageLayerNode.KeyFrames)
+                {
+                    if (keyFrame.Data is ChunkyImage chunkyImage)
+                    {
+                        ChunkyImage img = new ChunkyImage(chunkyImage.LatestSize, newColorSpace);
+                        img.EnqueueDrawCommitedChunkyImage(VecI.Zero, chunkyImage);
+                        img.CommitChanges();
+
+                        keyFrame.Data = img;
+                    }
+                }
+            }
+        }
+    }
 }

+ 7 - 0
src/PixiEditor/Helpers/DocumentViewModelBuilder.cs

@@ -33,6 +33,7 @@ internal class DocumentViewModelBuilder
     public NodeGraphBuilder Graph { get; set; }
     public string ImageEncoderUsed { get; set; } = "QOI";
     public bool UsesLegacyColorBlending { get; set; } = false;
+    public Version? PixiParserVersionUsed { get; set; }
 
     public DocumentViewModelBuilder WithSize(int width, int height)
     {
@@ -207,6 +208,12 @@ internal class DocumentViewModelBuilder
         SerializerVersion = documentSerializerVersion;
         return this;
     }
+
+    public DocumentViewModelBuilder WithPixiParserVersion(Version version)
+    {
+        PixiParserVersionUsed = version;
+        return this;
+    }
 }
 
 internal class AnimationDataBuilder

+ 1 - 0
src/PixiEditor/Helpers/Extensions/PixiParserDocumentEx.cs

@@ -29,6 +29,7 @@ internal static class PixiParserDocumentEx
         }
 
         return DocumentViewModel.Build(b => b
+            .WithPixiParserVersion(document.Version)
             .WithSerializerData(document.SerializerName, document.SerializerVersion)
             .WithLegacyColorBlending(document.LegacyColorBlending)
             .WithSize(document.Width, document.Height)

+ 1 - 0
src/PixiEditor/Helpers/Extensions/PixiParserPixiV4DocumentEx.cs

@@ -25,6 +25,7 @@ internal static class PixiParserPixiV4DocumentEx
         return DocumentViewModel.Build(b =>
         {
             b.ImageEncoderUsed = "PNG";
+            b.PixiParserVersionUsed = document.Version;
             b.WithSize(document.Width, document.Height)
                 .WithPalette(document.Palette, x => new PaletteColor(x.R, x.G, x.B))
                 .WithSwatches(document.Swatches, x => new(x.R, x.G, x.B))

+ 1 - 1
src/PixiEditor/Models/Serialization/SerializationConfig.cs

@@ -6,7 +6,7 @@ namespace PixiEditor.Models.Serialization;
 public class SerializationConfig
 {
     public ImageEncoder Encoder { get; set; }
-    public ColorSpace ProcessingProcessingColorSpace { get; set; } = ColorSpace.CreateSrgbLinear();
+    public ColorSpace ProcessingProcessingColorSpace { get; set; }
     
     public SerializationConfig(ImageEncoder encoder, ColorSpace processingColorSpace)
     {

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

@@ -295,10 +295,12 @@ internal partial class DocumentViewModel : PixiObservableObject, IDocument
         var acc = viewModel.Internals.ActionAccumulator;
 
         ColorSpace targetProcessingColorSpace = ColorSpace.CreateSrgbLinear();
-        if (builderInstance.UsesLegacyColorBlending || IsFileWithOldColorBlending(serializerData))
+        if (builderInstance.UsesLegacyColorBlending ||
+            IsFileWithOldColorBlending(serializerData, builderInstance.PixiParserVersionUsed))
         {
             targetProcessingColorSpace = ColorSpace.CreateSrgb();
-            acc.AddFinishedActions(new ChangeProcessingColorSpace_Action(ColorSpace.CreateSrgb()));
+            viewModel.Internals.Tracker.Document.InitProcessingColorSpace(ColorSpace.CreateSrgb());
+            viewModel.UsesLegacyBlending = true;
         }
 
         viewModel.Internals.ChangeController.SymmetryDraggedInlet(
@@ -322,7 +324,8 @@ internal partial class DocumentViewModel : PixiObservableObject, IDocument
         viewModel.Palette = new ObservableRangeCollection<PaletteColor>(builderInstance.Palette);
 
         SerializationConfig config =
-            new SerializationConfig(BuiltInEncoders.Encoders[builderInstance.ImageEncoderUsed], targetProcessingColorSpace);
+            new SerializationConfig(BuiltInEncoders.Encoders[builderInstance.ImageEncoderUsed],
+                targetProcessingColorSpace);
 
         List<SerializationFactory> allFactories =
             ViewModelMain.Current.Services.GetServices<SerializationFactory>().ToList();
@@ -449,19 +452,25 @@ internal partial class DocumentViewModel : PixiObservableObject, IDocument
                 }
             }
         }
-        
-        bool IsFileWithOldColorBlending((string serializerName, string serializerVersion) serializerData)
+
+        bool IsFileWithOldColorBlending((string serializerName, string serializerVersion) serializerData,
+            Version? pixiParserVersionUsed)
         {
-            if(string.IsNullOrEmpty(serializerData.serializerName) && string.IsNullOrEmpty(serializerData.serializerVersion))
+            if (pixiParserVersionUsed != null && pixiParserVersionUsed.Major < 5)
             {
                 return true;
             }
 
+            if (serializerData.serializerVersion == null || serializerData.serializerName == null)
+            {
+                return false;
+            }
+
             try
             {
                 Version parsedVersion = new Version(serializerData.serializerVersion);
 
-                return serializerData.serializerName == "PixiEditor" 
+                return serializerData.serializerName == "PixiEditor"
                        && parsedVersion is { Major: 2, Minor: 0, Build: 0, Revision: >= 28 and <= 31 };
             }
             catch (Exception)