-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add Color struct * Update u16 unpacking to hardware equivalent
- Loading branch information
Showing
3 changed files
with
203 additions
and
33 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
/// RGBA color type where values are 8-bit integers (0-255). | ||
/// | ||
/// This is not to be used as a generic color type, only for specific pigment interfaces. | ||
#[repr(C)] | ||
#[derive(Copy, Clone, Debug, PartialEq)] | ||
pub struct Color { | ||
pub r: u8, | ||
pub g: u8, | ||
pub b: u8, | ||
pub a: u8, | ||
} | ||
|
||
impl Color { | ||
#[rustfmt::skip] | ||
pub const TRANSPARENT: Color = Color { r: 0, g: 0, b: 0, a: 0 }; | ||
#[rustfmt::skip] | ||
pub const BLACK: Color = Color { r: 0, g: 0, b: 0, a: 255 }; | ||
#[rustfmt::skip] | ||
pub const WHITE: Color = Color { r: 255, g: 255, b: 255, a: 255 }; | ||
|
||
/// Creates a new color with the given RGBA values. | ||
#[inline] | ||
#[allow(non_snake_case)] | ||
pub const fn RGBA(r: u8, g: u8, b: u8, a: u8) -> Color { | ||
Color { r, g, b, a } | ||
} | ||
|
||
/// Creates a new color with the given RGB values and an alpha value of 255. | ||
#[inline] | ||
#[allow(non_snake_case)] | ||
pub const fn RGB(r: u8, g: u8, b: u8) -> Color { | ||
Color { r, g, b, a: 0xFF } | ||
} | ||
|
||
/// Converts a 16-bit RGBA pixel to a 32-bit RGBA color. | ||
#[inline] | ||
pub fn from_u16(pixel: u16) -> Color { | ||
let r = ((pixel >> 11) & 0x1F) as u8; | ||
let g = ((pixel >> 6) & 0x1F) as u8; | ||
let b = ((pixel >> 1) & 0x1F) as u8; | ||
let a = (pixel & 0x01) as u8; | ||
|
||
let r = (r << 3) | (r >> 2); | ||
let g = (g << 3) | (g >> 2); | ||
let b = (b << 3) | (b >> 2); | ||
let a = 255 * a; | ||
|
||
Color { r, g, b, a } | ||
} | ||
|
||
/// Converts a 32-bit RGBA color to a 16-bit RGBA pixel. | ||
#[inline] | ||
pub fn to_u16(&self) -> u16 { | ||
let r = (self.r / 8) as u16; | ||
let g = (self.g / 8) as u16; | ||
let b = (self.b / 8) as u16; | ||
let a = (self.a / 255) as u16; | ||
|
||
(r << 11) | (g << 6) | (b << 1) | a | ||
} | ||
|
||
/// Converts a 32-bit RGBA color to a 16-bit RGBA pixel and | ||
/// returns the two 8-bit components. | ||
#[inline] | ||
pub fn rgba16(self) -> (u8, u8) { | ||
let pixel = self.to_u16(); | ||
((pixel >> 8) as u8, (pixel & 0xFF) as u8) | ||
} | ||
|
||
/// Converts the rgb components to a single intensity value. | ||
/// This is used for grayscale images. | ||
#[inline] | ||
pub fn rgb_to_intensity(&self) -> u8 { | ||
(self.r as f32 * 0.2126 + self.g as f32 * 0.7152 + 0.0722 * self.b as f32) as u8 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
use pigment::color::Color; | ||
|
||
#[test] | ||
fn test_color_new() { | ||
// Test case 1: Color with alpha component | ||
let color = Color::RGBA(255, 128, 64, 255); | ||
assert_eq!(color.r, 255); | ||
assert_eq!(color.g, 128); | ||
assert_eq!(color.b, 64); | ||
assert_eq!(color.a, 255); | ||
|
||
// Test case 2: Color without alpha component | ||
let color = Color::RGB(255, 128, 64); | ||
assert_eq!(color.r, 255); | ||
assert_eq!(color.g, 128); | ||
assert_eq!(color.b, 64); | ||
assert_eq!(color.a, 255); | ||
} | ||
|
||
#[test] | ||
fn test_color_from_u16() { | ||
// Test case 1: Pixel value with maximum component values | ||
let pixel: u16 = 0xFFFF; // Binary: 1111111111111111 | ||
let color = Color::WHITE; | ||
assert_eq!(Color::from_u16(pixel), color); | ||
|
||
// Test case 2: Pixel value with minimum component values | ||
let pixel: u16 = 0x0000; // Binary: 0000000000000000 | ||
let color = Color::TRANSPARENT; | ||
assert_eq!(Color::from_u16(pixel), color); | ||
|
||
// Test case 3: Random pixel value | ||
let pixel: u16 = 0b1101010101010101; // Binary: 11010 10101 01010 101 | ||
let color = Color::RGBA(214, 173, 82, 255); | ||
assert_eq!(Color::from_u16(pixel), color); | ||
} | ||
|
||
#[test] | ||
fn test_color_to_u16() { | ||
// Test case 1: Pixel value with maximum component values | ||
let color = Color::WHITE; | ||
let pixel = color.to_u16(); | ||
assert_eq!(pixel, 0xFFFF); | ||
|
||
// Test case 2: Pixel value with minimum component values | ||
let color = Color::BLACK; | ||
let pixel = color.to_u16(); | ||
assert_eq!(pixel, 0x0001); | ||
|
||
// Test case 3: Random pixel value | ||
let color = Color::RGBA(213, 172, 82, 255); | ||
let pixel = color.to_u16(); | ||
assert_eq!(pixel, 0b1101010101010101); | ||
} | ||
|
||
#[test] | ||
fn test_color_rba16() { | ||
// Test case 1: Color value with maximum component values | ||
let color = Color::WHITE; | ||
let pixel = color.rgba16(); | ||
assert_eq!(pixel, (0xFF, 0xFF)); | ||
|
||
// Test case 2: Color value with minimum component values | ||
let color = Color::BLACK; | ||
let pixel = color.rgba16(); | ||
assert_eq!(pixel, (0, 1)); | ||
|
||
// Test case 3: Random color values | ||
let color = Color::RGBA(120, 200, 50, 150); | ||
let pixel = color.rgba16(); | ||
assert_eq!(pixel, (126, 76)); | ||
} | ||
|
||
#[test] | ||
fn test_color_rgb_to_intensity() { | ||
// Test case 1: Pixel value with maximum component values | ||
let color = Color::WHITE; | ||
let intensity = color.rgb_to_intensity(); | ||
assert_eq!(intensity, 255); | ||
|
||
// Test case 2: Pixel value with minimum component values | ||
let color = Color::BLACK; | ||
let intensity = color.rgb_to_intensity(); | ||
assert_eq!(intensity, 0); | ||
|
||
// Test case 3: RGB values with equal intensity | ||
let color = Color::RGBA(128, 128, 128, 255); | ||
let intensity = color.rgb_to_intensity(); | ||
assert_eq!(intensity, 128); | ||
|
||
// Test case 4: RGB values with different intensities | ||
let color = Color::RGBA(255, 128, 64, 255); | ||
let intensity = color.rgb_to_intensity(); | ||
assert_eq!(intensity, 150); | ||
} |