diff --git a/java-numbers-2/src/main/java/com/baeldung/rbg/Rgb.java b/java-numbers-2/src/main/java/com/baeldung/rbg/Rgb.java new file mode 100644 index 0000000000..536dbdd2eb --- /dev/null +++ b/java-numbers-2/src/main/java/com/baeldung/rbg/Rgb.java @@ -0,0 +1,46 @@ +package com.baeldung.rbg; + +import java.util.Objects; + +public class Rgb { + private int alpha; + private int red; + private int green; + private int blue; + + public Rgb(int alpha, int red, int green, int blue) { + this.alpha = alpha; + this.red = red; + this.green = green; + this.blue = blue; + } + + public int getAlpha() { + return alpha; + } + + public int getRed() { + return red; + } + + public int getGreen() { + return green; + } + + public int getBlue() { + return blue; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Rgb rgb = (Rgb) o; + return alpha == rgb.alpha && red == rgb.red && green == rgb.green && blue == rgb.blue; + } + + @Override + public int hashCode() { + return Objects.hash(alpha, red, green, blue); + } +} diff --git a/java-numbers-2/src/main/java/com/baeldung/rbg/RgbConversions.java b/java-numbers-2/src/main/java/com/baeldung/rbg/RgbConversions.java new file mode 100644 index 0000000000..fbf7615378 --- /dev/null +++ b/java-numbers-2/src/main/java/com/baeldung/rbg/RgbConversions.java @@ -0,0 +1,31 @@ +package com.baeldung.rbg; + +public class RgbConversions { + + public static int rgbToInt(int alpha, int red, int green, int blue) { + alpha = clamp(alpha, 0, 255); + red = clamp(red, 0, 255); + green = clamp(green, 0, 255); + blue = clamp(blue, 0, 255); + + return (alpha << 24) | (red << 16) | (green << 8) | blue; + } + + public static int rgbToInt(Rgb rgb) { + return rgbToInt(rgb.getAlpha(), rgb.getRed(), rgb.getGreen(), rgb.getBlue()); + } + + public static Rgb intToRgb(int argb) { + int alpha = (argb >> 24) & 0xFF; + int red = (argb >> 16) & 0xFF; + int green = (argb >> 8) & 0xFF; + int blue = argb & 0xFF; + + return new Rgb(alpha, red, green, blue); + } + + private static int clamp(int value, int min, int max) { + return Math.max(min, Math.min(max, value)); + } +} + diff --git a/java-numbers-2/src/test/java/com/baeldung/rgb/RgbConversionUnitTest.java b/java-numbers-2/src/test/java/com/baeldung/rgb/RgbConversionUnitTest.java new file mode 100644 index 0000000000..6a52ab1d22 --- /dev/null +++ b/java-numbers-2/src/test/java/com/baeldung/rgb/RgbConversionUnitTest.java @@ -0,0 +1,118 @@ +package com.baeldung.rgb; + +import com.baeldung.rbg.Rgb; +import com.baeldung.rbg.RgbConversions; +import org.junit.jupiter.api.Test; + +import static org.junit.Assert.assertEquals; + +public class RgbConversionUnitTest { + + @Test + public void whenBasicPackingAndUnpackingRgb_thenReturnInitialComponentsValues() { + int alpha = 255; + int red = 255; + int green = 0; + int blue = 0; + + int rgb = (alpha << 24) | (red << 16) | (green << 8) | blue; + + assertEquals(rgb, 0xFFFF0000); + + int alphaReconstructed = (rgb >> 24) & 0xFF; + int redReconstructed = (rgb >> 16) & 0xFF; + int greenReconstructed = (rgb >> 8) & 0xFF; + int blueReconstructed = rgb & 0xFF; + + assertEquals(alphaReconstructed, alpha); + assertEquals(redReconstructed, red); + assertEquals(greenReconstructed, green); + assertEquals(blueReconstructed, blue); + } + + @Test + public void whenRgbaToIntWithoutClamping_ReturnIntegerRepresentations() { + // Fully opaque red + assertEquals(0xFFFF0000, RgbConversions.rgbToInt(255, 255, 0, 0)); + // Fully transparent blue + assertEquals(0x000000FF, RgbConversions.rgbToInt(0, 0, 0, 255)); + // 50% transparent green + assertEquals(0x8000FF00, RgbConversions.rgbToInt(128, 0, 255, 0)); + } + + @Test + public void whenRgbaToIntWithClamping_ReturnIntegerRepresentations() { + // Clamping for values below 0 + assertEquals(0x00000000, RgbConversions.rgbToInt(-1, -1, -1, -1)); + // Clamping for values above 255 + assertEquals(0xFFFFFFFF, RgbConversions.rgbToInt(256, 256, 256, 256)); + } + + @Test + public void whenRgbaToIntBoundary_ReturnIntegerRepresentations() { + // Boundary values for each color component including alpha + assertEquals(0xFF000000, RgbConversions.rgbToInt(255, 0, 0, 0)); // Opaque black + assertEquals(0x00FFFFFF, RgbConversions.rgbToInt(0, 255, 255, 255)); // Transparent white + } + + @Test + public void whenRgbaToIntAndIntToRgb_ReturnTheSameValues() { + Rgb rgb = new Rgb(0, 125, 125, 100); + assertEquals(rgb, RgbConversions.intToRgb(RgbConversions.rgbToInt(rgb))); + } + + @Test + public void whenBrightnessAdjustment_ReturnChangedRgbIntegerValue() { + float scale = 0.8f; // darken by 20% + + // initial values + int alpha = 0; + int red = 100; + int green = 255; + int blue = 100; + + + int adjustedRed = (int)(red * scale); + int adjustedGreen = (int)(green * scale); + int adjustedBlue = (int)(blue * scale); + + int newArgb = (alpha << 24) | (adjustedRed << 16) | (adjustedGreen << 8) | adjustedBlue; + + assertEquals(newArgb, 0x50CC50); + } + + @Test + public void whenGrayscaleConversion_ReturnChangedRgbIntegerValue() { + float scale = 0.8f; // darken by 20% + + // initial values + int alpha = 0; + int red = 100; + int green = 255; + int blue = 100; + + int average = (int)(red * 0.299 + green * 0.587 + blue * 0.114); + int grayscaleArgb = (alpha << 24) | (average << 16) | (average << 8) | average; + + assertEquals(grayscaleArgb, 0xBEBEBE); + } + + @Test + public void whenInversion_ReturnChangedRgbIntegerValue() { + float scale = 0.8f; // darken by 20% + + // initial values + int alpha = 0; + int red = 100; + int green = 255; + int blue = 100; + + red = 255 - red; + green = 255 - green; + blue = 255 - blue; + + int invertedArgb = (alpha << 24) | (red << 16) | (green << 8) | blue; + + assertEquals(invertedArgb, 0x9B009B); + } +}