2018-09-06 09:01:52 -07:00
|
|
|
//! Image and color representations.
|
|
|
|
|
2019-02-11 03:28:53 -08:00
|
|
|
use crate::durandal::err::*;
|
2019-02-09 11:04:27 -08:00
|
|
|
use std::io;
|
2018-09-06 09:01:52 -07:00
|
|
|
|
2019-02-09 11:04:27 -08:00
|
|
|
/// Creates a RGB8 color from a R5G5B5 format color.
|
|
|
|
pub fn r5g5b5_to_rgb8(rgb: u16) -> Color8
|
2018-09-06 09:01:52 -07:00
|
|
|
{
|
2019-02-09 11:04:27 -08:00
|
|
|
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)
|
2018-09-06 09:01:52 -07:00
|
|
|
}
|
|
|
|
|
2019-02-09 11:04:27 -08:00
|
|
|
/// Creates a RGB16 color from a R5G5B5 format color.
|
|
|
|
pub fn r5g5b5_to_rgb16(rgb: u16) -> Color16
|
2018-09-06 09:01:52 -07:00
|
|
|
{
|
2019-02-09 11:04:27 -08:00
|
|
|
let r = rgb >> 10 & 0x1f;
|
|
|
|
let g = rgb >> 5 & 0x1f;
|
|
|
|
let b = rgb & 0x1f;
|
2019-02-09 21:52:51 -08:00
|
|
|
Color16::new(r << 11, g << 11, b << 11)
|
2018-09-06 09:01:52 -07:00
|
|
|
}
|
|
|
|
|
2019-02-09 11:04:27 -08:00
|
|
|
/// Creates a RGB16 color from a RGB8 format color.
|
|
|
|
pub fn rgb8_to_rgb16(r: u8, g: u8, b: u8) -> Color16
|
2018-09-06 09:01:52 -07:00
|
|
|
{
|
2019-02-13 21:19:36 -08:00
|
|
|
Color16::new(u16::from(r) << 8, u16::from(g) << 8, u16::from(b) << 8)
|
2019-02-09 11:04:27 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Writes a PPM file from an image.
|
2019-02-11 05:44:20 -08:00
|
|
|
pub fn write_ppm(out: &mut impl io::Write, im: &impl Image) -> ResultS<()>
|
2019-02-09 11:04:27 -08:00
|
|
|
{
|
2019-02-11 03:28:53 -08:00
|
|
|
write!(out, "P3\n{} {}\n{}\n", im.w(), im.h(), u16::max_value())?;
|
2019-02-09 11:04:27 -08:00
|
|
|
|
|
|
|
for y in 0..im.h() {
|
|
|
|
for x in 0..im.w() {
|
2019-02-11 05:44:20 -08:00
|
|
|
let cr = im.index(x, y);
|
2019-02-09 11:04:27 -08:00
|
|
|
write!(out, "{} {} {} ", cr.r(), cr.g(), cr.b())?;
|
|
|
|
}
|
2019-02-11 03:28:53 -08:00
|
|
|
|
2019-02-13 21:19:36 -08:00
|
|
|
out.write_all(b"\n")?;
|
2018-09-06 09:01:52 -07:00
|
|
|
}
|
2019-02-09 11:04:27 -08:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2019-02-11 07:33:10 -08:00
|
|
|
/// Writes a TGA file from an image.
|
|
|
|
pub fn write_tga(out: &mut impl io::Write, im: &impl Image) -> ResultS<()>
|
|
|
|
{
|
2019-02-13 21:19:36 -08:00
|
|
|
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
|
2019-02-11 07:33:10 -08:00
|
|
|
|
|
|
|
for y in (0..im.h()).rev() {
|
|
|
|
for x in 0..im.w() {
|
|
|
|
let cr = im.index(x, y);
|
2019-02-13 21:19:36 -08:00
|
|
|
out.write_all(&[(cr.b() >> 8) as u8,
|
|
|
|
(cr.g() >> 8) as u8,
|
|
|
|
(cr.r() >> 8) as u8,
|
|
|
|
(cr.a() >> 8) as u8])?;
|
2019-02-11 07:33:10 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2019-02-09 11:04:27 -08:00
|
|
|
pub trait Image
|
|
|
|
{
|
|
|
|
type Output: Color;
|
|
|
|
|
|
|
|
fn w(&self) -> usize;
|
|
|
|
fn h(&self) -> usize;
|
2019-02-11 05:44:20 -08:00
|
|
|
fn index(&self, x: usize, y: usize) -> &Self::Output;
|
2019-02-11 03:28:53 -08:00
|
|
|
|
2019-02-11 05:44:20 -08:00
|
|
|
fn get(&self, x: usize, y: usize) -> Option<&Self::Output>
|
2019-02-11 03:28:53 -08:00
|
|
|
{
|
|
|
|
if x < self.w() && y < self.h() {
|
2019-02-24 20:34:59 -08:00
|
|
|
Some(self.index(x, y))
|
2019-02-11 03:28:53 -08:00
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
2019-02-09 11:04:27 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub trait Color
|
|
|
|
{
|
2019-02-11 03:28:53 -08:00
|
|
|
fn r(&self) -> u16;
|
|
|
|
fn g(&self) -> u16;
|
|
|
|
fn b(&self) -> u16;
|
|
|
|
fn a(&self) -> u16;
|
2018-09-06 09:01:52 -07:00
|
|
|
}
|
|
|
|
|
2019-02-09 11:04:27 -08:00
|
|
|
impl Image16
|
2018-09-06 09:01:52 -07:00
|
|
|
{
|
2019-02-09 11:04:27 -08:00
|
|
|
/// Creates a new Image16.
|
2019-02-17 18:17:02 -08:00
|
|
|
pub fn new(w: usize, h: usize) -> Self
|
2019-02-08 21:53:27 -08:00
|
|
|
{
|
2019-02-17 18:17:02 -08:00
|
|
|
Self{w, h, cr: Vec::with_capacity(w * h)}
|
2019-02-08 21:53:27 -08:00
|
|
|
}
|
2019-02-09 11:04:27 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Image for Image16
|
|
|
|
{
|
|
|
|
type Output = Color16;
|
2019-02-08 21:53:27 -08:00
|
|
|
|
2019-02-09 21:52:51 -08:00
|
|
|
fn w(&self) -> usize {self.w}
|
|
|
|
fn h(&self) -> usize {self.h}
|
2019-02-09 11:04:27 -08:00
|
|
|
|
2019-02-11 05:44:20 -08:00
|
|
|
fn index(&self, x: usize, y: usize) -> &Self::Output
|
2019-02-09 11:04:27 -08:00
|
|
|
{
|
2019-02-11 03:28:53 -08:00
|
|
|
&self.cr[x + y * self.w]
|
2019-02-09 11:04:27 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Image8
|
|
|
|
{
|
|
|
|
/// Creates a new Image8.
|
2019-02-17 18:17:02 -08:00
|
|
|
pub fn new(w: usize, h: usize) -> Self
|
2019-02-09 11:04:27 -08:00
|
|
|
{
|
2019-02-17 18:17:02 -08:00
|
|
|
Self{w, h, cr: Vec::with_capacity(w * h)}
|
2019-02-09 11:04:27 -08:00
|
|
|
}
|
2018-09-06 09:01:52 -07:00
|
|
|
}
|
|
|
|
|
2019-02-09 11:04:27 -08:00
|
|
|
impl Image for Image8
|
2018-09-06 09:01:52 -07:00
|
|
|
{
|
2019-02-09 11:04:27 -08:00
|
|
|
type Output = Color8;
|
|
|
|
|
2019-02-09 21:52:51 -08:00
|
|
|
fn w(&self) -> usize {self.w}
|
|
|
|
fn h(&self) -> usize {self.h}
|
2018-09-06 09:01:52 -07:00
|
|
|
|
2019-02-11 05:44:20 -08:00
|
|
|
fn index(&self, x: usize, y: usize) -> &Self::Output
|
2019-02-08 21:53:27 -08:00
|
|
|
{
|
2019-02-11 03:28:53 -08:00
|
|
|
&self.cr[x + y * self.w]
|
2019-02-08 21:53:27 -08:00
|
|
|
}
|
2018-09-06 09:01:52 -07:00
|
|
|
}
|
|
|
|
|
2019-02-09 11:04:27 -08:00
|
|
|
impl Color16
|
|
|
|
{
|
2019-02-24 20:34:59 -08:00
|
|
|
pub const fn new(r: u16, g: u16, b: u16) -> Self {Self(r, g, b)}
|
2019-02-09 11:04:27 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Color for Color16
|
|
|
|
{
|
2019-02-09 21:52:51 -08:00
|
|
|
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()}
|
2019-02-09 11:04:27 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Color8
|
|
|
|
{
|
2019-02-24 20:34:59 -08:00
|
|
|
pub const fn new(r: u8, g: u8, b: u8) -> Self {Self(r, g, b)}
|
2019-02-09 11:04:27 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Color for Color8
|
2018-09-06 09:01:52 -07:00
|
|
|
{
|
2019-02-11 03:28:53 -08:00
|
|
|
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()}
|
2019-02-09 11:04:27 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// A RGB16 color.
|
|
|
|
#[derive(Clone, Debug, PartialEq)]
|
2019-02-09 21:52:51 -08:00
|
|
|
pub struct Color16(u16, u16, u16);
|
2019-02-09 11:04:27 -08:00
|
|
|
|
|
|
|
/// A RGB8 color.
|
|
|
|
#[derive(Clone, Debug, PartialEq)]
|
2019-02-09 21:52:51 -08:00
|
|
|
pub struct Color8(u8, u8, u8);
|
2019-02-09 11:04:27 -08:00
|
|
|
|
|
|
|
/// RGB16 image.
|
|
|
|
pub struct Image16
|
|
|
|
{
|
|
|
|
w: usize,
|
|
|
|
h: usize,
|
|
|
|
pub cr: Vec<Color16>,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// RGB16 image.
|
|
|
|
pub struct Image8
|
|
|
|
{
|
|
|
|
w: usize,
|
|
|
|
h: usize,
|
|
|
|
pub cr: Vec<Color8>,
|
2018-09-06 09:01:52 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// EOF
|