summaryrefslogtreecommitdiff
path: root/tvg/src/colors.rs
diff options
context:
space:
mode:
Diffstat (limited to 'tvg/src/colors.rs')
-rw-r--r--tvg/src/colors.rs517
1 files changed, 0 insertions, 517 deletions
diff --git a/tvg/src/colors.rs b/tvg/src/colors.rs
deleted file mode 100644
index 0dd8831..0000000
--- a/tvg/src/colors.rs
+++ /dev/null
@@ -1,517 +0,0 @@
-use std::io::{self, Read};
-
-use byteorder::{BigEndian, LittleEndian, ReadBytesExt};
-use num_enum::TryFromPrimitive;
-
-use crate::TvgError;
-
-const GAMMA: f32 = 2.2;
-const INVERT_GAMMA: f32 = 1.0 / GAMMA;
-
-/// The color table encodes the palette for this file.
-///
-/// It’s binary content is defined by the `color_encoding` field in the header.
-/// For the three defined color encodings, each will yield a list of
-/// `color_count` RGBA tuples.
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct ColorTable<C: Color> {
- colors: Box<[C]>,
-}
-
-impl<C: Color> ColorTable<C> {
- /// Read in one encoding, and convert it to another. If `encoding` is
- /// [`ColorEncoding::Custom`], then return
- /// [`TvgError::UnsupportedColorEncoding`].
- pub fn read_from_encoding(
- reader: &mut impl Read,
- color_count: u32,
- encoding: ColorEncoding,
- ) -> Result<Self, TvgError> {
- Ok(match encoding {
- ColorEncoding::Rgba8888 => (&ColorTable::<Rgba8888>::read(reader, color_count)?).into(),
- ColorEncoding::Rgb565 => (&ColorTable::<Rgb565>::read(reader, color_count)?).into(),
- ColorEncoding::RgbaF32 => (&ColorTable::<RgbaF32>::read(reader, color_count)?).into(),
- ColorEncoding::Custom => (&ColorTable::<Rgba16>::read(reader, color_count)?).into(),
- })
- }
-
- /// Read in one encoding, and convert it into another. If `encoding` is
- /// [`ColorEncoding::Custom`], then use the given encoding.
- pub fn read_from_encoding_with_custom<Custom: Color>(
- reader: &mut impl Read,
- color_count: u32,
- encoding: ColorEncoding,
- ) -> io::Result<Self> {
- Ok(match encoding {
- ColorEncoding::Rgba8888 => (&ColorTable::<Rgba8888>::read(reader, color_count)?).into(),
- ColorEncoding::Rgb565 => (&ColorTable::<Rgb565>::read(reader, color_count)?).into(),
- ColorEncoding::RgbaF32 => (&ColorTable::<RgbaF32>::read(reader, color_count)?).into(),
- ColorEncoding::Custom => (&ColorTable::<Custom>::read(reader, color_count)?).into(),
- })
- }
-
- /// Parse a color table.
- fn read(reader: &mut impl Read, color_count: u32) -> io::Result<Self> {
- let mut colors = Vec::with_capacity(color_count as usize);
- for _ in 0..color_count {
- colors.push(C::parse_bytes(reader)?);
- }
-
- let colors = colors.into_boxed_slice();
- Ok(Self { colors })
- }
-
- /// Returns the number of colors in the table.
- pub fn len(&self) -> usize {
- self.colors.len()
- }
-
- /// Returns `true` if the color table has no colors in it
- pub fn is_empty(&self) -> bool {
- self.colors.is_empty()
- }
-
- /// Returns a reference to a color, or `None` if out-of-bounds.
- pub fn get(&self, index: usize) -> Option<&C> {
- self.colors.get(index)
- }
-
- fn iter(&self) -> impl Iterator<Item = &C> {
- self.colors.iter()
- }
-}
-
-impl ColorTable<Rgba16> {}
-
-impl<Old: Color, New: Color> From<&ColorTable<Old>> for ColorTable<New> {
- fn from(value: &ColorTable<Old>) -> Self {
- let mut colors = Vec::with_capacity(value.len());
-
- for color in value.iter() {
- let r = color.red_u16();
- let g = color.green_u16();
- let b = color.blue_u16();
- let a = color.alpha_u16();
- colors.push(New::from_rgba16_lossy(r, g, b, a));
- }
-
- let colors = colors.into_boxed_slice();
- Self { colors }
- }
-}
-
-/// The color encoding defines which format the colors in the color table will
-/// have.
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, TryFromPrimitive)]
-#[repr(u8)]
-pub enum ColorEncoding {
- /// Each color is a 4-tuple (red, green, blue, alpha) of bytes with the
- /// color channels encoded in sRGB and the alpha as linear alpha.
- Rgba8888 = 0,
- /// Each color is encoded as a 3-tuple (red, green, blue) with 16 bits per
- /// color.
- ///
- /// While red and blue both use 5 bits, the green channel uses 6 bits. Red
- /// uses bit range 0...4, green bits 5...10 and blue bits 11...15. This
- /// color also uses the sRGB color space.
- Rgb565 = 1,
- /// Each color is a 4-tuple (red, green, blue, alpha) of binary32 IEEE 754
- /// floating point value with the color channels encoded in scRGB and the
- /// alpha as linear alpha. A color value of 1.0 is full intensity, while a
- /// value of 0.0 is zero intensity.
- RgbaF32 = 2,
- /// The custom color encoding is defined *undefined*. The information how
- /// these colors are encoded must be implemented via external means.
- Custom = 3,
-}
-
-pub trait Color: Sized {
- /// The size of the color's representation in bits
- const SIZE: usize;
-
- /// Attempt to read the color. Returns `Err` if an error occurred while
- /// attempting to read [`SIZE`] bytes from `bytes`.
- fn parse_bytes(reader: &mut impl Read) -> io::Result<Self>;
-
- /// Convert from the RGBA16 format to this format. This may be lossy.
- fn from_rgba16_lossy(red: u16, green: u16, blue: u16, alpha: u16) -> Self;
-
- /// Convert from the RGBAF32 format to this format. This may be lossy.
- fn from_rgbaf32_lossy(red: f32, green: f32, blue: f32, alpha: f32) -> Self;
-
- fn red_u16(&self) -> u16;
- fn blue_u16(&self) -> u16;
- fn green_u16(&self) -> u16;
- fn alpha_u16(&self) -> u16;
-
- fn red_f32(&self) -> f32;
- fn green_f32(&self) -> f32;
- fn blue_f32(&self) -> f32;
- fn alpha_f32(&self) -> f32;
-}
-
-fn to_color_space(val: f32) -> f32 {
- val.powf(INVERT_GAMMA)
-}
-
-fn to_linear(val: f32) -> f32 {
- val.powf(GAMMA)
-}
-
-pub(crate) fn blend<C: Color + Clone>(dest: &mut C, src: &C) {
- fn lerp_color(src: f32, dst: f32, src_alpha: f32, dst_alpha: f32, alpha: f32) -> f32 {
- let src = to_linear(src);
- let dst = to_linear(dst);
-
- let val = (1.0 / alpha) * (src_alpha * src + (1.0 - src_alpha) * dst_alpha * dst);
-
- to_color_space(val)
- }
-
- if src.alpha_f32() == 1.0 || dest.alpha_u16() == 0 {
- *dest = src.clone();
- return;
- } else if src.alpha_u16() == 0 {
- return;
- }
-
- let src_a = src.alpha_f32();
- let dst_a = dest.alpha_f32();
- let alpha = src_a + (1.0 - src_a) * dst_a;
- let red = lerp_color(src.red_f32(), dest.red_f32(), src_a, dst_a, alpha);
- let green = lerp_color(src.green_f32(), dest.green_f32(), src_a, dst_a, alpha);
- let blue = lerp_color(src.blue_f32(), dest.blue_f32(), src_a, dst_a, alpha);
-
- *dest = C::from_rgbaf32_lossy(red, green, blue, alpha);
-}
-
-pub(crate) fn lerp<C: Color>(first: &C, second: &C, f: f64) -> C {
- fn lerp_color(a: f32, b: f32, f: f64) -> f32 {
- a + (b - a) * f as f32
- }
-
- let f = f.clamp(0.0, 1.0);
-
- let red = to_color_space(lerp_color(first.red_f32(), second.red_f32(), f));
- let green = to_color_space(lerp_color(first.green_f32(), second.green_f32(), f));
- let blue = to_color_space(lerp_color(first.blue_f32(), second.blue_f32(), f));
- let alpha = lerp_color(first.alpha_f32(), second.alpha_f32(), f);
-
- C::from_rgbaf32_lossy(red, green, blue, alpha)
-}
-
-/// Each color value is encoded as a sequence of four bytes.
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub struct Rgba8888 {
- /// Red color channel between 0 and 100% intensity, mapped to byte values 0
- /// to 255.
- red: u8,
- /// Green color channel between 0 and 100% intensity, mapped to byte values
- /// 0 to 255.
- green: u8,
- /// Blue color channel between 0 and 100% intensity, mapped to byte values
- /// 0 to 255.
- blue: u8,
- /// Transparency channel between 0 and 100% transparency, mapped to byte
- /// values 0 to 255.
- alpha: u8,
-}
-
-impl Color for Rgba8888 {
- const SIZE: usize = 4;
-
- fn parse_bytes(reader: &mut impl Read) -> io::Result<Self> {
- Ok(Self {
- red: reader.read_u8()?,
- green: reader.read_u8()?,
- blue: reader.read_u8()?,
- alpha: reader.read_u8()?,
- })
- }
-
- fn from_rgba16_lossy(red: u16, green: u16, blue: u16, alpha: u16) -> Self {
- Self {
- red: (red >> 8) as u8,
- green: (green >> 8) as u8,
- blue: (blue >> 8) as u8,
- alpha: (alpha >> 8) as u8,
- }
- }
-
- fn from_rgbaf32_lossy(red: f32, green: f32, blue: f32, alpha: f32) -> Self {
- Self {
- red: (red * u8::MAX as f32) as u8,
- green: (green * u8::MAX as f32) as u8,
- blue: (blue * u8::MAX as f32) as u8,
- alpha: (alpha * u8::MAX as f32) as u8,
- }
- }
-
- fn red_u16(&self) -> u16 {
- (self.red as u16) << 8
- }
-
- fn green_u16(&self) -> u16 {
- (self.green as u16) << 8
- }
-
- fn blue_u16(&self) -> u16 {
- (self.blue as u16) << 8
- }
-
- fn alpha_u16(&self) -> u16 {
- (self.alpha as u16) << 8
- }
-
- fn red_f32(&self) -> f32 {
- self.red as f32 / u8::MAX as f32
- }
-
- fn green_f32(&self) -> f32 {
- self.green as f32 / u8::MAX as f32
- }
-
- fn blue_f32(&self) -> f32 {
- self.blue as f32 / u8::MAX as f32
- }
-
- fn alpha_f32(&self) -> f32 {
- self.alpha as f32 / u8::MAX as f32
- }
-}
-
-/// Each color value is encoded as a sequence of 2 bytes.
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub struct Rgb565 {
- /// Red color channel between 0 and 100% intensity, mapped to integer
- /// values 0 to 31.
- red: u8,
- /// Green color channel between 0 and 100% intensity, mapped to integer
- /// values 0 to 63.
- green: u8,
- /// Blue color channel between 0 and 100% intensity, mapped to integer
- /// values 0 to 31.
- blue: u8,
-}
-
-impl Color for Rgb565 {
- const SIZE: usize = 2;
-
- fn parse_bytes(reader: &mut impl Read) -> io::Result<Self> {
- let color = reader.read_u16::<LittleEndian>()?;
-
- let red = ((color & 0x001F) << 3) as u8;
- let green = ((color & 0x07E0) >> 3) as u8;
- let blue = ((color & 0xF800) >> 8) as u8;
-
- Ok(Self { red, blue, green })
- }
-
- fn from_rgba16_lossy(red: u16, green: u16, blue: u16, _a: u16) -> Self {
- Self {
- red: (red >> 11) as u8,
- green: (green >> 10) as u8,
- blue: (blue >> 11) as u8,
- }
- }
-
- fn from_rgbaf32_lossy(red: f32, green: f32, blue: f32, alpha: f32) -> Self {
- Self {
- red: (red * (0b011111) as f32) as u8,
- green: (green * (0b111111) as f32) as u8,
- blue: (blue * (0b011111) as f32) as u8,
- }
- }
-
- fn red_u16(&self) -> u16 {
- (self.red as u16) << 11
- }
-
- fn green_u16(&self) -> u16 {
- (self.green as u16) << 11
- }
-
- fn blue_u16(&self) -> u16 {
- (self.blue as u16) << 10
- }
-
- fn alpha_u16(&self) -> u16 {
- 0
- }
-
- fn red_f32(&self) -> f32 {
- self.red as f32 / (0b011111) as f32
- }
-
- fn green_f32(&self) -> f32 {
- self.green as f32 / (0b111111) as f32
- }
-
- fn blue_f32(&self) -> f32 {
- self.blue as f32 / (0b011111) as f32
- }
-
- fn alpha_f32(&self) -> f32 {
- 0.0
- }
-}
-
-/// Each color value is encoded as a sequence of 16 bytes.
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub struct RgbaF32 {
- /// Red color channel, using 0.0 for 0% intensity and 1.0 for 100%
- /// intensity.
- red: f32,
- /// Green color channel, using 0.0 for 0% intensity and 1.0 for 100%
- /// intensity.
- green: f32,
- /// Blue color channel, using 0.0 for 0% intensity and 1.0 for 100%
- /// intensity.
- blue: f32,
- /// Transparency channel between 0 and 100% transparency, mapped to byte
- /// values 0.0 to 1.0.
- alpha: f32,
-}
-
-impl Color for RgbaF32 {
- const SIZE: usize = 16;
-
- fn parse_bytes(reader: &mut impl Read) -> io::Result<Self> {
- Ok(Self {
- red: reader.read_f32::<LittleEndian>()?,
- green: reader.read_f32::<LittleEndian>()?,
- blue: reader.read_f32::<LittleEndian>()?,
- alpha: reader.read_f32::<LittleEndian>()?,
- })
- }
-
- fn from_rgba16_lossy(red: u16, green: u16, blue: u16, alpha: u16) -> Self {
- Self {
- red: (red as f32) / (u16::MAX as f32),
- green: (green as f32) / (u16::MAX as f32),
- blue: (blue as f32) / (u16::MAX as f32),
- alpha: (alpha as f32) / (u16::MAX as f32),
- }
- }
-
- fn from_rgbaf32_lossy(red: f32, green: f32, blue: f32, alpha: f32) -> Self {
- Self {
- red,
- green,
- blue,
- alpha,
- }
- }
-
- fn red_u16(&self) -> u16 {
- (self.red * (u16::MAX as f32)) as u16
- }
-
- fn green_u16(&self) -> u16 {
- (self.green * (u16::MAX as f32)) as u16
- }
-
- fn blue_u16(&self) -> u16 {
- (self.blue * (u16::MAX as f32)) as u16
- }
-
- fn alpha_u16(&self) -> u16 {
- (self.alpha * (u16::MAX as f32)) as u16
- }
-
- fn red_f32(&self) -> f32 {
- self.red
- }
-
- fn green_f32(&self) -> f32 {
- self.green
- }
-
- fn blue_f32(&self) -> f32 {
- self.blue
- }
-
- fn alpha_f32(&self) -> f32 {
- self.alpha
- }
-}
-
-/// Each color value is encoded as a sequence of 8 bytes.
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub struct Rgba16 {
- /// Red color channel between 0 and 100% intensity, mapped to a big-endian
- /// 16-bit integer.
- red: u16,
- /// Green color channel between 0 and 100% intensity, mapped to a
- /// big-endian 16-bit integer.
- green: u16,
- /// Blue color channel between 0 and 100% intensity, mapped to a big-endian
- /// 16-bit integer.
- blue: u16,
- /// Transparency channel between 0 and 100% intensity, mapped to a
- /// big-endian 16-bit integer.
- alpha: u16,
-}
-
-impl Color for Rgba16 {
- const SIZE: usize = 8;
-
- fn parse_bytes(reader: &mut impl Read) -> io::Result<Self> {
- Ok(Self {
- red: reader.read_u16::<BigEndian>()?,
- green: reader.read_u16::<BigEndian>()?,
- blue: reader.read_u16::<BigEndian>()?,
- alpha: reader.read_u16::<BigEndian>()?,
- })
- }
-
- fn from_rgba16_lossy(red: u16, green: u16, blue: u16, alpha: u16) -> Self {
- Self {
- red,
- green,
- blue,
- alpha,
- }
- }
-
- fn from_rgbaf32_lossy(red: f32, green: f32, blue: f32, alpha: f32) -> Self {
- Self {
- red: (red * u16::MAX as f32) as u16,
- green: (green * u16::MAX as f32) as u16,
- blue: (blue * u16::MAX as f32) as u16,
- alpha: (alpha * u16::MAX as f32) as u16,
- }
- }
-
- fn red_u16(&self) -> u16 {
- self.red
- }
-
- fn green_u16(&self) -> u16 {
- self.green
- }
-
- fn blue_u16(&self) -> u16 {
- self.blue
- }
-
- fn alpha_u16(&self) -> u16 {
- self.alpha
- }
-
- fn red_f32(&self) -> f32 {
- self.red as f32 / u16::MAX as f32
- }
-
- fn green_f32(&self) -> f32 {
- self.green as f32 / u16::MAX as f32
- }
-
- fn blue_f32(&self) -> f32 {
- self.blue as f32 / u16::MAX as f32
- }
-
- fn alpha_f32(&self) -> f32 {
- self.alpha as f32 / u16::MAX as f32
- }
-}