Browse Source

Fix ConvertToColorArray and namespaces

tznind 10 months ago
parent
commit
68d5e995d1

+ 1 - 1
Terminal.Gui/Drawing/Quant/CIE76ColorDistance.cs

@@ -1,4 +1,4 @@
-namespace Terminal.Gui.Drawing.Quant;
+namespace Terminal.Gui;
 
 /// <summary>
 /// This is the simplest method to measure color difference in the CIE Lab color space. The Euclidean distance in Lab

+ 1 - 1
Terminal.Gui/Drawing/Quant/CIE94ColorDistance.cs

@@ -1,4 +1,4 @@
-namespace Terminal.Gui.Drawing.Quant;
+namespace Terminal.Gui;
 
 /// <summary>
 /// CIE94 improves on CIE76 by introducing adjustments for chroma (color intensity) and lightness.

+ 3 - 3
Terminal.Gui/Drawing/Quant/ColorQuantizer.cs

@@ -1,6 +1,7 @@
 using System.Collections.ObjectModel;
+using Terminal.Gui.Drawing.Quant;
 
-namespace Terminal.Gui.Drawing.Quant;
+namespace Terminal.Gui;
 
 /// <summary>
 /// Translates colors in an image into a Palette of up to 256 colors.
@@ -27,9 +28,8 @@ public class ColorQuantizer
 
     /// <summary>
     /// Gets or sets the algorithm used to build the <see cref="Palette"/>.
-    /// Defaults to <see cref="MedianCutPaletteBuilder"/>
     /// </summary>
-    public IPaletteBuilder PaletteBuildingAlgorithm { get; set; } = new MedianCutPaletteBuilder ();
+    public IPaletteBuilder PaletteBuildingAlgorithm { get; set; } = new KMeansPaletteBuilder (new EuclideanColorDistance ()) ;
 
     public void BuildPalette (Color [,] pixels)
     {

+ 1 - 1
Terminal.Gui/Drawing/Quant/EuclideanColorDistance.cs

@@ -1,4 +1,4 @@
-namespace Terminal.Gui.Drawing.Quant;
+namespace Terminal.Gui;
 
 /// <summary>
 /// Calculates the distance between two colors using Euclidean distance in 3D RGB space.

+ 1 - 1
Terminal.Gui/Drawing/Quant/IColorDistance.cs

@@ -1,4 +1,4 @@
-namespace Terminal.Gui.Drawing.Quant;
+namespace Terminal.Gui;
 
 /// <summary>
 /// Interface for algorithms that compute the relative distance between pairs of colors.

+ 1 - 1
Terminal.Gui/Drawing/Quant/IPaletteBuilder.cs

@@ -1,4 +1,4 @@
-namespace Terminal.Gui.Drawing.Quant;
+namespace Terminal.Gui;
 
 public interface IPaletteBuilder
 {

+ 1 - 1
Terminal.Gui/Drawing/Quant/LabColorDistance.cs

@@ -1,6 +1,6 @@
 using ColorHelper;
 
-namespace Terminal.Gui.Drawing.Quant;
+namespace Terminal.Gui;
 
 public abstract class LabColorDistance : IColorDistance
 {

+ 53 - 76
Terminal.Gui/Drawing/Quant/MedianCutPaletteBuilder.cs

@@ -1,4 +1,4 @@
-namespace Terminal.Gui.Drawing.Quant;
+namespace Terminal.Gui;
 
 public class MedianCutPaletteBuilder : IPaletteBuilder
 {
@@ -10,7 +10,7 @@ public class MedianCutPaletteBuilder : IPaletteBuilder
         // Keep splitting boxes until we have the desired number of colors
         while (boxes.Count < maxColors)
         {
-            // Find the box with the largest range and split it
+            // Find the box with the largest brightness range and split it
             ColorBox boxToSplit = FindBoxWithLargestRange (boxes);
 
             if (boxToSplit == null || boxToSplit.Colors.Count == 0)
@@ -18,25 +18,25 @@ public class MedianCutPaletteBuilder : IPaletteBuilder
                 break;
             }
 
-            // Split the box into two smaller boxes
-            var splitBoxes = SplitBox (boxToSplit);
+            // Split the box into two smaller boxes, based on luminance
+            var splitBoxes = SplitBoxByLuminance (boxToSplit);
             boxes.Remove (boxToSplit);
             boxes.AddRange (splitBoxes);
         }
 
         // Average the colors in each box to get the final palette
-        return boxes.Select (box => box.GetAverageColor ()).ToList ();
+        return boxes.Select (box => box.GetWeightedAverageColor ()).ToList ();
     }
 
-    // Find the box with the largest color range (R, G, or B)
+    // Find the box with the largest brightness range (based on luminance)
     private ColorBox FindBoxWithLargestRange (List<ColorBox> boxes)
     {
         ColorBox largestRangeBox = null;
-        int largestRange = 0;
+        double largestRange = 0;
 
         foreach (var box in boxes)
         {
-            int range = box.GetColorRange ();
+            double range = box.GetBrightnessRange ();
             if (range > largestRange)
             {
                 largestRange = range;
@@ -47,14 +47,10 @@ public class MedianCutPaletteBuilder : IPaletteBuilder
         return largestRangeBox;
     }
 
-    // Split a box at the median point in its largest color channel
-    private List<ColorBox> SplitBox (ColorBox box)
+    // Split a box at the median point based on brightness (luminance)
+    private List<ColorBox> SplitBoxByLuminance (ColorBox box)
     {
-        List<ColorBox> result = new List<ColorBox> ();
-
-        // Find the color channel with the largest range (R, G, or B)
-        int channel = box.GetLargestChannel ();
-        var sortedColors = box.Colors.OrderBy (c => GetColorChannelValue (c, channel)).ToList ();
+        var sortedColors = box.Colors.OrderBy (c => GetBrightness (c)).ToList ();
 
         // Split the box at the median
         int medianIndex = sortedColors.Count / 2;
@@ -62,22 +58,18 @@ public class MedianCutPaletteBuilder : IPaletteBuilder
         var lowerHalf = sortedColors.Take (medianIndex).ToList ();
         var upperHalf = sortedColors.Skip (medianIndex).ToList ();
 
-        result.Add (new ColorBox (lowerHalf));
-        result.Add (new ColorBox (upperHalf));
-
-        return result;
+        return new List<ColorBox>
+        {
+            new ColorBox(lowerHalf),
+            new ColorBox(upperHalf)
+        };
     }
 
-    // Helper method to get the value of a color channel (R = 0, G = 1, B = 2)
-    private static int GetColorChannelValue (Color color, int channel)
+    // Calculate the brightness (luminance) of a color
+    private static double GetBrightness (Color color)
     {
-        switch (channel)
-        {
-            case 0: return color.R;
-            case 1: return color.G;
-            case 2: return color.B;
-            default: throw new ArgumentException ("Invalid channel index");
-        }
+        // Luminance formula (standard)
+        return 0.299 * color.R + 0.587 * color.G + 0.114 * color.B;
     }
 
     // The ColorBox class to represent a subset of colors
@@ -90,72 +82,57 @@ public class MedianCutPaletteBuilder : IPaletteBuilder
             Colors = colors;
         }
 
-        // Get the color channel with the largest range (0 = R, 1 = G, 2 = B)
-        public int GetLargestChannel ()
-        {
-            int rRange = GetColorRangeForChannel (0);
-            int gRange = GetColorRangeForChannel (1);
-            int bRange = GetColorRangeForChannel (2);
-
-            if (rRange >= gRange && rRange >= bRange)
-            {
-                return 0;
-            }
-
-            if (gRange >= rRange && gRange >= bRange)
-            {
-                return 1;
-            }
-
-            return 2;
-        }
-
-        // Get the range of colors for a given channel (0 = R, 1 = G, 2 = B)
-        private int GetColorRangeForChannel (int channel)
+        // Get the range of brightness (luminance) in this box
+        public double GetBrightnessRange ()
         {
-            int min = int.MaxValue, max = int.MinValue;
+            double minBrightness = double.MaxValue, maxBrightness = double.MinValue;
 
             foreach (var color in Colors)
             {
-                int value = GetColorChannelValue (color, channel);
-                if (value < min)
+                double brightness = GetBrightness (color);
+                if (brightness < minBrightness)
                 {
-                    min = value;
+                    minBrightness = brightness;
                 }
 
-                if (value > max)
+                if (brightness > maxBrightness)
                 {
-                    max = value;
+                    maxBrightness = brightness;
                 }
             }
 
-            return max - min;
-        }
-
-        // Get the overall color range across all channels (for finding the box to split)
-        public int GetColorRange ()
-        {
-            int rRange = GetColorRangeForChannel (0);
-            int gRange = GetColorRangeForChannel (1);
-            int bRange = GetColorRangeForChannel (2);
-
-            return Math.Max (rRange, Math.Max (gRange, bRange));
+            return maxBrightness - minBrightness;
         }
 
-        // Calculate the average color in the box
-        public Color GetAverageColor ()
+        // Calculate the average color in the box, weighted by brightness (darker colors have more weight)
+        public Color GetWeightedAverageColor ()
         {
-            int totalR = 0, totalG = 0, totalB = 0;
+            double totalR = 0, totalG = 0, totalB = 0;
+            double totalWeight = 0;
 
             foreach (var color in Colors)
             {
-                totalR += color.R;
-                totalG += color.G;
-                totalB += color.B;
+                double brightness = GetBrightness (color);
+                double weight = 1.0 - brightness / 255.0; // Darker colors get more weight
+
+                totalR += color.R * weight;
+                totalG += color.G * weight;
+                totalB += color.B * weight;
+                totalWeight += weight;
             }
 
-            int count = Colors.Count;
-            return new Color (totalR / count, totalG / count, totalB / count);
+            // Normalize by the total weight
+            totalR /= totalWeight;
+            totalG /= totalWeight;
+            totalB /= totalWeight;
+
+            return new Color ((int)totalR, (int)totalG, (int)totalB);
+        }
+
+        // Calculate brightness (luminance) of a color
+        private static double GetBrightness (Color color)
+        {
+            return 0.299 * color.R + 0.587 * color.G + 0.114 * color.B;
         }
     }
-}
+}

+ 1 - 1
Terminal.Gui/Drawing/SixelEncoder.cs

@@ -1,4 +1,4 @@
-using Terminal.Gui.Drawing.Quant;
+using Terminal.Gui;
 
 namespace Terminal.Gui;
 

+ 1 - 2
UICatalog/Scenarios/Images.cs

@@ -8,7 +8,6 @@ using SixLabors.ImageSharp;
 using SixLabors.ImageSharp.PixelFormats;
 using SixLabors.ImageSharp.Processing;
 using Terminal.Gui;
-using Terminal.Gui.Drawing.Quant;
 using Color = Terminal.Gui.Color;
 
 namespace UICatalog.Scenarios;
@@ -210,7 +209,7 @@ public class Images : Scenario
                 for (int y = 0; y < height; y++)
                 {
                     var pixel = image [x, y];
-                    colors [x, y] = new Color (pixel.A, pixel.R, pixel.G, pixel.B); // Convert Rgba32 to System.Drawing.Color
+                    colors [x, y] = new Color (pixel.R, pixel.G, pixel.B); // Convert Rgba32 to System.Drawing.Color
                 }
             }