From 3c0856b93dbbb0b54573374c86b34c9fb21eaf14 Mon Sep 17 00:00:00 2001 From: Dan Royer Date: Mon, 24 Feb 2025 13:45:11 -0800 Subject: [PATCH 1/4] added interface, HSV, LUV, and unit tests --- .../donatello/colorspace/ColorSpace.java | 21 ++++++++++ .../donatello/colorspace/HSVColorSpace.java | 42 +++++++++++++++++++ .../donatello/colorspace/LUVColorSpace.java | 24 +++++++++++ .../donatello/colorspace/RGBColorSpace.java | 13 ++++++ .../donatello/colorspace/ColorSpaceTest.java | 38 +++++++++++++++++ 5 files changed, 138 insertions(+) create mode 100644 src/main/java/com/marginallyclever/donatello/colorspace/ColorSpace.java create mode 100644 src/main/java/com/marginallyclever/donatello/colorspace/HSVColorSpace.java create mode 100644 src/main/java/com/marginallyclever/donatello/colorspace/LUVColorSpace.java create mode 100644 src/main/java/com/marginallyclever/donatello/colorspace/RGBColorSpace.java create mode 100644 src/test/java/com/marginallyclever/donatello/colorspace/ColorSpaceTest.java diff --git a/src/main/java/com/marginallyclever/donatello/colorspace/ColorSpace.java b/src/main/java/com/marginallyclever/donatello/colorspace/ColorSpace.java new file mode 100644 index 0000000..f730793 --- /dev/null +++ b/src/main/java/com/marginallyclever/donatello/colorspace/ColorSpace.java @@ -0,0 +1,21 @@ +package com.marginallyclever.donatello.colorspace; + +public interface ColorSpace { + /** + * Converts RGB values (0-1 range) to the target color space. + * @param r Red component (0-1) + * @param g Green component (0-1) + * @param b Blue component (0-1) + * @return Array of converted color space values. + */ + float[] fromRGB(float r, float g, float b); + + /** + * Converts from the target color space back to RGB (0-1 range). + * @param c1 First component of color space. + * @param c2 Second component of color space. + * @param c3 Third component of color space. + * @return Array with RGB values (0-1 range). + */ + float[] toRGB(float c1, float c2, float c3); +} \ No newline at end of file diff --git a/src/main/java/com/marginallyclever/donatello/colorspace/HSVColorSpace.java b/src/main/java/com/marginallyclever/donatello/colorspace/HSVColorSpace.java new file mode 100644 index 0000000..0bf4cdf --- /dev/null +++ b/src/main/java/com/marginallyclever/donatello/colorspace/HSVColorSpace.java @@ -0,0 +1,42 @@ +package com.marginallyclever.donatello.colorspace; + +public class HSVColorSpace implements ColorSpace { + @Override + public float[] fromRGB(float r, float g, float b) { + float max = Math.max(r, Math.max(g, b)); + float min = Math.min(r, Math.min(g, b)); + float delta = max - min; + + float h = 0f; + if (delta != 0) { + if (max == r) h = ((g - b) / delta) % 6; + else if (max == g) h = ((b - r) / delta) + 2; + else h = ((r - g) / delta) + 4; + h /= 6f; + if (h < 0) h += 1; + } + + float s = (max == 0) ? 0 : (delta / max); + float v = max; + return new float[]{h, s, v}; + } + + @Override + public float[] toRGB(float h, float s, float v) { + float c = v * s; + float x = c * (1 - Math.abs((h * 6) % 2 - 1)); + float m = v - c; + + float r = 0, g = 0, b = 0; + int sector = (int)(h * 6) % 6; + switch (sector) { + case 0: r = c; g = x; break; + case 1: r = x; g = c; break; + case 2: g = c; b = x; break; + case 3: g = x; b = c; break; + case 4: r = x; b = c; break; + case 5: r = c; b = x; break; + } + return new float[]{r + m, g + m, b + m}; + } +} diff --git a/src/main/java/com/marginallyclever/donatello/colorspace/LUVColorSpace.java b/src/main/java/com/marginallyclever/donatello/colorspace/LUVColorSpace.java new file mode 100644 index 0000000..21c03af --- /dev/null +++ b/src/main/java/com/marginallyclever/donatello/colorspace/LUVColorSpace.java @@ -0,0 +1,24 @@ +package com.marginallyclever.donatello.colorspace; + +/** + * LUV color space conversion. + * https://framewave.sourceforge.net/Manual/fw_function_020_0060_00330.html + * preserve the D65 white point. + */ +public class LUVColorSpace implements ColorSpace { + @Override + public float[] fromRGB(float r, float g, float b) { + float x = r * 0.4124564f + g * 0.3575761f + b * 0.1804375f; + float y = r * 0.2126729f + g * 0.7151522f + b * 0.0721750f; + float z = r * 0.0193339f + g * 0.1191920f + b * 0.9503041f; + return new float[]{x,y,z}; + } + + @Override + public float[] toRGB(float x, float y, float z) { + float r = x * 3.2404542f + y * -1.5371385f + z * -0.4985314f; + float g = x * -0.9692660f + y * 1.8760108f + z * 0.0415560f; + float b = x * 0.0556434f + y * -0.2040259f + z * 1.0572252f; + return new float[]{r,g,b}; + } +} diff --git a/src/main/java/com/marginallyclever/donatello/colorspace/RGBColorSpace.java b/src/main/java/com/marginallyclever/donatello/colorspace/RGBColorSpace.java new file mode 100644 index 0000000..30be50e --- /dev/null +++ b/src/main/java/com/marginallyclever/donatello/colorspace/RGBColorSpace.java @@ -0,0 +1,13 @@ +package com.marginallyclever.donatello.colorspace; + +public class RGBColorSpace implements ColorSpace { + @Override + public float[] fromRGB(float r, float g, float b) { + return new float[]{r, g, b}; + } + + @Override + public float[] toRGB(float c1, float c2, float c3) { + return new float[]{c1, c2, c3}; + } +} diff --git a/src/test/java/com/marginallyclever/donatello/colorspace/ColorSpaceTest.java b/src/test/java/com/marginallyclever/donatello/colorspace/ColorSpaceTest.java new file mode 100644 index 0000000..48b56ea --- /dev/null +++ b/src/test/java/com/marginallyclever/donatello/colorspace/ColorSpaceTest.java @@ -0,0 +1,38 @@ +package com.marginallyclever.donatello.colorspace; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class ColorSpaceTest { + @Test + public void testToAndFromRGB() { + testToAndFrom(new RGBColorSpace()); + } + + @Test + public void testToAndFromLUT() { + testToAndFrom(new LUVColorSpace()); + } + + @Test + public void testToAndFromHSV() { + testToAndFrom(new HSVColorSpace()); + } + + private void testToAndFrom(ColorSpace colorSpace) { + for (int r = 0; r < 256; r++) { + for (int g = 0; g < 256; g++) { + for (int b = 0; b < 256; b++) { + float r2 = r / 255f; + float g2 = g / 255f; + float b2 = b / 255f; + float[] converted = colorSpace.fromRGB(r2, g2, b2); + float[] after = colorSpace.toRGB(converted[0], converted[1], converted[2]); + Assertions.assertEquals(after[0], r2, 0.01, r+","+g+","+b); + Assertions.assertEquals(after[1], g2, 0.01, r+","+g+","+b); + Assertions.assertEquals(after[2], b2, 0.01, r+","+g+","+b); + } + } + } + } +} From c99d001f7de62f79262600df62205246f9baae70 Mon Sep 17 00:00:00 2001 From: Dan Royer Date: Mon, 24 Feb 2025 14:03:05 -0800 Subject: [PATCH 2/4] comments --- .../com/marginallyclever/donatello/colorspace/ColorSpace.java | 3 +++ .../marginallyclever/donatello/colorspace/HSVColorSpace.java | 3 +++ .../marginallyclever/donatello/colorspace/RGBColorSpace.java | 3 +++ 3 files changed, 9 insertions(+) diff --git a/src/main/java/com/marginallyclever/donatello/colorspace/ColorSpace.java b/src/main/java/com/marginallyclever/donatello/colorspace/ColorSpace.java index f730793..3b3c4be 100644 --- a/src/main/java/com/marginallyclever/donatello/colorspace/ColorSpace.java +++ b/src/main/java/com/marginallyclever/donatello/colorspace/ColorSpace.java @@ -1,5 +1,8 @@ package com.marginallyclever.donatello.colorspace; +/** + * Interface for color space conversion to and from RGB. + */ public interface ColorSpace { /** * Converts RGB values (0-1 range) to the target color space. diff --git a/src/main/java/com/marginallyclever/donatello/colorspace/HSVColorSpace.java b/src/main/java/com/marginallyclever/donatello/colorspace/HSVColorSpace.java index 0bf4cdf..5b1077b 100644 --- a/src/main/java/com/marginallyclever/donatello/colorspace/HSVColorSpace.java +++ b/src/main/java/com/marginallyclever/donatello/colorspace/HSVColorSpace.java @@ -1,5 +1,8 @@ package com.marginallyclever.donatello.colorspace; +/** + * A color space that converts between RGB and HSV. + */ public class HSVColorSpace implements ColorSpace { @Override public float[] fromRGB(float r, float g, float b) { diff --git a/src/main/java/com/marginallyclever/donatello/colorspace/RGBColorSpace.java b/src/main/java/com/marginallyclever/donatello/colorspace/RGBColorSpace.java index 30be50e..096ffe9 100644 --- a/src/main/java/com/marginallyclever/donatello/colorspace/RGBColorSpace.java +++ b/src/main/java/com/marginallyclever/donatello/colorspace/RGBColorSpace.java @@ -1,5 +1,8 @@ package com.marginallyclever.donatello.colorspace; +/** + * A color space that converts between RGB and RGB. + */ public class RGBColorSpace implements ColorSpace { @Override public float[] fromRGB(float r, float g, float b) { From e77fe70dac4e12ae6b290a4eafc9ba66a2cb9a92 Mon Sep 17 00:00:00 2001 From: Dan Royer Date: Mon, 24 Feb 2025 15:19:27 -0800 Subject: [PATCH 3/4] added toString --- .../marginallyclever/donatello/colorspace/HSVColorSpace.java | 5 +++++ .../marginallyclever/donatello/colorspace/LUVColorSpace.java | 5 +++++ .../marginallyclever/donatello/colorspace/RGBColorSpace.java | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/src/main/java/com/marginallyclever/donatello/colorspace/HSVColorSpace.java b/src/main/java/com/marginallyclever/donatello/colorspace/HSVColorSpace.java index 5b1077b..b79740b 100644 --- a/src/main/java/com/marginallyclever/donatello/colorspace/HSVColorSpace.java +++ b/src/main/java/com/marginallyclever/donatello/colorspace/HSVColorSpace.java @@ -42,4 +42,9 @@ public float[] toRGB(float h, float s, float v) { } return new float[]{r + m, g + m, b + m}; } + + @Override + public String toString() { + return "HSV"; + } } diff --git a/src/main/java/com/marginallyclever/donatello/colorspace/LUVColorSpace.java b/src/main/java/com/marginallyclever/donatello/colorspace/LUVColorSpace.java index 21c03af..0c3efcf 100644 --- a/src/main/java/com/marginallyclever/donatello/colorspace/LUVColorSpace.java +++ b/src/main/java/com/marginallyclever/donatello/colorspace/LUVColorSpace.java @@ -21,4 +21,9 @@ public float[] toRGB(float x, float y, float z) { float b = x * 0.0556434f + y * -0.2040259f + z * 1.0572252f; return new float[]{r,g,b}; } + + @Override + public String toString() { + return "LUV"; + } } diff --git a/src/main/java/com/marginallyclever/donatello/colorspace/RGBColorSpace.java b/src/main/java/com/marginallyclever/donatello/colorspace/RGBColorSpace.java index 096ffe9..8b8eb0a 100644 --- a/src/main/java/com/marginallyclever/donatello/colorspace/RGBColorSpace.java +++ b/src/main/java/com/marginallyclever/donatello/colorspace/RGBColorSpace.java @@ -13,4 +13,9 @@ public float[] fromRGB(float r, float g, float b) { public float[] toRGB(float c1, float c2, float c3) { return new float[]{c1, c2, c3}; } + + @Override + public String toString() { + return "RGB"; + } } From 7e789e6728743248ab8374ef7d6f1555532c218a Mon Sep 17 00:00:00 2001 From: Dan Royer Date: Mon, 24 Feb 2025 15:19:54 -0800 Subject: [PATCH 4/4] removed unused tangents --- .../marginallyclever/donatello/curveeditor/CurveEditor.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/main/java/com/marginallyclever/donatello/curveeditor/CurveEditor.java b/src/main/java/com/marginallyclever/donatello/curveeditor/CurveEditor.java index 903d916..5929d98 100644 --- a/src/main/java/com/marginallyclever/donatello/curveeditor/CurveEditor.java +++ b/src/main/java/com/marginallyclever/donatello/curveeditor/CurveEditor.java @@ -18,13 +18,10 @@ public class CurveEditor extends JPanel { private static class ControlPoint { Point2d position; - Point2d tangentIn; - Point2d tangentOut; + // TODO add bezier curve control points public ControlPoint(Point2d position) { this.position = position; - this.tangentIn = new Point2d(); - this.tangentOut = new Point2d(); } }