diff --git a/src/main/micycle/peasygradients/gradient/Palette.java b/src/main/micycle/peasygradients/gradient/Palette.java index ce5fd22..9206b0c 100644 --- a/src/main/micycle/peasygradients/gradient/Palette.java +++ b/src/main/micycle/peasygradients/gradient/Palette.java @@ -6,11 +6,12 @@ import processing.core.PApplet; /** - * Generates random color palettes to use in gradients. Palettes are generated - * in the HSB color space and output as sRGB integers. + * Provides methods for generating color palettes based on various color harmony + * principles, employing the HSB color space and producing colors as sRGB + * integers. The palettes can be used for creating gradients and other + * color-related visual elements. * * @author Michael Carleton - * */ public final class Palette { @@ -21,63 +22,68 @@ public final class Palette { * https://observablehq.com/@makio135/give-me-colors */ + // Constants defining the minimum saturation, minimum brightness, and their + // respective maximum variances. private static final float sMin = 0.75f; // min saturation private static final float bMin = 0.75f; // min brightness private static final float sVarMax = 0.1f; // max saturation variance private static final float bVarMax = 0.1f; // max brightness variance + private static final float GRC = 0.618033988749895f; // Golden ratio conjugate for hue distribution + /** * https://martin.ankerl.com/2009/12/09/how-to-create-random-colors-programmatically/ */ - private static final float GRC = 0.618033988749895f; // golden ratio conjugate /** - * Generates a palette of two colors that are on opposite sides of the color - * wheel. + * Generates a complementary color palette consisting of two colors that are + * diametrically opposite on the color wheel. * - * @return + * @return An array of two colors, represented as ARGB integers. */ public static int[] complementary() { return generic(2, 1 / 2f); } /** - * Generates a palette of three colors that are evenly spaced on the color - * wheel. + * Generates a triadic color palette consisting of three colors that are evenly + * spaced around the color wheel, creating a harmonious and balanced color + * scheme. * - * @return + * @return An array of three colors, represented as ARGB integers. */ public static int[] triadic() { return generic(3, 1 / 3f); } /** - * Generates a palette of four colors that are evenly spaced on the color wheel. + * Generates a tetradic color palette consisting of four colors that are evenly + * spaced around the color wheel, offering a diverse range of hues. * - * @return + * @return An array of four colors, represented as ARGB integers. */ public static int[] tetradic() { return generic(4, 1 / 4f); } /** - * Generate a color palette of n random colors. colors are distributed using the - * golden ratio. + * Generates a palette of randomly selected colors using the golden ratio for + * hue distribution, which tends to produce aesthetically pleasing results. * - * @param ncolors number of random colors to generate - * @return array of colors, represented by (Processing-compatible) ARGB integers + * @param ncolors The number of random colors to generate. + * @return An array of colors, represented as ARGB integers. */ public static int[] randomcolors(int ncolors) { return generic(ncolors, GRC); } /** - * Generate a color palette of n random colors. colors are generated completely - * randomly. + * Generates a palette of completely random colors without any constraints on + * hue distribution, saturation, or brightness. * - * @param ncolors - * @return - * @see #randomcolors(int) generates colors with similar saturation and - * brightness + * @param ncolors The number of random colors to generate. + * @return An array of colors, represented as ARGB integers. + * @see #randomcolors(int) For generating colors with similar saturation and + * brightness. */ public static int[] randomRandomcolors(int ncolors) { int[] out = new int[ncolors]; @@ -88,12 +94,13 @@ public static int[] randomRandomcolors(int ncolors) { } /** - * Generate an n-color palette by cycling hue and varying saturation and - * brightness a little. + * Generic method for generating a color palette with specified number of + * colors, incrementally adjusting the hue, and applying slight variations to + * saturation and brightness. * - * @param colors - * @param increment - * @return array of colors, represented by ARGB integers + * @param colors The number of colors to generate in the palette. + * @param increment The hue increment between consecutive colors. + * @return An array of colors, represented as ARGB integers. */ private static int[] generic(int colors, float increment) { int[] out = new int[colors]; diff --git a/src/main/micycle/peasygradients/utilities/ColorUtils.java b/src/main/micycle/peasygradients/utilities/ColorUtils.java index f9e908d..ebbf54a 100644 --- a/src/main/micycle/peasygradients/utilities/ColorUtils.java +++ b/src/main/micycle/peasygradients/utilities/ColorUtils.java @@ -1,11 +1,11 @@ package micycle.peasygradients.utilities; /** - * Contains static functions mostly related to color processing (mostly - * (de)composition). + * Provides static utility methods for color processing, including color + * composition and decomposition, as well as linear interpolation between + * colors. * * @author Michael Carleton - * */ public final class ColorUtils { @@ -16,14 +16,14 @@ private ColorUtils() { private static final float INV_255 = 1f / 255f; // used to normalise RGB values // TODO use double? /** - * Linearly interpolate between 2 colors (color-space independent) using the - * given step. + * Linearly interpolates between two colors represented as double arrays. * - * @param a double[3] (col 1) - * @param b double[3] (col 2) - * @param step - * @param out double[] - * @return + * @param a The first color as a double array [R,G,B]. + * @param b The second color as a double array [R,G,B]. + * @param step The interpolation factor, where 0.0 is the start color and 1.0 is + * the end color. + * @param out The array to store the interpolated color [R,G,B]. + * @return The interpolated color as a double array. */ public static double[] interpolateLinear(double[] a, double[] b, float step, double[] out) { out[0] = a[0] + step * (b[0] - a[0]); @@ -33,16 +33,16 @@ public static double[] interpolateLinear(double[] a, double[] b, float step, dou } /** - * Returns a color by interpolating between two given colors. An alternative to - * Processing's native lerpcolor() method (which is linear). + * Linearly interpolates between two colors with alpha values. * - * @param col1 First color, represented as [R,G,B,A] array; each value between - * 0...1. - * @param col2 Second color, represented as [R,G,B,A] array; each value between - * 0...1. - * @param st step: percentage between the two colors. - * @param out The new interpolated color, represented by a [R,G,B,A] array. - * @return + * @param col1 The first color as a float array [R,G,B,A] with each component in + * the range 0...1. + * @param col2 The second color as a float array [R,G,B,A] with each component + * in the range 0...1. + * @param step The interpolation factor, where 0.0 is the start color and 1.0 is + * the end color. + * @param out The array to store the interpolated color [R,G,B,A]. + * @return The interpolated color as a float array. */ public static float[] interpolateLinear(float[] col1, float[] col2, float step, float[] out) { out[0] = col1[0] + step * (col2[0] - col1[0]); @@ -53,82 +53,88 @@ public static float[] interpolateLinear(float[] col1, float[] col2, float step, } /** - * Compose a 32 bit sARGB int from float[] 0...1 + * Composes a 32-bit ARGB color from RGBA components represented as a float + * array. * - * @param RGBA - * @return + * @param RGBA The RGBA components as a float array [R,G,B,A] with each value in + * the range 0...1. + * @return The composed ARGB color as an integer. */ public static int composeclr(float[] RGBA) { return (int) (RGBA[3] * 255) << 24 | (int) (RGBA[0] * 255) << 16 | (int) (RGBA[1] * 255) << 8 | (int) (RGBA[2] * 255); } /** - * Compose a 32 bit sARGB int from float[] 0...255 + * Composes a 32-bit ARGB color from RGBA components represented as a float + * array. * - * @param RGBA - * @return + * @param RGBA The RGBA components as a float array [R,G,B,A] with each value in + * the range 0...255. + * @return The composed ARGB color as an integer. */ public static int composeclr255(float[] RGBA) { return (int) (RGBA[3]) << 24 | (int) (RGBA[0]) << 16 | (int) (RGBA[1]) << 8 | (int) (RGBA[2]); } /** - * Compose an RGBA color using a float[] of values in range 0...1 + * Composes a 32-bit ARGB color from individual RGBA components. * - * @param red - * @param green - * @param blue - * @param alpha - * @return integer representation of RGBA + * @param red The red component in the range 0...1. + * @param green The green component in the range 0...1. + * @param blue The blue component in the range 0...1. + * @param alpha The alpha component in the range 0...1. + * @return The composed ARGB color as an integer. */ public static int composeclr(float red, float green, float blue, float alpha) { return (int) (alpha * 255) << 24 | (int) (red * 255) << 16 | (int) (green * 255) << 8 | (int) (blue * 255); } - public static int composeclr(float red, float green, float blue) { + /** + * Composes a 32-bit ARGB color from individual RGB components, defaulting to + * full opacity. + * + * @param red The red component as a float. + * @param green The green component as a float. + * @param blue The blue component as a float. + * @return The composed ARGB color as an integer. + */ + public static int composeclr255(float red, float green, float blue) { return 255 << 24 | (int) red << 16 | (int) green << 8 | (int) blue; } /** - * sRGB (0...1) in. Assumes full alpha. + * Composes a 32-bit ARGB color from RGB components represented as a double + * array. Assumes full opacity. * - * @param in - * @return + * @param in The RGB components as a double array [R,G,B] with each value in the + * range 0...1. + * @return The composed ARGB color as an integer. */ public static int composeclr(double[] in) { return OPAQUE | (int) (in[0] * 255 + 0.5) << 16 | (int) (in[1] * 255 + 0.5) << 8 | (int) (in[2] * 255 + 0.5); } /** + * Composes a 32-bit ARGB color from RGB components represented as a double + * array and an alpha component as an integer. * - * @param in double[3] each is 0...1 - * @param alpha 0...255 - * @return + * @param in The RGB components as a double array [R,G,B] with each value in + * the range 0...1. + * @param alpha The alpha component as an integer in the range 0...255. + * @return The composed ARGB color as an integer. */ public static int composeclr(double[] in, int alpha) { return alpha << 24 | (int) (in[0] * 255 + 0.5) << 16 | (int) (in[1] * 255 + 0.5) << 8 | (int) (in[2] * 255 + 0.5); } /** - * Floor of 0. - * - * @param in - * @param alpha - * @return integer representation of RGBA - */ - public static int composeclrFloor(double[] in, int alpha) { - return alpha << 24 | Math.max((int) (in[0] * 255 + 0.5), 0) << 16 | Math.max((int) (in[1] * 255 + 0.5), 0) << 8 - | Math.max((int) (in[2] * 255 + 0.5), 0); - } - - /** - * Compose an ARGB color from a double input, clamping the output of each - * channel between 0 and 255. + * Composes a 32-bit ARGB color from RGB components represented as a double + * array, clamping each channel output between 0 and 255. * - * @param in [r,g,b] where each channel's range is 0...1 (but may slightly - * over/underflow). - * @param alpha 0...2555 - * @return + * @param in The RGB components as a double array [R,G,B] with possible + * over/underflow. + * @param alpha The alpha component as an integer in the range 0...255. + * @return The composed ARGB color as an integer. */ public static int composeclrClamp(double[] in, int alpha) { // https://stackoverflow.com/a/70420549/9808792 @@ -148,17 +154,26 @@ private static int composeclrClampSimple(double[] in, int alpha) { return alpha << 24 | r << 16 | g << 8 | b; } + /** + * Converts RGB components from a double array to an integer array with values + * scaled to range 0...255. + * + * @param in The RGB components as a double array [R,G,B] with each value in the + * range 0...1. + * @return The RGB components as an integer array [R,G,B] scaled to range + * 0...255. + */ public static int[] composeclrTo255(double[] in) { return new int[] { (int) Math.round(in[0] * 255), (int) Math.round(in[1] * 255), (int) Math.round(in[2] * 255) }; } /** - * Decompose color integer (ARGB) into 4 separate components and scale between - * 0...1 + * Decomposes a 32-bit ARGB color into its components and scales them to range + * 0...1. * - * @param clr - * @param out - * @return [R,G,B,A] 0...1 + * @param clr The ARGB color as an integer. + * @return The color components as a float array [R,G,B,A] scaled to range + * 0...1. */ public static float[] decomposeclr(int clr) { // 1.0 / 255.0 = 0.003921569 @@ -167,11 +182,12 @@ public static float[] decomposeclr(int clr) { } /** - * Decompose color integer (ARGB) into 4 separate components (0...255) + * Decomposes a 32-bit ARGB color into its components with values in the range + * 0...255. * - * @param clr - * @param out - * @return [R,G,B,A] 0...255 + * @param clr The ARGB color as an integer. + * @return The color components as a float array [R,G,B,A] with values in the + * range 0...255. */ public static float[] decomposeclrRGB(int clr) { float[] out = new float[4]; @@ -183,10 +199,12 @@ public static float[] decomposeclrRGB(int clr) { } /** - * out 255 + * Decomposes a 32-bit RGB color into its components, returning them as a double + * array. * - * @param clr - * @return + * @param clr The RGB color as an integer. + * @return The color components as a double array [R,G,B] with values in the + * range 0...255. */ public static double[] decomposeclrRGBDouble(int clr) { double[] out = new double[3]; @@ -196,6 +214,15 @@ public static double[] decomposeclrRGBDouble(int clr) { return out; } + /** + * Decomposes a 32-bit RGB color into its components, including an alpha value + * as an additional parameter. + * + * @param clr The RGB color as an integer. + * @param alpha The alpha component as an integer in the range 0...255. + * @return The color components as a double array [R,G,B,A] with RGB values in + * the range 0...255 and the given alpha. + */ public static double[] decomposeclrRGBDouble(int clr, int alpha) { double[] out = new double[4]; out[0] = (clr >> 16 & 0xff); @@ -206,10 +233,12 @@ public static double[] decomposeclrRGBDouble(int clr, int alpha) { } /** - * Unpack a 32-Bit ARGB int, normalising to 0..1 + * Decomposes a 32-bit ARGB color into its components and normalizes them to + * range 0...1. * - * @param clr - * @return sRGB representing the argb color + * @param clr The ARGB color as an integer. + * @return The color components as a float array [R,G,B,A] normalized to range + * 0...1. */ public static float[] decomposeclrRGBA(int clr) { float[] out = new float[4]; @@ -221,10 +250,12 @@ public static float[] decomposeclrRGBA(int clr) { } /** - * out 0...1 + * Decomposes a 32-bit RGB color into its components and normalizes them to + * range 0...1. * - * @param clr RGB [0, 255] - * @return + * @param clr The RGB color as an integer. + * @return The color components as a double array [R,G,B] normalized to range + * 0...1. */ public static double[] decomposeclrDouble(int clr) { double[] out = new double[3]; diff --git a/src/test/micycle/peasygradients/colorspace/GradientTests.java b/src/test/micycle/peasygradients/colorspace/GradientTests.java index c17d9b0..a6bc7a0 100644 --- a/src/test/micycle/peasygradients/colorspace/GradientTests.java +++ b/src/test/micycle/peasygradients/colorspace/GradientTests.java @@ -13,9 +13,9 @@ class GradientTests { - private static final int WHITE = ColorUtils.composeclr(255, 255, 255); - private static final int GREY = ColorUtils.composeclr(128, 128, 128); - private static final int BLACK = ColorUtils.composeclr(0, 0, 0); + private static final int WHITE = ColorUtils.composeclr255(255, 255, 255); + private static final int GREY = ColorUtils.composeclr255(128, 128, 128); + private static final int BLACK = ColorUtils.composeclr255(0, 0, 0); @Test void testMidPoint() { diff --git a/src/test/micycle/peasygradients/colorspace/PeasyGradientsTests.java b/src/test/micycle/peasygradients/colorspace/PeasyGradientsTests.java index e1d0c13..bb488e9 100644 --- a/src/test/micycle/peasygradients/colorspace/PeasyGradientsTests.java +++ b/src/test/micycle/peasygradients/colorspace/PeasyGradientsTests.java @@ -15,9 +15,9 @@ */ class PeasyGradientsTests { - private static final int WHITE = ColorUtils.composeclr(255, 255, 255); - private static final int GREY = ColorUtils.composeclr(128, 128, 128); - private static final int BLACK = ColorUtils.composeclr(0, 0, 0); + private static final int WHITE = ColorUtils.composeclr255(255, 255, 255); + private static final int GREY = ColorUtils.composeclr255(128, 128, 128); + private static final int BLACK = ColorUtils.composeclr255(0, 0, 0); @Test void testLinearGradient() {