Browse Source

Fixed brightness tool and replace color

flabbet 7 months ago
parent
commit
b2133f7822

+ 26 - 9
src/ChunkyImageLib/ChunkyImage.cs

@@ -76,7 +76,7 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable, ICloneable, ICache
     private readonly Paint blendModePaint = new Paint() { BlendMode = BlendMode.Src };
 
     public ColorSpace ProcessingColorSpace { get; set; }
-    
+
     public int CommitCounter => commitCounter;
 
     public VecI CommittedSize { get; private set; }
@@ -130,7 +130,7 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable, ICloneable, ICache
             [ChunkResolution.Quarter] = new(),
             [ChunkResolution.Eighth] = new(),
         };
-        
+
         ProcessingColorSpace = colorSpace;
     }
 
@@ -280,7 +280,23 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable, ICloneable, ICache
             return MaybeGetCommittedChunk(chunkPos, ChunkResolution.Full) switch
             {
                 null => Colors.Transparent,
-                var chunk => chunk.Surface.GetPixel(posInChunk)
+                var chunk => chunk.Surface.GetSrgbPixel(posInChunk)
+            };
+        }
+    }
+
+    /// <exception cref="ObjectDisposedException">This image is disposed</exception>
+    public Color GetCommittedPixelRaw(VecI posOnImage)
+    {
+        lock (lockObject)
+        {
+            ThrowIfDisposed();
+            var chunkPos = OperationHelper.GetChunkPos(posOnImage, FullChunkSize);
+            var posInChunk = posOnImage - chunkPos * FullChunkSize;
+            return MaybeGetCommittedChunk(chunkPos, ChunkResolution.Full) switch
+            {
+                null => Colors.Transparent,
+                var chunk => chunk.Surface.GetRawPixel(posInChunk)
             };
         }
     }
@@ -301,7 +317,7 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable, ICloneable, ICache
                 return committedChunk switch
                 {
                     null => Colors.Transparent,
-                    _ => committedChunk.Surface.GetPixel(posInChunk)
+                    _ => committedChunk.Surface.GetSrgbPixel(posInChunk)
                 };
             }
 
@@ -312,7 +328,7 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable, ICloneable, ICache
                 return latestChunk switch
                 {
                     null => Colors.Transparent,
-                    _ => latestChunk.Surface.GetPixel(posInChunk)
+                    _ => latestChunk.Surface.GetSrgbPixel(posInChunk)
                 };
             }
 
@@ -322,10 +338,10 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable, ICloneable, ICache
                 Chunk? latestChunk = GetLatestChunk(chunkPos, ChunkResolution.Full);
                 Color committedColor = committedChunk is null
                     ? Colors.Transparent
-                    : committedChunk.Surface.GetPixel(posInChunk);
+                    : committedChunk.Surface.GetSrgbPixel(posInChunk);
                 Color latestColor = latestChunk is null
                     ? Colors.Transparent
-                    : latestChunk.Surface.GetPixel(posInChunk);
+                    : latestChunk.Surface.GetSrgbPixel(posInChunk);
                 // using a whole chunk just to draw 1 pixel is kinda dumb,
                 // but this should be faster than any approach that requires allocations
                 using Chunk tempChunk = Chunk.Create(ProcessingColorSpace, ChunkResolution.Eighth);
@@ -333,7 +349,7 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable, ICloneable, ICache
                 using Paint latestPaint = new Paint() { Color = latestColor, BlendMode = this.blendMode };
                 tempChunk.Surface.DrawingSurface.Canvas.DrawPixel(VecI.Zero, committedPaint);
                 tempChunk.Surface.DrawingSurface.Canvas.DrawPixel(VecI.Zero, latestPaint);
-                return tempChunk.Surface.GetPixel(VecI.Zero);
+                return tempChunk.Surface.GetSrgbPixel(VecI.Zero);
             }
         }
     }
@@ -601,7 +617,8 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable, ICloneable, ICache
         lock (lockObject)
         {
             ThrowIfDisposed();
-            EllipseOperation operation = new(location, strokeColor, fillColor, strokeWidth, rotationRad, antiAliased, paint);
+            EllipseOperation operation = new(location, strokeColor, fillColor, strokeWidth, rotationRad, antiAliased,
+                paint);
             EnqueueOperation(operation);
         }
     }

+ 2 - 2
src/ChunkyImageLib/DataHolders/ColorBounds.cs

@@ -25,8 +25,8 @@ public struct ColorBounds
     {
         static (float lower, float upper) FindInclusiveBoundaryPremul(byte channel, float alpha)
         {
-            float subHalf = channel > 0 ? channel - .5f : channel;
-            float addHalf = channel < 255 ? channel + .5f : channel;
+            float subHalf = channel > 0 ? channel - 1f : channel;
+            float addHalf = channel < 255 ? channel + 1f : channel;
             
             var lower = subHalf * alpha / 255f;
             var upper = addHalf * alpha / 255f;

+ 1 - 1
src/ChunkyImageLib/Operations/PixelOperation.cs

@@ -55,7 +55,7 @@ internal class PixelOperation : IMirroredDrawOperation
         if (colorProcessor != null && getCommitedPixelFunc != null)
         {
             var pos = pixel - chunkPos * ChunkyImage.FullChunkSize;
-            pixelColor = colorProcessor(getCommitedPixelFunc(pixel), chunk.Surface.GetPixel(pos));
+            pixelColor = colorProcessor(getCommitedPixelFunc(pixel), chunk.Surface.GetSrgbPixel(pos));
         }
 
         return new Color(pixelColor.R, pixelColor.G, pixelColor.B, (byte)(pixelColor.A * chunk.Resolution.Multiplier()));

+ 14 - 1
src/ChunkyImageLib/Operations/ReplaceColorOperation.cs

@@ -2,9 +2,11 @@
 using Drawie.Backend.Core.ColorsImpl;
 using Drawie.Backend.Core.Numerics;
 using Drawie.Backend.Core.Surfaces;
+using Drawie.Backend.Core.Surfaces.ImageData;
 using Drawie.Numerics;
 
 namespace ChunkyImageLib.Operations;
+
 internal class ReplaceColorOperation : IDrawOperation
 {
     private readonly Color oldColor;
@@ -25,7 +27,18 @@ internal class ReplaceColorOperation : IDrawOperation
 
     public void DrawOnChunk(Chunk targetChunk, VecI chunkPos)
     {
-        ReplaceColor(oldColorBounds, newColorBits, targetChunk);
+        ulong targetColorBits = newColor.ToULong();
+        ColorBounds colorBounds = new(oldColor);
+        if (targetChunk.Surface.ImageInfo.ColorSpace is { IsSrgb: false })
+        {
+            var transform = ColorSpace.CreateSrgb().GetTransformFunction();
+            targetColorBits = newColor.TransformColor(transform).ToULong();
+
+            var transformOld = targetChunk.Surface.ImageInfo.ColorSpace.GetTransformFunction();
+            colorBounds = new ColorBounds(oldColor.TransformColor(transform));
+        }
+
+        ReplaceColor(colorBounds, targetColorBits, targetChunk);
     }
 
     private static unsafe void ReplaceColor(ColorBounds oldColorBounds, ulong newColorBits, Chunk chunk)

+ 1 - 1
src/Drawie

@@ -1 +1 @@
-Subproject commit 303ed11c4cb15983a0d0ca29edc798c3898a2d52
+Subproject commit c90f46c8ac9050511e5d65999c72b27e8b32ebfb

+ 3 - 3
src/PixiEditor.ChangeableDocument/Changes/Drawing/FloodFill/FloodFillHelper.cs

@@ -59,7 +59,7 @@ public static class FloodFillHelper
         VecI initPosOnChunk = startingPos - initChunkPos * chunkSize;
         var chunkAtPos = cache.GetChunk(initChunkPos);
         Color colorToReplace = chunkAtPos.Match(
-            (Chunk chunk) => chunk.Surface.GetPixel(initPosOnChunk),
+            (Chunk chunk) => chunk.Surface.GetRawPixel(initPosOnChunk),
             static (EmptyChunk _) => Colors.Transparent
         );
 
@@ -175,9 +175,9 @@ public static class FloodFillHelper
         ColorBounds bounds,
         bool checkFirstPixel)
     {
-        if (referenceChunk.Surface.GetPixel(pos) == color || drawingChunk.Surface.GetPixel(pos) == color)
+        if (referenceChunk.Surface.GetRawPixel(pos) == color || drawingChunk.Surface.GetRawPixel(pos) == color)
             return null;
-        if (checkFirstPixel && !bounds.IsWithinBounds(referenceChunk.Surface.GetPixel(pos)))
+        if (checkFirstPixel && !bounds.IsWithinBounds(referenceChunk.Surface.GetRawPixel(pos)))
             return null;
 
         byte[] pixelStates = new byte[chunkSize * chunkSize];

+ 2 - 2
src/PixiEditor.ChangeableDocument/Changes/Selection/MagicWand/MagicWandHelper.cs

@@ -126,7 +126,7 @@ internal class MagicWandHelper
 
 
         Color colorToReplace = cache.GetChunk(initChunkPos).Match(
-            (Chunk chunk) => chunk.Surface.GetPixel(initPosOnChunk),
+            (Chunk chunk) => chunk.Surface.GetRawPixel(initPosOnChunk),
             static (EmptyChunk _) => Colors.Transparent
         );
 
@@ -257,7 +257,7 @@ internal class MagicWandHelper
         VecI pos,
         ColorBounds bounds, Lines lines)
     {
-        if (!bounds.IsWithinBounds(referenceChunk.Surface.GetPixel(pos)))
+        if (!bounds.IsWithinBounds(referenceChunk.Surface.GetRawPixel(pos)))
         {
             return null;
         }

+ 1 - 0
src/PixiEditor/Models/Handlers/Tools/IBrightnessToolHandler.cs

@@ -1,4 +1,5 @@
 using Avalonia.Input;
+using PixiEditor.Models.Handlers.Toolbars;
 using PixiEditor.Models.Tools;
 
 namespace PixiEditor.Models.Handlers.Tools;

+ 25 - 0
src/PixiEditor/ViewModels/Tools/ToolSettings/Toolbars/BrightnessToolbar.cs

@@ -0,0 +1,25 @@
+using PixiEditor.Models.Handlers.Toolbars;
+using PixiEditor.ViewModels.Tools.ToolSettings.Settings;
+
+namespace PixiEditor.ViewModels.Tools.ToolSettings.Toolbars;
+
+internal class BrightnessToolbar : Toolbar, IToolSizeToolbar
+{
+    public double ToolSize
+    {
+        get => GetSetting<SizeSettingViewModel>(nameof(ToolSize)).Value;
+        set => GetSetting<SizeSettingViewModel>(nameof(ToolSize)).Value = value;
+    }
+
+    public override void OnLoadedSettings()
+    {
+        OnPropertyChanged(nameof(ToolSize));
+    }
+
+    public BrightnessToolbar()
+    {
+        var setting = new SizeSettingViewModel(nameof(ToolSize), "TOOL_SIZE_LABEL");
+        AddSetting(setting);
+        setting.ValueChanged += (_, _) => OnPropertyChanged(nameof(ToolSize));
+    }
+}

+ 3 - 3
src/PixiEditor/ViewModels/Tools/Tools/BrightnessToolViewModel.cs

@@ -23,7 +23,7 @@ internal class BrightnessToolViewModel : ToolViewModel, IBrightnessToolHandler
     public BrightnessToolViewModel()
     {
         ActionDisplay = defaultActionDisplay;
-        Toolbar = ToolbarFactory.Create<BrightnessToolViewModel, EmptyToolbar>(this);
+        Toolbar = ToolbarFactory.Create<BrightnessToolViewModel, BrightnessToolbar>(this);
     }
 
     public override bool IsErasable => true;
@@ -43,8 +43,8 @@ internal class BrightnessToolViewModel : ToolViewModel, IBrightnessToolHandler
         get => BrightnessMode;
     }
 
-    [Settings.Size("TOOL_SIZE_LABEL", Name = "ToolSize")]
-    public int ToolSize => GetValue<int>();
+    [Settings.Inherited]
+    public double ToolSize => GetValue<double>();
     
     [Settings.Float("STRENGTH_LABEL", 5, 0, 50)]
     public float CorrectionFactor => GetValue<float>();

+ 1 - 1
src/PixiEditor/ViewModels/Tools/Tools/PenToolViewModel.cs

@@ -35,7 +35,7 @@ namespace PixiEditor.ViewModels.Tools.Tools
         public override LocalizedString Tooltip => new LocalizedString("PEN_TOOL_TOOLTIP", Shortcut);
 
         [Settings.Inherited]
-        public double ToolSize => GetValue<int>();
+        public double ToolSize => GetValue<double>();
 
         [Settings.Bool("PIXEL_PERFECT_SETTING", Notify = nameof(PixelPerfectChanged), ExposedByDefault = false)]
         public bool PixelPerfectEnabled => GetValue<bool>();