Browse Source

Brightness tool works better now

flabbet 5 years ago
parent
commit
b522e8b76e

+ 115 - 13
PixiEditor/Models/Colors/ExColor.cs

@@ -1,4 +1,5 @@
-using System.Windows.Media;
+using System;
+using System.Windows.Media;
 
 namespace PixiEditor.Models.Colors
 {
@@ -15,25 +16,126 @@ namespace PixiEditor.Models.Colors
         /// </returns>
         public static Color ChangeColorBrightness(Color color, float correctionFactor)
         {
-            float red = color.R;
-            float green = color.G;
-            float blue = color.B;
+            Tuple<int, float, float> hsl = RgbToHsl(color.R, color.G, color.B);
+            int h = hsl.Item1;
+            float s = hsl.Item2;
+            float l = hsl.Item3;
 
-            if (correctionFactor < 0)
+            l = Math.Clamp(l + correctionFactor, 0, 100);
+            Color rgb = HslToRGB(h, s, l);
+
+            return Color.FromArgb(color.A, rgb.R, rgb.G, rgb.B);
+        }
+
+
+        /// <summary>
+        /// Converts RGB to HSL
+        /// </summary>
+        /// <param name="r">Red value</param>
+        /// <param name="b">Blue value</param>
+        /// <param name="g">Green value</param>
+        /// <returns>Tuple with 3 values in order: h, s, l0</returns>
+        public static Tuple<int,float,float> RgbToHsl(int r, int g, int b)
+        {
+            int h;
+            float s, l;
+            float dR = (r / 255.0f);
+            float dG = (g / 255.0f);
+            float dB = (b / 255.0f);
+
+            float min = Math.Min(Math.Min(dR, dG), dB);
+            float max = Math.Max(Math.Max(dR, dG), dB);
+            float delta = max - min;
+
+            l = (max + min) / 2;
+
+            if (delta == 0)
             {
-                correctionFactor = 1 + correctionFactor;
-                red *= correctionFactor;
-                green *= correctionFactor;
-                blue *= correctionFactor;
+                h = 0;
+                s = 0.0f;
             }
             else
             {
-                red = (255 - red) * correctionFactor + red;
-                green = (255 - green) * correctionFactor + green;
-                blue = (255 - blue) * correctionFactor + blue;
+                s = (l <= 0.5) ? (delta / (max + min)) : (delta / (2 - max - min));
+
+                float hue;
+
+                if (dR == max)
+                {
+                    hue = ((dG - dB) / 6) / delta;
+                }
+                else if (dG == max)
+                {
+                    hue = (1.0f / 3) + (dB - dR) / 6 / delta;
+                }
+                else
+                {
+                    hue = (2.0f / 3) + (dR - dG) / 6 / delta;
+                }
+
+                if (hue < 0)
+                    hue += 1;
+                if (hue > 1)
+                    hue -= 1;
+
+                h = (int)(hue * 360);
             }
+            return new Tuple<int, float, float>(h, s * 100, l * 100);
+        }
 
-            return Color.FromArgb(color.A, (byte)red, (byte)green, (byte)blue);
+        /// <summary>
+        /// Converts HSL color format to RGB
+        /// </summary>
+        /// <param name="h"></param>
+        /// <param name="s"></param>
+        /// <param name="l"></param>
+        /// <returns>RGB Color</returns>
+        public static Color HslToRGB(int h, float s, float l)
+        {
+            s /= 100;
+            l /= 100;
+            byte r = 0;
+            byte g = 0;
+            byte b = 0;
+
+            if (s == 0)
+            {
+                r = g = b = (byte)(l * 255);
+            }
+            else
+            {
+                float v1, v2;
+                float hue = (float)h / 360;
+
+                v2 = (l < 0.5) ? (l * (1 + s)) : (l + s - (l * s));
+                v1 = 2 * l - v2;
+
+                r = (byte)(255 * HueToRGB(v1, v2, hue + (1.0f / 3)));
+                g = (byte)(255 * HueToRGB(v1, v2, hue));
+                b = (byte)(255 * HueToRGB(v1, v2, hue - (1.0f / 3)));
+            }
+            return Color.FromRgb(r, g, b);
         }
+
+        private static float HueToRGB(float v1, float v2, float hue)
+        {
+            if (hue < 0)
+                hue += 1;
+
+            if (hue > 1)
+                hue -= 1;
+
+            if ((6 * hue) < 1)
+                return (v1 + (v2 - v1) * 6 * hue);
+
+            if ((2 * hue) < 1)
+                return v2;
+
+            if ((3 * hue) < 2)
+                return (v1 + (v2 - v1) * ((2.0f / 3) - hue) * 6);
+
+            return v1;
+        }
+
     }
 }

+ 7 - 2
PixiEditor/Models/Controllers/BitmapOperationsUtility.cs

@@ -83,6 +83,10 @@ namespace PixiEditor.Models.Controllers
 
         public void SetActiveTool(Tool tool)
         {
+            if(PreviewLayer != null)
+            {
+                PreviewLayer.Clear();
+            }
             if (SelectedTool != null)
             {
                 SelectedTool.Toolbar.SaveToolbarSettings();
@@ -114,8 +118,8 @@ namespace PixiEditor.Models.Controllers
         {
             if(SelectedTool != null && SelectedTool.ToolType != ToolType.None && Mouse.LeftButton == MouseButtonState.Pressed)
             {
-                if (Layers.Count == 0) return;
                 var mouseMove = MouseController.LastMouseMoveCoordinates.ToList();
+                if (Layers.Count == 0 || mouseMove.Count == 0) return;
                 mouseMove.Reverse();
                 UseTool(mouseMove);
                 
@@ -129,7 +133,7 @@ namespace PixiEditor.Models.Controllers
 
         private void HighlightPixels(Coordinates newPosition)
         {
-            if (Layers.Count == 0) return;
+            if (Layers.Count == 0 || SelectedTool.HideHighlight) return;
             GeneratePreviewLayer();
             PreviewLayer.Clear();
             Coordinates[] highlightArea = CoordinatesCalculator.RectangleToCoordinates(CoordinatesCalculator.CalculateThicknessCenter(newPosition, ToolSize));    
@@ -138,6 +142,7 @@ namespace PixiEditor.Models.Controllers
 
         private void UseTool(List<Coordinates> mouseMoveCords)
         {
+            if (SelectedTool.PerformsOperationOnBitmap == false) return;
             if (Keyboard.IsKeyDown(Key.LeftShift) && !MouseCordsNotInLine(mouseMoveCords))
             {
                 mouseMoveCords = GetSquareCoordiantes(mouseMoveCords);

+ 2 - 0
PixiEditor/Models/Tools/Tool.cs

@@ -12,6 +12,8 @@ namespace PixiEditor.Models.Tools
         public abstract BitmapPixelChanges Use(Layer layer, Coordinates[] pixels, Color color);
         public abstract ToolType ToolType { get; }
         public string ImagePath => $"/Images/{ToolType}Image.png";
+        public bool PerformsOperationOnBitmap { get; set; } = true;
+        public bool HideHighlight { get; set; } = false;
         public bool RequiresPreviewLayer { get; set; }
         public string Tooltip { get; set; }
 

+ 3 - 4
PixiEditor/Models/Tools/Tools/BrightnessTool.cs

@@ -12,8 +12,7 @@ namespace PixiEditor.Models.Tools.Tools
     public class BrightnessTool : Tool
     {
         public override ToolType ToolType => ToolType.Brightness;
-        public const float DarkenFactor = -0.06f;
-        public const float LightenFactor = 0.1f;
+        public const float CorrectionFactor = 5f;
         
         public BrightnessTool()
         {
@@ -26,9 +25,9 @@ namespace PixiEditor.Models.Tools.Tools
             int toolSize = (int)Toolbar.GetSetting("ToolSize").Value;
             if(Keyboard.IsKeyDown(Key.LeftCtrl))
             {
-                return ChangeBrightness(layer, coordinates[0], toolSize, DarkenFactor);
+                return ChangeBrightness(layer, coordinates[0], toolSize, -CorrectionFactor);
             }
-                return ChangeBrightness(layer, coordinates[0], toolSize, LightenFactor);
+                return ChangeBrightness(layer, coordinates[0], toolSize, CorrectionFactor);
         }       
 
         private BitmapPixelChanges ChangeBrightness(Layer layer, Coordinates coordinates, int toolSize, float correctionFactor)

+ 25 - 0
PixiEditor/Models/Tools/Tools/ColorPickerTool.cs

@@ -0,0 +1,25 @@
+using PixiEditor.Models.Layers;
+using PixiEditor.Models.Position;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Windows.Media;
+
+namespace PixiEditor.Models.Tools.Tools
+{
+    public class ColorPickerTool : Tool
+    {
+        public override ToolType ToolType => ToolType.ColorPicker;
+
+        public ColorPickerTool()
+        {
+            PerformsOperationOnBitmap = false;
+            HideHighlight = true;
+        }
+
+        public override BitmapPixelChanges Use(Layer layer, Coordinates[] pixels, Color color)
+        {
+            return new BitmapPixelChanges();
+        }
+    }
+}

+ 9 - 5
PixiEditor/ViewModels/ViewModelMain.cs

@@ -155,7 +155,7 @@ namespace PixiEditor.ViewModels
             KeyDownCommand = new RelayCommand(KeyDown);
             RenameLayerCommand = new RelayCommand(RenameLayer);
             ToolSet = new ObservableCollection<Tool> { new PixiTools.PenTool(), new PixiTools.FloodFill(), new PixiTools.LineTool(),
-            new PixiTools.CircleTool(), new PixiTools.RectangleTool(), new PixiTools.EarserTool(), new PixiTools.BrightnessTool() };
+            new PixiTools.CircleTool(), new PixiTools.RectangleTool(), new PixiTools.EarserTool(), new PixiTools.ColorPickerTool(), new PixiTools.BrightnessTool() };
             ShortcutController = new ShortcutController
             {
                 Shortcuts = new List<Shortcut> { 
@@ -197,8 +197,12 @@ namespace PixiEditor.ViewModels
 
         private void MouseController_StoppedRecordingChanges(object sender, EventArgs e)
         {
-            Tuple<LayerChanges, LayerChanges> changes = ChangesController.PopChanges();
-            UndoManager.AddUndoChange(new Change("UndoChanges", changes.Item2, changes.Item1)); //Item2 is old value
+            if (BitmapUtility.SelectedTool.PerformsOperationOnBitmap)
+            {
+                Tuple<LayerChanges, LayerChanges> changes = ChangesController.PopChanges();
+                if (changes.Item1.PixelChanges.ChangedPixels.Count > 0)
+                    UndoManager.AddUndoChange(new Change("UndoChanges", changes.Item2, changes.Item1)); //Item2 is old value
+            }
         }
 
         private void BitmapUtility_BitmapChanged(object sender, BitmapChangedEventArgs e)
@@ -333,11 +337,11 @@ namespace PixiEditor.ViewModels
         private void MouseDown(object parameter)
         {
             if (BitmapUtility.Layers.Count == 0) return;
-            if(SelectedTool == ToolType.ColorPicker)
+            if(BitmapUtility.SelectedTool.ToolType == ToolType.ColorPicker)
             {
                 ExecuteColorPicker();
             }
-            else if(Mouse.LeftButton == MouseButtonState.Pressed)
+            else if(Mouse.LeftButton == MouseButtonState.Pressed && BitmapUtility.SelectedTool.PerformsOperationOnBitmap)
             {
                 if (!BitmapUtility.MouseController.IsRecordingChanges)
                 {

+ 30 - 2
PixiEditorTests/WorkspaceTests/ColorsTests/ExtendedColorTests.cs

@@ -13,15 +13,43 @@ namespace PixiEditorTests.WorkspaceTests.ColorsTests
         [TestCase()]
         public void ChangeColorBrightnessIsNotTheSameTest()
         {
-            Color newColor = ExColor.ChangeColorBrightness(Colors.White, -0.1f);
+            Color newColor = ExColor.ChangeColorBrightness(Colors.White, -1);
             Assert.AreNotEqual(Colors.White, newColor);
         }
 
         [TestCase()]
         public void ChangeColorBrightnessNewValueTest()
         {
-            Color newColor = ExColor.ChangeColorBrightness(Colors.White, -1f);
+            Color newColor = ExColor.ChangeColorBrightness(Colors.White, -100);
             Assert.AreEqual(Colors.Black, newColor);
         }
+
+        [TestCase(0,0,0,0,0,0)]
+        [TestCase(255,255,255,0,0,100)]
+        [TestCase(182,55,55,0,53.6f,46.5f)]
+        [TestCase(20,47,255,233,100,53.9f)]
+        [TestCase(137, 43,226, 270,75.9f,52.7f)] //Theoretically 170 should be 171, but error margin of 1 is acceptable
+        public void RgbToHslTest(int r, int g, int b, int h, float s, float l)
+        {
+            Tuple<int, float, float> hsl = ExColor.RgbToHsl(r, g, b);
+            Assert.AreEqual(h, hsl.Item1);
+            Assert.AreEqual(Math.Round(s), Math.Round(hsl.Item2));
+            Assert.AreEqual(Math.Round(l), Math.Round(hsl.Item3));
+
+        }
+
+        [TestCase(0, 0, 0, 0, 0, 0)]
+        [TestCase(0, 0, 100, 255, 255, 255)]
+        [TestCase(0, 53.6f, 46.5f, 182, 55, 55)]
+        [TestCase(297, 100, 17.1f, 82, 0, 87)]
+        [TestCase(271, 75.9f, 52.7f, 137, 42, 226)] //Same as above, but with 43 instead of 42
+        public void HslToRgbTest(int h, float s, float l, int r, int g, int b)
+        {
+            Color rgb = ExColor.HslToRGB(h, s, l);
+            Assert.AreEqual(r, rgb.R);
+            Assert.AreEqual(g, rgb.G);
+            Assert.AreEqual(b, rgb.B);
+
+        }
     }
 }