pub trait ColorTrait {
fn rgba(&self) -> (u32, u32, u32, u32); }
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum Color {
RGBA(RGBA),
NRGBA(NRGBA),
RGBA64(RGBA64),
NRGBA64(NRGBA64),
Gray(Gray),
Gray16(Gray16),
Alpha(Alpha),
Alpha16(Alpha16),
}
impl Color {
pub const fn new_gray(y: u8) -> Self {
Color::Gray(Gray::new(y))
}
pub const fn new_rgba(r: u8, g: u8, b: u8, a: u8) -> Self {
Color::RGBA(RGBA::new(r, g, b, a))
}
pub const fn new_rgba64(r: u16, g: u16, b: u16, a: u16) -> Self {
Color::RGBA64(RGBA64::new(r, g, b, a))
}
pub const fn new_nrgba(r: u8, g: u8, b: u8, a: u8) -> Self {
Color::NRGBA(NRGBA::new(r, g, b, a))
}
pub const fn new_nrgba64(r: u16, g: u16, b: u16, a: u16) -> Self {
Color::NRGBA64(NRGBA64::new(r, g, b, a))
}
pub fn to_gray16(&self) -> Gray16 {
match self {
Color::Gray16(c) => *c,
_ => Gray16::new_from(self),
}
}
pub fn to_nrgba(&self) -> NRGBA {
match self {
Color::NRGBA(c) => *c,
_ => NRGBA::new_from(self),
}
}
pub fn to_nrgba64(&self) -> NRGBA64 {
match self {
Color::NRGBA64(c) => *c,
_ => NRGBA64::new_from(self),
}
}
}
impl ColorTrait for Color {
fn rgba(&self) -> (u32, u32, u32, u32) {
match self {
Color::RGBA(c) => c.rgba(),
Color::NRGBA(c) => c.rgba(),
Color::Gray(c) => c.rgba(),
Color::Gray16(c) => c.rgba(),
Color::RGBA64(c) => c.rgba(),
Color::NRGBA64(c) => c.rgba(),
Color::Alpha(c) => c.rgba(),
Color::Alpha16(c) => c.rgba(),
}
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct RGBA {
pub r: u8,
pub g: u8,
pub b: u8,
pub a: u8,
}
impl RGBA {
pub const fn new(r: u8, g: u8, b: u8, a: u8) -> Self {
Self { r, g, b, a }
}
pub fn new_from(c: &Color) -> Self {
if let Color::RGBA(c) = c {
*c
} else {
let (r, g, b, a) = c.rgba();
RGBA::new(
(r >> 8) as u8,
(g >> 8) as u8,
(b >> 8) as u8,
(a >> 8) as u8,
)
}
}
}
impl ColorTrait for RGBA {
fn rgba(&self) -> (u32, u32, u32, u32) {
let mut r = self.r as u32;
r |= r << 8;
let mut g = self.g as u32;
g |= g << 8;
let mut b = self.b as u32;
b |= b << 8;
let mut a = self.a as u32;
a |= a << 8;
(r, g, b, a)
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct RGBA64 {
pub r: u16,
pub g: u16,
pub b: u16,
pub a: u16,
}
impl RGBA64 {
pub const fn new(r: u16, g: u16, b: u16, a: u16) -> Self {
Self { r, g, b, a }
}
pub fn new_from(c: &Color) -> Self {
match c {
Color::RGBA64(c) => Self::new(c.r, c.g, c.b, c.a),
_ => {
let (r, g, b, a) = c.rgba();
RGBA64::new(r as u16, g as u16, b as u16, a as u16)
}
}
}
}
impl ColorTrait for RGBA64 {
fn rgba(&self) -> (u32, u32, u32, u32) {
(self.r as u32, self.g as u32, self.b as u32, self.a as u32)
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct NRGBA {
pub r: u8,
pub g: u8,
pub b: u8,
pub a: u8,
}
impl NRGBA {
pub const fn new(r: u8, g: u8, b: u8, a: u8) -> Self {
Self { r, g, b, a }
}
pub fn new_from(c: &Color) -> Self {
match c {
Color::NRGBA(c) => Self::new(c.r, c.g, c.b, c.a),
_ => {
let (r, g, b, a) = c.rgba();
if a == 0xffff {
return Self::new((r >> 8) as u8, (g >> 8) as u8, (b >> 8) as u8, 0xff);
}
if a == 0 {
return Self::new(0, 0, 0, 0);
}
let r = (r * 0xffff) / a;
let g = (g * 0xffff) / a;
let b = (b * 0xffff) / a;
Self::new(
(r >> 8) as u8,
(g >> 8) as u8,
(b >> 8) as u8,
(a >> 8) as u8,
)
}
}
}
}
impl ColorTrait for NRGBA {
fn rgba(&self) -> (u32, u32, u32, u32) {
let mut r = self.r as u32;
r |= r << 8;
r *= self.a as u32;
r /= 0xff;
let mut g = self.g as u32;
g |= g << 8;
g *= self.a as u32;
g /= 0xff;
let mut b = self.b as u32;
b |= b << 8;
b *= self.a as u32;
b /= 0xff;
let mut a = self.a as u32;
a |= a << 8;
(r, g, b, a)
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct NRGBA64 {
pub r: u16,
pub g: u16,
pub b: u16,
pub a: u16,
}
impl NRGBA64 {
pub const fn new(r: u16, g: u16, b: u16, a: u16) -> Self {
Self { r, g, b, a }
}
pub fn new_from(c: &Color) -> Self {
match c {
Color::NRGBA64(c) => Self::new(c.r, c.g, c.b, c.a),
_ => {
let (r, g, b, a) = c.rgba();
if a == 0xffff {
return NRGBA64::new(r as u16, g as u16, b as u16, 0xffff);
}
if a == 0 {
return NRGBA64::new(0, 0, 0, 0);
}
let r = (r * 0xffff) / a;
let g = (g * 0xffff) / a;
let b = (b * 0xffff) / a;
NRGBA64::new(r as u16, g as u16, b as u16, a as u16)
}
}
}
}
impl ColorTrait for NRGBA64 {
fn rgba(&self) -> (u32, u32, u32, u32) {
let mut r = self.r as u32;
r *= self.a as u32;
r /= 0xffff;
let mut g = self.g as u32;
g *= self.a as u32;
g /= 0xffff;
let mut b = self.b as u32;
b *= self.a as u32;
b /= 0xffff;
let a = self.a as u32;
(r, g, b, a)
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Alpha {
pub a: u8,
}
impl Alpha {
pub const fn new(a: u8) -> Self {
Self { a }
}
pub fn new_from(c: &Color) -> Self {
match c {
Color::Alpha(c) => Self::new(c.a),
_ => {
let (_, _, _, a) = c.rgba();
Alpha::new((a >> 8) as u8)
}
}
}
}
impl ColorTrait for Alpha {
fn rgba(&self) -> (u32, u32, u32, u32) {
let mut a = self.a as u32;
a |= a << 8;
(a, a, a, a)
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Alpha16 {
pub a: u16,
}
impl Alpha16 {
pub const fn new(a: u16) -> Self {
Self { a }
}
pub fn new_from(c: &Color) -> Self {
match c {
Color::Alpha16(c) => Self::new(c.a),
_ => {
let (_, _, _, a) = c.rgba();
Alpha16::new(a as u16)
}
}
}
}
impl ColorTrait for Alpha16 {
fn rgba(&self) -> (u32, u32, u32, u32) {
let a = self.a as u32;
(a, a, a, a)
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Gray {
pub y: u8,
}
impl Gray {
pub const fn new(y: u8) -> Self {
Self { y }
}
pub fn new_from(c: &Color) -> Self {
match c {
Color::Gray(c) => Self::new(c.y),
_ => {
let (r, g, b, _) = c.rgba();
let y = (19595 * r + 38470 * g + 7471 * b + (1 << 15)) >> 24;
Gray::new(y as u8)
}
}
}
}
impl ColorTrait for Gray {
fn rgba(&self) -> (u32, u32, u32, u32) {
let mut y = self.y as u32;
y |= y << 8;
(y, y, y, 0xffff)
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Gray16 {
pub y: u16,
}
impl Gray16 {
pub const fn new(y: u16) -> Self {
Self { y }
}
pub fn new_from(c: &Color) -> Self {
match c {
Color::Gray16(c) => Self::new(c.y),
_ => {
let (r, g, b, _) = c.rgba();
let y = (19595 * r + 38470 * g + 7471 * b + (1 << 15)) >> 16;
Gray16::new(y as u16)
}
}
}
}
impl ColorTrait for Gray16 {
fn rgba(&self) -> (u32, u32, u32, u32) {
let y = self.y as u32;
(y, y, y, 0xffff)
}
}
#[derive(Debug, PartialEq)]
pub enum Model {
RGBAModel,
RGBA64Model,
NRGBAModel,
NRGBA64Model,
AlphaModel,
Alpha16Model,
GrayModel,
Gray16Model,
Paletted(Palette),
}
impl Model {
pub fn convert(&self, c: &Color) -> Color {
match self {
Model::RGBAModel => Color::RGBA(RGBA::new_from(c)),
Model::NRGBAModel => Color::NRGBA(NRGBA::new_from(c)),
Model::RGBA64Model => Color::RGBA64(RGBA64::new_from(c)),
Model::NRGBA64Model => Color::NRGBA64(NRGBA64::new_from(c)),
Model::GrayModel => Color::Gray(Gray::new_from(c)),
Model::Gray16Model => Color::Gray16(Gray16::new_from(c)),
Model::AlphaModel => Color::Alpha(Alpha::new_from(c)),
Model::Alpha16Model => Color::Alpha16(Alpha16::new_from(c)),
Model::Paletted(pal) => pal.convert(c),
}
}
pub fn bitdepth(&self) -> usize {
match self {
Model::RGBAModel => 8,
Model::RGBA64Model => 16,
Model::NRGBAModel => 8,
Model::NRGBA64Model => 16,
Model::AlphaModel => 8,
Model::Alpha16Model => 16,
Model::GrayModel => 8,
Model::Gray16Model => 16,
Model::Paletted(pal) => match pal.colors.len() {
0..=2 => 1,
3..=4 => 2,
5..=16 => 4,
_ => 8,
},
}
}
}
#[derive(Debug, PartialEq, Clone)]
pub struct Palette {
pub colors: Vec<Color>,
}
impl Palette {
pub fn new(num_colors: usize) -> Self {
Self {
colors: vec![OPAQUE_BLACK; num_colors],
}
}
pub fn convert(&self, c: &Color) -> Color {
if self.colors.is_empty() {
return Color::new_gray(0);
}
self.colors[self.index(c)]
}
pub fn index(&self, c: &Color) -> usize {
let (cr, cg, cb, ca) = c.rgba();
let (mut ret, mut best_sum) = (0, 0xffffffff);
for (i, v) in self.colors.iter().enumerate() {
let (vr, vg, vb, va) = v.rgba();
let sum = sq_diff(cr, vr) + sq_diff(cg, vg) + sq_diff(cb, vb) + sq_diff(ca, va);
if sum < best_sum {
if sum == 0 {
return i;
}
(ret, best_sum) = (i, sum);
}
}
ret
}
}
pub(super) fn sq_diff(x: u32, y: u32) -> u32 {
let d = x.wrapping_sub(y);
d.wrapping_mul(d) >> 2
}
pub const BLACK: Color = Color::Gray16(Gray16::new(0));
pub const WHITE: Color = Color::Gray16(Gray16::new(0xffff));
pub const TRANSPARENT: Color = Color::Alpha16(Alpha16::new(0));
pub const OPAQUE: Color = Color::Alpha16(Alpha16::new(0xffff));
pub const OPAQUE_BLACK: Color = Color::new_rgba(0x00, 0x00, 0x00, 0xff);