//! Image and color representations. use crate::durandal::err::*; use std::io; /// Creates a RGB8 color from a R5G5B5 format color. pub fn r5g5b5_to_rgb8(rgb: u16) -> Color8 { let r = rgb >> 10 & 0x1f; let g = rgb >> 5 & 0x1f; let b = rgb & 0x1f; Color8::new((r << 3 | r >> 2) as u8, (g << 3 | g >> 2) as u8, (b << 3 | b >> 2) as u8) } /// Creates a RGB16 color from a R5G5B5 format color. pub fn r5g5b5_to_rgb16(rgb: u16) -> Color16 { let r = rgb >> 10 & 0x1f; let g = rgb >> 5 & 0x1f; let b = rgb & 0x1f; Color16::new(r << 11, g << 11, b << 11) } /// Creates a RGB16 color from a RGB8 format color. pub fn rgb8_to_rgb16(r: u8, g: u8, b: u8) -> Color16 { Color16::new(u16::from(r) << 8, u16::from(g) << 8, u16::from(b) << 8) } /// Writes a PPM file from an image. pub fn write_ppm(out: &mut impl io::Write, im: &impl Image) -> ResultS<()> { write!(out, "P3\n{} {}\n{}\n", im.w(), im.h(), u16::max_value())?; for y in 0..im.h() { for x in 0..im.w() { let cr = im.index(x, y); write!(out, "{} {} {} ", cr.r(), cr.g(), cr.b())?; } out.write_all(b"\n")?; } Ok(()) } /// Writes a TGA file from an image. pub fn write_tga(out: &mut impl io::Write, im: &impl Image) -> ResultS<()> { out.write_all(&[0, 0, 2])?; // id len, color map type, image type out.write_all(&[0, 0, 0, 0, 0])?; // color map spec out.write_all(&[0, 0])?; // x origin out.write_all(&[0, 0])?; // y origin out.write_all(&(im.w() as u16).to_le_bytes())?; // width out.write_all(&(im.h() as u16).to_le_bytes())?; // height out.write_all(&[32, 0])?; // depth, descriptor for y in (0..im.h()).rev() { for x in 0..im.w() { let cr = im.index(x, y); out.write_all(&[(cr.b() >> 8) as u8, (cr.g() >> 8) as u8, (cr.r() >> 8) as u8, (cr.a() >> 8) as u8])?; } } Ok(()) } pub trait Image { type Output: Color; fn w(&self) -> usize; fn h(&self) -> usize; fn index(&self, x: usize, y: usize) -> &Self::Output; fn get(&self, x: usize, y: usize) -> Option<&Self::Output> { if x < self.w() && y < self.h() { Some(&self.index(x, y)) } else { None } } } pub trait Color { fn r(&self) -> u16; fn g(&self) -> u16; fn b(&self) -> u16; fn a(&self) -> u16; } impl Image16 { /// Creates a new Image16. pub fn new(w: usize, h: usize) -> Image16 { Image16{w, h, cr: Vec::with_capacity(w * h)} } } impl Image for Image16 { type Output = Color16; fn w(&self) -> usize {self.w} fn h(&self) -> usize {self.h} fn index(&self, x: usize, y: usize) -> &Self::Output { &self.cr[x + y * self.w] } } impl Image8 { /// Creates a new Image8. pub fn new(w: usize, h: usize) -> Image8 { Image8{w, h, cr: Vec::with_capacity(w * h)} } } impl Image for Image8 { type Output = Color8; fn w(&self) -> usize {self.w} fn h(&self) -> usize {self.h} fn index(&self, x: usize, y: usize) -> &Self::Output { &self.cr[x + y * self.w] } } impl Color16 { pub const fn new(r: u16, g: u16, b: u16) -> Color16 { Color16(r, g, b) } } impl Color for Color16 { fn r(&self) -> u16 {self.0} fn g(&self) -> u16 {self.1} fn b(&self) -> u16 {self.2} fn a(&self) -> u16 {u16::max_value()} } impl Color8 { pub const fn new(r: u8, g: u8, b: u8) -> Color8 { Color8(r, g, b) } } impl Color for Color8 { fn r(&self) -> u16 {u16::from(self.0) << 8} fn g(&self) -> u16 {u16::from(self.1) << 8} fn b(&self) -> u16 {u16::from(self.2) << 8} fn a(&self) -> u16 {u16::max_value()} } /// A RGB16 color. #[derive(Clone, Debug, PartialEq)] pub struct Color16(u16, u16, u16); /// A RGB8 color. #[derive(Clone, Debug, PartialEq)] pub struct Color8(u8, u8, u8); /// RGB16 image. pub struct Image16 { w: usize, h: usize, pub cr: Vec, } /// RGB16 image. pub struct Image8 { w: usize, h: usize, pub cr: Vec, } // EOF