use std;
use std::io;
#[derive(Clone)]
pub struct Image {
pub(crate) format: PixelFormat,
pub(crate) width: u32,
pub(crate) height: u32,
pub(crate) data: Box<[u8]>,
}
impl Image {
pub fn new(format: PixelFormat, width: u32, height: u32) -> Image {
let data_bits = format.bits_per_pixel() * width * height;
let data_bytes = ((data_bits + 7) / 8) as usize;
Image {
format,
width,
height,
data: vec![0u8; data_bytes].into_boxed_slice(),
}
}
pub fn from_data(
format: PixelFormat,
width: u32,
height: u32,
data: Vec<u8>,
) -> io::Result<Image> {
let data_bits = format.bits_per_pixel() * width * height;
let data_bytes = ((data_bits + 7) / 8) as usize;
if data.len() == data_bytes {
Ok(Image {
format,
width,
height,
data: data.into_boxed_slice(),
})
} else {
let msg = format!(
"incorrect pixel data array length for \
speicifed format and dimensions ({} instead \
of {})",
data.len(),
data_bytes
);
Err(io::Error::new(io::ErrorKind::InvalidInput, msg))
}
}
pub fn pixel_format(&self) -> PixelFormat {
self.format
}
pub fn width(&self) -> u32 {
self.width
}
pub fn height(&self) -> u32 {
self.height
}
pub fn data(&self) -> &[u8] {
&self.data
}
pub fn data_mut(&mut self) -> &mut [u8] {
&mut self.data
}
pub fn into_data(self) -> Box<[u8]> {
self.data
}
pub fn convert_to(&self, format: PixelFormat) -> Image {
let new_data = match self.format {
PixelFormat::RGBA => match format {
PixelFormat::RGBA => self.data.clone(),
PixelFormat::RGB => rgba_to_rgb(&self.data),
PixelFormat::GrayAlpha => rgba_to_grayalpha(&self.data),
PixelFormat::Gray => rgba_to_gray(&self.data),
PixelFormat::Alpha => rgba_to_alpha(&self.data),
PixelFormat::PNG => return self.make_png_image(),
},
PixelFormat::RGB => match format {
PixelFormat::RGBA => rgb_to_rgba(&self.data),
PixelFormat::RGB => self.data.clone(),
PixelFormat::GrayAlpha => rgb_to_grayalpha(&self.data),
PixelFormat::Gray => rgb_to_gray(&self.data),
PixelFormat::Alpha => rgb_to_alpha(&self.data),
PixelFormat::PNG => return self.make_png_image(),
},
PixelFormat::GrayAlpha => match format {
PixelFormat::RGBA => grayalpha_to_rgba(&self.data),
PixelFormat::RGB => grayalpha_to_rgb(&self.data),
PixelFormat::GrayAlpha => self.data.clone(),
PixelFormat::Gray => grayalpha_to_gray(&self.data),
PixelFormat::Alpha => grayalpha_to_alpha(&self.data),
PixelFormat::PNG => return self.make_png_image(),
},
PixelFormat::Gray => match format {
PixelFormat::RGBA => gray_to_rgba(&self.data),
PixelFormat::RGB => gray_to_rgb(&self.data),
PixelFormat::GrayAlpha => gray_to_grayalpha(&self.data),
PixelFormat::Gray => self.data.clone(),
PixelFormat::Alpha => gray_to_alpha(&self.data),
PixelFormat::PNG => return self.make_png_image(),
},
PixelFormat::Alpha => match format {
PixelFormat::RGBA => alpha_to_rgba(&self.data),
PixelFormat::RGB => alpha_to_rgb(&self.data),
PixelFormat::GrayAlpha => alpha_to_grayalpha(&self.data),
PixelFormat::Gray => alpha_to_gray(&self.data),
PixelFormat::Alpha => self.data.clone(),
PixelFormat::PNG => return self.make_png_image(),
},
PixelFormat::PNG => match format {
PixelFormat::PNG => self.data.clone(),
_ => {
return Image::decode_from_png(&*self.data)
.expect("Unable to read PNG")
.convert_to(format)
}
},
};
Image {
format,
width: self.width,
height: self.height,
data: new_data,
}
}
fn make_png_image(&self) -> Image {
let mut v = Vec::new();
self.write_png(&mut v).expect("Unable to write to PNG");
Image {
format: PixelFormat::PNG,
width: self.width,
height: self.height,
data: v.into_boxed_slice(),
}
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum PixelFormat {
RGBA,
RGB,
GrayAlpha,
Gray,
Alpha,
PNG,
}
impl PixelFormat {
pub fn bits_per_pixel(self) -> u32 {
match self {
PixelFormat::RGBA => 32,
PixelFormat::RGB => 24,
PixelFormat::GrayAlpha => 16,
PixelFormat::Gray => 8,
PixelFormat::Alpha => 8,
PixelFormat::PNG => panic!("Unable to know definite number of bits per pixel for PNG"),
}
}
}
fn rgba_to_rgb(rgba: &[u8]) -> Box<[u8]> {
assert_eq!(rgba.len() % 4, 0);
let num_pixels = rgba.len() / 4;
let mut rgb = Vec::with_capacity(num_pixels * 3);
for i in 0..num_pixels {
rgb.extend_from_slice(&rgba[(4 * i)..(4 * i + 3)]);
}
rgb.into_boxed_slice()
}
fn rgb_to_rgba(rgb: &[u8]) -> Box<[u8]> {
assert_eq!(rgb.len() % 3, 0);
let num_pixels = rgb.len() / 3;
let mut rgba = Vec::with_capacity(num_pixels * 4);
for i in 0..num_pixels {
rgba.extend_from_slice(&rgb[(3 * i)..(3 * i + 3)]);
rgba.push(std::u8::MAX);
}
rgba.into_boxed_slice()
}
fn rgba_to_gray(rgba: &[u8]) -> Box<[u8]> {
assert_eq!(rgba.len() % 4, 0);
let num_pixels = rgba.len() / 4;
let mut gray = Vec::with_capacity(num_pixels);
for i in 0..num_pixels {
let red = u32::from(rgba[4 * i]);
let green = u32::from(rgba[4 * i + 1]);
let blue = u32::from(rgba[4 * i + 2]);
gray.push(((red + green + blue) / 3) as u8);
}
gray.into_boxed_slice()
}
fn rgb_to_gray(rgb: &[u8]) -> Box<[u8]> {
assert_eq!(rgb.len() % 3, 0);
let num_pixels = rgb.len() / 3;
let mut gray = Vec::with_capacity(num_pixels);
for i in 0..num_pixels {
let red = u32::from(rgb[3 * i]);
let green = u32::from(rgb[3 * i + 1]);
let blue = u32::from(rgb[3 * i + 2]);
gray.push(((red + green + blue) / 3) as u8);
}
gray.into_boxed_slice()
}
fn rgba_to_grayalpha(rgba: &[u8]) -> Box<[u8]> {
assert_eq!(rgba.len() % 4, 0);
let num_pixels = rgba.len() / 4;
let mut grayalpha = Vec::with_capacity(num_pixels * 2);
for i in 0..num_pixels {
let red = u32::from(rgba[4 * i]);
let green = u32::from(rgba[4 * i + 1]);
let blue = u32::from(rgba[4 * i + 2]);
let alpha = rgba[4 * i + 3];
grayalpha.push(((red + green + blue) / 3) as u8);
grayalpha.push(alpha);
}
grayalpha.into_boxed_slice()
}
fn rgb_to_grayalpha(rgb: &[u8]) -> Box<[u8]> {
assert_eq!(rgb.len() % 3, 0);
let num_pixels = rgb.len() / 3;
let mut gray = Vec::with_capacity(num_pixels);
for i in 0..num_pixels {
let red = u32::from(rgb[3 * i]);
let green = u32::from(rgb[3 * i + 1]);
let blue = u32::from(rgb[3 * i + 2]);
gray.push(((red + green + blue) / 3) as u8);
gray.push(std::u8::MAX);
}
gray.into_boxed_slice()
}
fn rgba_to_alpha(rgba: &[u8]) -> Box<[u8]> {
assert_eq!(rgba.len() % 4, 0);
let num_pixels = rgba.len() / 4;
let mut alpha = Vec::with_capacity(num_pixels);
for i in 0..num_pixels {
alpha.push(rgba[4 * i + 3]);
}
alpha.into_boxed_slice()
}
fn rgb_to_alpha(rgb: &[u8]) -> Box<[u8]> {
assert_eq!(rgb.len() % 3, 0);
let num_pixels = rgb.len() / 3;
vec![std::u8::MAX; num_pixels].into_boxed_slice()
}
fn grayalpha_to_rgba(grayalpha: &[u8]) -> Box<[u8]> {
assert_eq!(grayalpha.len() % 2, 0);
let num_pixels = grayalpha.len() / 2;
let mut rgba = Vec::with_capacity(num_pixels * 4);
for i in 0..num_pixels {
let gray = grayalpha[2 * i];
let alpha = grayalpha[2 * i + 1];
rgba.push(gray);
rgba.push(gray);
rgba.push(gray);
rgba.push(alpha);
}
rgba.into_boxed_slice()
}
fn grayalpha_to_rgb(grayalpha: &[u8]) -> Box<[u8]> {
assert_eq!(grayalpha.len() % 2, 0);
let num_pixels = grayalpha.len() / 2;
let mut rgb = Vec::with_capacity(num_pixels * 3);
for i in 0..num_pixels {
let gray = grayalpha[2 * i];
rgb.push(gray);
rgb.push(gray);
rgb.push(gray);
}
rgb.into_boxed_slice()
}
fn grayalpha_to_gray(grayalpha: &[u8]) -> Box<[u8]> {
assert_eq!(grayalpha.len() % 2, 0);
let num_pixels = grayalpha.len() / 2;
let mut gray = Vec::with_capacity(num_pixels);
for i in 0..num_pixels {
let value = grayalpha[2 * i];
gray.push(value);
}
gray.into_boxed_slice()
}
fn grayalpha_to_alpha(grayalpha: &[u8]) -> Box<[u8]> {
assert_eq!(grayalpha.len() % 2, 0);
let num_pixels = grayalpha.len() / 2;
let mut alpha = Vec::with_capacity(num_pixels);
for i in 0..num_pixels {
let value = grayalpha[2 * i + 1];
alpha.push(value);
}
alpha.into_boxed_slice()
}
fn gray_to_rgba(gray: &[u8]) -> Box<[u8]> {
let num_pixels = gray.len();
let mut rgba = Vec::with_capacity(num_pixels * 4);
for &value in gray {
rgba.push(value);
rgba.push(value);
rgba.push(value);
rgba.push(std::u8::MAX);
}
rgba.into_boxed_slice()
}
fn gray_to_rgb(gray: &[u8]) -> Box<[u8]> {
let num_pixels = gray.len();
let mut rgb = Vec::with_capacity(num_pixels * 3);
for &value in gray {
rgb.push(value);
rgb.push(value);
rgb.push(value);
}
rgb.into_boxed_slice()
}
fn gray_to_grayalpha(gray: &[u8]) -> Box<[u8]> {
let num_pixels = gray.len();
let mut grayalpha = Vec::with_capacity(num_pixels * 2);
for &value in gray {
grayalpha.push(value);
grayalpha.push(std::u8::MAX);
}
grayalpha.into_boxed_slice()
}
fn gray_to_alpha(gray: &[u8]) -> Box<[u8]> {
vec![std::u8::MAX; gray.len()].into_boxed_slice()
}
fn alpha_to_rgba(alpha: &[u8]) -> Box<[u8]> {
let num_pixels = alpha.len();
let mut rgba = Vec::with_capacity(num_pixels * 4);
for &value in alpha {
rgba.push(0);
rgba.push(0);
rgba.push(0);
rgba.push(value);
}
rgba.into_boxed_slice()
}
fn alpha_to_rgb(alpha: &[u8]) -> Box<[u8]> {
vec![0u8; alpha.len() * 3].into_boxed_slice()
}
fn alpha_to_grayalpha(alpha: &[u8]) -> Box<[u8]> {
let num_pixels = alpha.len();
let mut grayalpha = Vec::with_capacity(num_pixels * 2);
for &value in alpha {
grayalpha.push(0);
grayalpha.push(value);
}
grayalpha.into_boxed_slice()
}
fn alpha_to_gray(alpha: &[u8]) -> Box<[u8]> {
vec![0u8; alpha.len()].into_boxed_slice()
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::Cursor;
#[test]
fn image_from_data() {
let data: Vec<u8> = vec![255, 0, 0, 0, 255, 0, 0, 0, 255, 95, 95, 95];
let image = Image::from_data(PixelFormat::RGB, 2, 2, data.clone()).unwrap();
assert_eq!(image.data(), &data as &[u8]);
}
#[test]
fn image_from_data_wrong_size() {
let data: Vec<u8> = vec![1, 2, 3];
let result = Image::from_data(PixelFormat::Alpha, 2, 2, data);
assert!(result.is_err());
}
#[test]
fn alpha_to_gray() {
let alpha_data: Vec<u8> = vec![63, 127, 191, 255];
let mut alpha_image = Image::new(PixelFormat::Alpha, 2, 2);
alpha_image.data_mut().clone_from_slice(&alpha_data);
let gray_image = alpha_image.convert_to(PixelFormat::Gray);
let gray_data: Vec<u8> = vec![0, 0, 0, 0];
assert_eq!(gray_image.data(), &gray_data as &[u8]);
}
#[test]
fn alpha_to_grayalpha() {
let alpha_data: Vec<u8> = vec![63, 127, 191, 255];
let mut alpha_image = Image::new(PixelFormat::Alpha, 2, 2);
alpha_image.data_mut().clone_from_slice(&alpha_data);
let grayalpha_image = alpha_image.convert_to(PixelFormat::GrayAlpha);
let grayalpha_data: Vec<u8> = vec![0, 63, 0, 127, 0, 191, 0, 255];
assert_eq!(grayalpha_image.data(), &grayalpha_data as &[u8]);
}
#[test]
fn alpha_to_rgb() {
let alpha_data: Vec<u8> = vec![63, 127, 191, 255];
let mut alpha_image = Image::new(PixelFormat::Alpha, 2, 2);
alpha_image.data_mut().clone_from_slice(&alpha_data);
let rgb_image = alpha_image.convert_to(PixelFormat::RGB);
let rgb_data: Vec<u8> = vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
assert_eq!(rgb_image.data(), &rgb_data as &[u8]);
}
#[test]
fn alpha_to_rgba() {
let alpha_data: Vec<u8> = vec![63, 127, 191, 255];
let mut alpha_image = Image::new(PixelFormat::Alpha, 2, 2);
alpha_image.data_mut().clone_from_slice(&alpha_data);
let rgba_image = alpha_image.convert_to(PixelFormat::RGBA);
let rgba_data: Vec<u8> = vec![0, 0, 0, 63, 0, 0, 0, 127, 0, 0, 0, 191, 0, 0, 0, 255];
assert_eq!(rgba_image.data(), &rgba_data as &[u8]);
}
#[test]
fn gray_to_alpha() {
let gray_data: Vec<u8> = vec![63, 127, 191, 255];
let mut gray_image = Image::new(PixelFormat::Gray, 2, 2);
gray_image.data_mut().clone_from_slice(&gray_data);
let alpha_image = gray_image.convert_to(PixelFormat::Alpha);
let alpha_data: Vec<u8> = vec![255, 255, 255, 255];
assert_eq!(alpha_image.data(), &alpha_data as &[u8]);
}
#[test]
fn gray_to_grayalpha() {
let gray_data: Vec<u8> = vec![63, 127, 191, 255];
let mut gray_image = Image::new(PixelFormat::Gray, 2, 2);
gray_image.data_mut().clone_from_slice(&gray_data);
let grayalpha_image = gray_image.convert_to(PixelFormat::GrayAlpha);
let grayalpha_data: Vec<u8> = vec![63, 255, 127, 255, 191, 255, 255, 255];
assert_eq!(grayalpha_image.data(), &grayalpha_data as &[u8]);
}
#[test]
fn gray_to_rgb() {
let gray_data: Vec<u8> = vec![63, 127, 191, 255];
let mut gray_image = Image::new(PixelFormat::Gray, 2, 2);
gray_image.data_mut().clone_from_slice(&gray_data);
let rgb_image = gray_image.convert_to(PixelFormat::RGB);
let rgb_data: Vec<u8> = vec![63, 63, 63, 127, 127, 127, 191, 191, 191, 255, 255, 255];
assert_eq!(rgb_image.data(), &rgb_data as &[u8]);
}
#[test]
fn gray_to_rgba() {
let gray_data: Vec<u8> = vec![63, 127, 191, 255];
let mut gray_image = Image::new(PixelFormat::Gray, 2, 2);
gray_image.data_mut().clone_from_slice(&gray_data);
let rgba_image = gray_image.convert_to(PixelFormat::RGBA);
assert_eq!(rgba_image.pixel_format(), PixelFormat::RGBA);
assert_eq!(rgba_image.width(), 2);
assert_eq!(rgba_image.height(), 2);
let rgba_data: Vec<u8> = vec![
63, 63, 63, 255, 127, 127, 127, 255, 191, 191, 191, 255, 255, 255, 255, 255,
];
assert_eq!(rgba_image.data(), &rgba_data as &[u8]);
}
#[test]
fn grayalpha_to_alpha() {
let grayalpha_data: Vec<u8> = vec![1, 2, 3, 4, 5, 6, 7, 8];
let mut grayalpha_image = Image::new(PixelFormat::GrayAlpha, 2, 2);
grayalpha_image.data_mut().clone_from_slice(&grayalpha_data);
let alpha_image = grayalpha_image.convert_to(PixelFormat::Alpha);
let alpha_data: Vec<u8> = vec![2, 4, 6, 8];
assert_eq!(alpha_image.data(), &alpha_data as &[u8]);
}
#[test]
fn grayalpha_to_gray() {
let grayalpha_data: Vec<u8> = vec![1, 2, 3, 4, 5, 6, 7, 8];
let mut grayalpha_image = Image::new(PixelFormat::GrayAlpha, 2, 2);
grayalpha_image.data_mut().clone_from_slice(&grayalpha_data);
let gray_image = grayalpha_image.convert_to(PixelFormat::Gray);
let gray_data: Vec<u8> = vec![1, 3, 5, 7];
assert_eq!(gray_image.data(), &gray_data as &[u8]);
}
#[test]
fn grayalpha_to_rgb() {
let grayalpha_data: Vec<u8> = vec![1, 2, 3, 4, 5, 6, 7, 8];
let mut grayalpha_image = Image::new(PixelFormat::GrayAlpha, 2, 2);
grayalpha_image.data_mut().clone_from_slice(&grayalpha_data);
let rgb_image = grayalpha_image.convert_to(PixelFormat::RGB);
let rgb_data: Vec<u8> = vec![1, 1, 1, 3, 3, 3, 5, 5, 5, 7, 7, 7];
assert_eq!(rgb_image.data(), &rgb_data as &[u8]);
}
#[test]
fn grayalpha_to_rgba() {
let grayalpha_data: Vec<u8> = vec![1, 2, 3, 4, 5, 6, 7, 8];
let mut grayalpha_image = Image::new(PixelFormat::GrayAlpha, 2, 2);
grayalpha_image.data_mut().clone_from_slice(&grayalpha_data);
let rgba_image = grayalpha_image.convert_to(PixelFormat::RGBA);
let rgba_data: Vec<u8> = vec![1, 1, 1, 2, 3, 3, 3, 4, 5, 5, 5, 6, 7, 7, 7, 8];
assert_eq!(rgba_image.data(), &rgba_data as &[u8]);
}
#[test]
fn rgb_to_alpha() {
let rgb_data: Vec<u8> = vec![30, 0, 0, 0, 60, 0, 0, 0, 90, 40, 40, 40];
let mut rgb_image = Image::new(PixelFormat::RGB, 2, 2);
rgb_image.data_mut().clone_from_slice(&rgb_data);
let alpha_image = rgb_image.convert_to(PixelFormat::Alpha);
let alpha_data: Vec<u8> = vec![255, 255, 255, 255];
assert_eq!(alpha_image.data(), &alpha_data as &[u8]);
}
#[test]
fn rgb_to_gray() {
let rgb_data: Vec<u8> = vec![30, 0, 0, 0, 60, 0, 0, 0, 90, 40, 40, 40];
let mut rgb_image = Image::new(PixelFormat::RGB, 2, 2);
rgb_image.data_mut().clone_from_slice(&rgb_data);
let gray_image = rgb_image.convert_to(PixelFormat::Gray);
let gray_data: Vec<u8> = vec![10, 20, 30, 40];
assert_eq!(gray_image.data(), &gray_data as &[u8]);
}
#[test]
fn rgb_to_grayalpha() {
let rgb_data: Vec<u8> = vec![30, 0, 0, 0, 60, 0, 0, 0, 90, 40, 40, 40];
let mut rgb_image = Image::new(PixelFormat::RGB, 2, 2);
rgb_image.data_mut().clone_from_slice(&rgb_data);
let grayalpha_image = rgb_image.convert_to(PixelFormat::GrayAlpha);
let grayalpha_data: Vec<u8> = vec![10, 255, 20, 255, 30, 255, 40, 255];
assert_eq!(grayalpha_image.data(), &grayalpha_data as &[u8]);
}
#[test]
fn rgb_to_rgba() {
let rgb_data: Vec<u8> = vec![255, 0, 0, 0, 255, 0, 0, 0, 255, 127, 127, 127];
let mut rgb_image = Image::new(PixelFormat::RGB, 2, 2);
rgb_image.data_mut().clone_from_slice(&rgb_data);
let rgba_image = rgb_image.convert_to(PixelFormat::RGBA);
assert_eq!(rgba_image.pixel_format(), PixelFormat::RGBA);
assert_eq!(rgba_image.width(), 2);
assert_eq!(rgba_image.height(), 2);
let rgba_data: Vec<u8> = vec![
255, 0, 0, 255, 0, 255, 0, 255, 0, 0, 255, 255, 127, 127, 127, 255,
];
assert_eq!(rgba_image.data(), &rgba_data as &[u8]);
}
#[test]
fn rgba_to_alpha() {
let rgba_data: Vec<u8> = vec![30, 0, 0, 200, 0, 60, 0, 150, 0, 0, 90, 100, 40, 40, 40, 50];
let mut rgba_image = Image::new(PixelFormat::RGBA, 2, 2);
rgba_image.data_mut().clone_from_slice(&rgba_data);
let alpha_image = rgba_image.convert_to(PixelFormat::Alpha);
let alpha_data: Vec<u8> = vec![200, 150, 100, 50];
assert_eq!(alpha_image.data(), &alpha_data as &[u8]);
}
#[test]
fn rgba_to_gray() {
let rgba_data: Vec<u8> = vec![30, 0, 0, 200, 0, 60, 0, 150, 0, 0, 90, 100, 40, 40, 40, 50];
let mut rgba_image = Image::new(PixelFormat::RGBA, 2, 2);
rgba_image.data_mut().clone_from_slice(&rgba_data);
let gray_image = rgba_image.convert_to(PixelFormat::Gray);
let gray_data: Vec<u8> = vec![10, 20, 30, 40];
assert_eq!(gray_image.data(), &gray_data as &[u8]);
}
#[test]
fn rgba_to_grayalpha() {
let rgba_data: Vec<u8> = vec![30, 0, 0, 200, 0, 60, 0, 150, 0, 0, 90, 100, 40, 40, 40, 50];
let mut rgba_image = Image::new(PixelFormat::RGBA, 2, 2);
rgba_image.data_mut().clone_from_slice(&rgba_data);
let grayalpha_image = rgba_image.convert_to(PixelFormat::GrayAlpha);
let grayalpha_data: Vec<u8> = vec![10, 200, 20, 150, 30, 100, 40, 50];
assert_eq!(grayalpha_image.data(), &grayalpha_data as &[u8]);
}
#[test]
fn rgba_to_rgb() {
let rgba_data: Vec<u8> = vec![30, 0, 0, 200, 0, 60, 0, 150, 0, 0, 90, 100, 40, 40, 40, 50];
let mut rgba_image = Image::new(PixelFormat::RGBA, 2, 2);
rgba_image.data_mut().clone_from_slice(&rgba_data);
let rgb_image = rgba_image.convert_to(PixelFormat::RGB);
let rgb_data: Vec<u8> = vec![30, 0, 0, 0, 60, 0, 0, 0, 90, 40, 40, 40];
assert_eq!(rgb_image.data(), &rgb_data as &[u8]);
}
#[test]
#[cfg(feature = "pngio")]
fn write_grayscale_png() {
let gray_data: Vec<u8> = vec![63, 127, 191, 255];
let mut image = Image::new(PixelFormat::Gray, 2, 2);
image.data_mut().clone_from_slice(&gray_data);
let mut output: Vec<u8> = Vec::new();
image.write_png(&mut output).expect("failed to write PNG");
let expected: Vec<u8> = vec![
137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 2, 0, 0, 0, 2,
8, 0, 0, 0, 0, 87, 221, 82, 248, 0, 0, 0, 14, 73, 68, 65, 84, 120, 156, 99, 180, 119,
96, 220, 239, 0, 0, 4, 8, 1, 129, 134, 46, 201, 141, 0, 0, 0, 0, 73, 69, 78, 68, 174,
66, 96, 130,
];
assert_eq!(output, expected);
}
#[test]
#[cfg(feature = "pngio")]
fn write_rgb_png() {
let rgb_data: Vec<u8> = vec![255, 0, 0, 0, 255, 0, 0, 0, 255, 127, 127, 127];
let mut image = Image::new(PixelFormat::RGB, 2, 2);
image.data_mut().clone_from_slice(&rgb_data);
let mut output: Vec<u8> = Vec::new();
image.write_png(&mut output).expect("failed to write PNG");
let expected: Vec<u8> = vec![
137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 2, 0, 0, 0, 2,
8, 2, 0, 0, 0, 253, 212, 154, 115, 0, 0, 0, 20, 73, 68, 65, 84, 120, 156, 99, 252, 207,
192, 0, 196, 140, 12, 12, 255, 235, 235, 27, 0, 29, 14, 4, 127, 253, 15, 140, 153, 0,
0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130,
];
assert_eq!(output, expected);
}
#[test]
#[cfg(feature = "pngio")]
fn write_rgba_png() {
let rgba_data: Vec<u8> = vec![
255, 0, 0, 63, 0, 255, 0, 127, 0, 0, 255, 191, 127, 127, 127, 255,
];
let mut image = Image::new(PixelFormat::RGBA, 2, 2);
image.data_mut().clone_from_slice(&rgba_data);
let mut output: Vec<u8> = Vec::new();
image.write_png(&mut output).expect("failed to write PNG");
let expected: Vec<u8> = vec![
137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 2, 0, 0, 0, 2,
8, 6, 0, 0, 0, 114, 182, 13, 36, 0, 0, 0, 25, 73, 68, 65, 84, 120, 156, 99, 252, 207,
192, 96, 15, 36, 28, 24, 25, 24, 254, 239, 175, 175, 111, 112, 0, 0, 49, 125, 5, 253,
88, 193, 178, 240, 0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130,
];
assert_eq!(output, expected);
}
#[test]
#[cfg(feature = "pngio")]
fn read_rgba_png() {
let png: Vec<u8> = vec![
137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 2, 0, 0, 0, 2,
8, 6, 0, 0, 0, 114, 182, 13, 36, 0, 0, 0, 29, 73, 68, 65, 84, 120, 1, 1, 18, 0, 237,
255, 1, 255, 0, 0, 63, 1, 255, 0, 64, 1, 0, 0, 255, 191, 127, 127, 128, 64, 49, 125, 5,
253, 198, 70, 247, 56, 0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130,
];
let image = Image::read_png(Cursor::new(&png)).expect("failed to read PNG");
assert_eq!(image.data(), &png as &[u8]);
let image = image.convert_to(PixelFormat::RGBA);
assert_eq!(image.pixel_format(), PixelFormat::RGBA);
assert_eq!(image.width(), 2);
assert_eq!(image.height(), 2);
let rgba_data: Vec<u8> = vec![
255, 0, 0, 63, 0, 255, 0, 127, 0, 0, 255, 191, 127, 127, 127, 255,
];
assert_eq!(image.data(), &rgba_data as &[u8]);
}
#[test]
#[cfg(feature = "pngio")]
fn png_round_trip() {
let rgba_data: Vec<u8> = vec![
127, 0, 0, 63, 0, 191, 0, 127, 0, 0, 255, 191, 127, 127, 127, 255,
];
let mut rgba_image = Image::new(PixelFormat::RGBA, 2, 2);
rgba_image.data_mut().clone_from_slice(&rgba_data);
let pixel_formats = [
PixelFormat::RGBA,
PixelFormat::RGB,
PixelFormat::GrayAlpha,
PixelFormat::Gray,
PixelFormat::Alpha,
];
for &format in pixel_formats.iter() {
let image_1 = rgba_image.convert_to(format);
let mut png_data = Vec::<u8>::new();
image_1
.write_png(&mut png_data)
.expect("failed to write PNG");
let mut image_2 = Image::read_png(Cursor::new(&png_data)).expect("failed to read PNG");
if image_2.pixel_format() != image_1.pixel_format() {
image_2 = image_2.convert_to(image_1.pixel_format());
}
assert_eq!(image_1.data(), image_2.data());
}
}
}