Use ExtendedColorType when encoding (#2142)

This commit is contained in:
Jonathan Behrens 2024-02-18 19:12:23 -08:00 committed by GitHub
commit a0ebeabafc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
35 changed files with 353 additions and 335 deletions

View file

@ -245,6 +245,6 @@ fn main() {
let buffer: &[u8] = unimplemented!(); // Generate the image data
// Save the buffer as "image.png"
image::save_buffer("image.png", buffer, 800, 600, image::ColorType::Rgb8).unwrap()
image::save_buffer("image.png", buffer, 800, 600, image::ExtendedColorType::Rgb8).unwrap()
}
```

View file

@ -1,15 +1,16 @@
extern crate criterion;
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
use image::ExtendedColorType;
use image::{codecs::bmp::BmpEncoder, codecs::jpeg::JpegEncoder, ColorType};
use std::fs::File;
use std::io::{BufWriter, Seek, SeekFrom, Write};
trait Encoder {
fn encode_raw(&self, into: &mut Vec<u8>, im: &[u8], dims: u32, color: ColorType);
fn encode_bufvec(&self, into: &mut Vec<u8>, im: &[u8], dims: u32, color: ColorType);
fn encode_file(&self, file: &File, im: &[u8], dims: u32, color: ColorType);
fn encode_raw(&self, into: &mut Vec<u8>, im: &[u8], dims: u32, color: ExtendedColorType);
fn encode_bufvec(&self, into: &mut Vec<u8>, im: &[u8], dims: u32, color: ExtendedColorType);
fn encode_file(&self, file: &File, im: &[u8], dims: u32, color: ExtendedColorType);
}
#[derive(Clone, Copy)]
@ -50,9 +51,8 @@ type BenchGroup<'a> = criterion::BenchmarkGroup<'a, criterion::measurement::Wall
///
/// For compressed formats this is surely not representative of encoding a normal image but it's a
/// start for benchmarking.
fn encode_zeroed(group: &mut BenchGroup, with: &dyn Encoder, size: u32, color: ColorType) {
let bytes = size as usize * usize::from(color.bytes_per_pixel());
let im = vec![0; bytes * bytes];
fn encode_zeroed(group: &mut BenchGroup, with: &dyn Encoder, size: u32, color: ExtendedColorType) {
let im = vec![0; (color.bits_per_pixel() as usize * size as usize + 7) / 8 * size as usize];
group.bench_with_input(
BenchmarkId::new(format!("zero-{:?}-rawvec", color), size),
@ -87,7 +87,7 @@ fn encode_definition(criterion: &mut Criterion, def: &BenchDef) {
for &color in def.colors {
for &size in def.sizes {
encode_zeroed(&mut group, def.with, size, color);
encode_zeroed(&mut group, def.with, size, color.into());
}
}
}
@ -97,22 +97,22 @@ struct Bmp;
struct Jpeg;
trait EncoderBase {
fn encode(&self, into: impl Write, im: &[u8], dims: u32, color: ColorType);
fn encode(&self, into: impl Write, im: &[u8], dims: u32, color: ExtendedColorType);
}
impl<T: EncoderBase> Encoder for T {
fn encode_raw(&self, into: &mut Vec<u8>, im: &[u8], dims: u32, color: ColorType) {
fn encode_raw(&self, into: &mut Vec<u8>, im: &[u8], dims: u32, color: ExtendedColorType) {
into.clear();
self.encode(into, im, dims, color);
}
fn encode_bufvec(&self, into: &mut Vec<u8>, im: &[u8], dims: u32, color: ColorType) {
fn encode_bufvec(&self, into: &mut Vec<u8>, im: &[u8], dims: u32, color: ExtendedColorType) {
into.clear();
let buf = BufWriter::new(into);
self.encode(buf, im, dims, color);
}
fn encode_file(&self, mut file: &File, im: &[u8], dims: u32, color: ColorType) {
fn encode_file(&self, mut file: &File, im: &[u8], dims: u32, color: ExtendedColorType) {
file.seek(SeekFrom::Start(0)).unwrap();
let buf = BufWriter::new(file);
self.encode(buf, im, dims, color);
@ -120,14 +120,14 @@ impl<T: EncoderBase> Encoder for T {
}
impl EncoderBase for Bmp {
fn encode(&self, mut into: impl Write, im: &[u8], size: u32, color: ColorType) {
fn encode(&self, mut into: impl Write, im: &[u8], size: u32, color: ExtendedColorType) {
let mut x = BmpEncoder::new(&mut into);
x.encode(im, size, size, color).unwrap();
}
}
impl EncoderBase for Jpeg {
fn encode(&self, mut into: impl Write, im: &[u8], size: u32, color: ColorType) {
fn encode(&self, mut into: impl Write, im: &[u8], size: u32, color: ExtendedColorType) {
let mut x = JpegEncoder::new(&mut into);
x.encode(im, size, size, color).unwrap();
}

View file

@ -5,7 +5,7 @@ extern crate image;
use image::codecs::openexr::*;
use image::io::Limits;
use image::ColorType;
use image::ExtendedColorType;
use image::ImageDecoder;
use image::ImageEncoder;
use image::ImageResult;
@ -45,7 +45,7 @@ fn roundtrip(bytes: &[u8]) -> ImageResult<()> {
write: impl Write + Seek,
(width, height, data): &(u32, u32, Vec<u8>),
) -> ImageResult<()> {
OpenExrEncoder::new(write).write_image(data.as_slice(), *width, *height, ColorType::Rgba32F)
OpenExrEncoder::new(write).write_image(data.as_slice(), *width, *height, ExtendedColorType::Rgba32F)
}
let decoded_image = read_as_rgba_byte_image(Cursor::new(bytes))?;

View file

@ -1,5 +1,4 @@
use std::cmp::Ordering;
use std::iter::Iterator;
use std::time::Duration;
use crate::error::ImageResult;

View file

@ -3,7 +3,6 @@
/// The [AVIF] specification defines an image derivative of the AV1 bitstream, an open video codec.
///
/// [AVIF]: https://aomediacodec.github.io/av1-avif/
use std::convert::TryFrom;
use std::error::Error;
use std::io::Read;
use std::marker::PhantomData;

View file

@ -12,7 +12,7 @@ use crate::color::{FromColor, Luma, LumaA, Rgb, Rgba};
use crate::error::{
EncodingError, ParameterError, ParameterErrorKind, UnsupportedError, UnsupportedErrorKind,
};
use crate::{ColorType, ImageBuffer, ImageEncoder, ImageFormat, Pixel};
use crate::{ExtendedColorType, ImageBuffer, ImageEncoder, ImageFormat, Pixel};
use crate::{ImageError, ImageResult};
use bytemuck::{try_cast_slice, try_cast_slice_mut, Pod, PodCastError};
@ -104,10 +104,9 @@ impl<W: Write> ImageEncoder for AvifEncoder<W> {
data: &[u8],
width: u32,
height: u32,
color: ColorType,
color: ExtendedColorType,
) -> ImageResult<()> {
let expected_buffer_len =
(width as u64 * height as u64).saturating_mul(color.bytes_per_pixel() as u64);
let expected_buffer_len = color.buffer_size(width, height);
assert_eq!(
expected_buffer_len,
data.len() as u64,
@ -134,7 +133,7 @@ impl<W: Write> ImageEncoder for AvifEncoder<W> {
impl<W: Write> AvifEncoder<W> {
// Does not currently do anything. Mirrors behaviour of old config function.
fn set_color(&mut self, _color: ColorType) {
fn set_color(&mut self, _color: ExtendedColorType) {
// self.config.color_space = ColorSpace::RGB;
}
@ -143,7 +142,7 @@ impl<W: Write> AvifEncoder<W> {
data: &'buf [u8],
width: u32,
height: u32,
color: ColorType,
color: ExtendedColorType,
) -> ImageResult<RgbColor<'buf>> {
// Error wrapping utility for color dependent buffer dimensions.
fn try_from_raw<P: Pixel + 'static>(
@ -210,7 +209,7 @@ impl<W: Write> AvifEncoder<W> {
}
match color {
ColorType::Rgb8 => {
ExtendedColorType::Rgb8 => {
// ravif doesn't do any checks but has some asserts, so we do the checks.
let img = try_from_raw::<Rgb<u8>>(data, width, height)?;
// Now, internally ravif uses u32 but it takes usize. We could do some checked
@ -227,7 +226,7 @@ impl<W: Write> AvifEncoder<W> {
height as usize,
)))
}
ColorType::Rgba8 => {
ExtendedColorType::Rgba8 => {
// ravif doesn't do any checks but has some asserts, so we do the checks.
let img = try_from_raw::<Rgba<u8>>(data, width, height)?;
// Now, internally ravif uses u32 but it takes usize. We could do some checked
@ -245,31 +244,31 @@ impl<W: Write> AvifEncoder<W> {
)))
}
// we need a separate buffer..
ColorType::L8 => {
ExtendedColorType::L8 => {
let image = try_from_raw::<Luma<u8>>(data, width, height)?;
Ok(RgbColor::Rgba8(convert_into(fallback, image)))
}
ColorType::La8 => {
ExtendedColorType::La8 => {
let image = try_from_raw::<LumaA<u8>>(data, width, height)?;
Ok(RgbColor::Rgba8(convert_into(fallback, image)))
}
// we need to really convert data..
ColorType::L16 => {
ExtendedColorType::L16 => {
let buffer = cast_buffer(data)?;
let image = try_from_raw::<Luma<u16>>(&buffer, width, height)?;
Ok(RgbColor::Rgba8(convert_into(fallback, image)))
}
ColorType::La16 => {
ExtendedColorType::La16 => {
let buffer = cast_buffer(data)?;
let image = try_from_raw::<LumaA<u16>>(&buffer, width, height)?;
Ok(RgbColor::Rgba8(convert_into(fallback, image)))
}
ColorType::Rgb16 => {
ExtendedColorType::Rgb16 => {
let buffer = cast_buffer(data)?;
let image = try_from_raw::<Rgb<u16>>(&buffer, width, height)?;
Ok(RgbColor::Rgba8(convert_into(fallback, image)))
}
ColorType::Rgba16 => {
ExtendedColorType::Rgba16 => {
let buffer = cast_buffer(data)?;
let image = try_from_raw::<Rgba<u16>>(&buffer, width, height)?;
Ok(RgbColor::Rgba8(convert_into(fallback, image)))
@ -278,7 +277,7 @@ impl<W: Write> AvifEncoder<W> {
_ => Err(ImageError::Unsupported(
UnsupportedError::from_format_and_kind(
ImageFormat::Avif.into(),
UnsupportedErrorKind::Color(color.into()),
UnsupportedErrorKind::Color(color),
),
)),
}

View file

@ -1,7 +1,6 @@
use std::cmp::{self, Ordering};
use std::convert::TryFrom;
use std::io::{self, Read, Seek, SeekFrom};
use std::iter::{repeat, Iterator, Rev};
use std::iter::{repeat, Rev};
use std::slice::ChunksMut;
use std::{error, fmt};

View file

@ -5,7 +5,7 @@ use crate::error::{
EncodingError, ImageError, ImageFormatHint, ImageResult, ParameterError, ParameterErrorKind,
};
use crate::image::ImageEncoder;
use crate::{color, ImageFormat};
use crate::{ExtendedColorType, ImageFormat};
const BITMAPFILEHEADER_SIZE: u32 = 14;
const BITMAPINFOHEADER_SIZE: u32 = 40;
@ -22,7 +22,7 @@ impl<'a, W: Write + 'a> BmpEncoder<'a, W> {
BmpEncoder { writer: w }
}
/// Encodes the image `image` that has dimensions `width` and `height` and `ColorType` `c`.
/// Encodes the image `image` that has dimensions `width` and `height` and `ExtendedColorType` `c`.
///
/// # Panics
///
@ -33,7 +33,7 @@ impl<'a, W: Write + 'a> BmpEncoder<'a, W> {
image: &[u8],
width: u32,
height: u32,
c: color::ColorType,
c: ExtendedColorType,
) -> ImageResult<()> {
self.encode_with_palette(image, width, height, c, None)
}
@ -50,10 +50,10 @@ impl<'a, W: Write + 'a> BmpEncoder<'a, W> {
image: &[u8],
width: u32,
height: u32,
c: color::ColorType,
c: ExtendedColorType,
palette: Option<&[[u8; 3]]>,
) -> ImageResult<()> {
if palette.is_some() && c != color::ColorType::L8 && c != color::ColorType::La8 {
if palette.is_some() && c != ExtendedColorType::L8 && c != ExtendedColorType::La8 {
return Err(ImageError::IoError(io::Error::new(
io::ErrorKind::InvalidInput,
format!(
@ -63,8 +63,7 @@ impl<'a, W: Write + 'a> BmpEncoder<'a, W> {
)));
}
let expected_buffer_len =
(width as u64 * height as u64).saturating_mul(c.bytes_per_pixel() as u64);
let expected_buffer_len = c.buffer_size(width, height);
assert_eq!(
expected_buffer_len,
image.len() as u64,
@ -141,12 +140,12 @@ impl<'a, W: Write + 'a> BmpEncoder<'a, W> {
// write image data
match c {
color::ColorType::Rgb8 => self.encode_rgb(image, width, height, row_pad_size, 3)?,
color::ColorType::Rgba8 => self.encode_rgba(image, width, height, row_pad_size, 4)?,
color::ColorType::L8 => {
ExtendedColorType::Rgb8 => self.encode_rgb(image, width, height, row_pad_size, 3)?,
ExtendedColorType::Rgba8 => self.encode_rgba(image, width, height, row_pad_size, 4)?,
ExtendedColorType::L8 => {
self.encode_gray(image, width, height, row_pad_size, 1, palette)?
}
color::ColorType::La8 => {
ExtendedColorType::La8 => {
self.encode_gray(image, width, height, row_pad_size, 2, palette)?
}
_ => {
@ -274,13 +273,13 @@ impl<'a, W: Write> ImageEncoder for BmpEncoder<'a, W> {
buf: &[u8],
width: u32,
height: u32,
color_type: color::ColorType,
color_type: ExtendedColorType,
) -> ImageResult<()> {
self.encode(buf, width, height, color_type)
}
}
fn get_unsupported_error_message(c: color::ColorType) -> String {
fn get_unsupported_error_message(c: ExtendedColorType) -> String {
format!(
"Unsupported color type {:?}. Supported types: RGB(8), RGBA(8), Gray(8), GrayA(8).",
c
@ -288,16 +287,19 @@ fn get_unsupported_error_message(c: color::ColorType) -> String {
}
/// Returns a tuple representing: (dib header size, written pixel size, palette color count).
fn get_pixel_info(c: color::ColorType, palette: Option<&[[u8; 3]]>) -> io::Result<(u32, u32, u32)> {
fn get_pixel_info(
c: ExtendedColorType,
palette: Option<&[[u8; 3]]>,
) -> io::Result<(u32, u32, u32)> {
let sizes = match c {
color::ColorType::Rgb8 => (BITMAPINFOHEADER_SIZE, 3, 0),
color::ColorType::Rgba8 => (BITMAPV4HEADER_SIZE, 4, 0),
color::ColorType::L8 => (
ExtendedColorType::Rgb8 => (BITMAPINFOHEADER_SIZE, 3, 0),
ExtendedColorType::Rgba8 => (BITMAPV4HEADER_SIZE, 4, 0),
ExtendedColorType::L8 => (
BITMAPINFOHEADER_SIZE,
1,
palette.map(|p| p.len()).unwrap_or(256) as u32,
),
color::ColorType::La8 => (
ExtendedColorType::La8 => (
BITMAPINFOHEADER_SIZE,
1,
palette.map(|p| p.len()).unwrap_or(256) as u32,
@ -317,11 +319,12 @@ fn get_pixel_info(c: color::ColorType, palette: Option<&[[u8; 3]]>) -> io::Resul
mod tests {
use super::super::BmpDecoder;
use super::BmpEncoder;
use crate::color::ColorType;
use crate::image::ImageDecoder;
use crate::ExtendedColorType;
use std::io::Cursor;
fn round_trip_image(image: &[u8], width: u32, height: u32, c: ColorType) -> Vec<u8> {
fn round_trip_image(image: &[u8], width: u32, height: u32, c: ExtendedColorType) -> Vec<u8> {
let mut encoded_data = Vec::new();
{
let mut encoder = BmpEncoder::new(&mut encoded_data);
@ -340,7 +343,7 @@ mod tests {
#[test]
fn round_trip_single_pixel_rgb() {
let image = [255u8, 0, 0]; // single red pixel
let decoded = round_trip_image(&image, 1, 1, ColorType::Rgb8);
let decoded = round_trip_image(&image, 1, 1, ExtendedColorType::Rgb8);
assert_eq!(3, decoded.len());
assert_eq!(255, decoded[0]);
assert_eq!(0, decoded[1]);
@ -353,27 +356,27 @@ mod tests {
let mut encoded_data = Vec::new();
let image = vec![0u8; 3 * 40_000 * 40_000]; // 40_000x40_000 pixels, 3 bytes per pixel, allocated on the heap
let mut encoder = BmpEncoder::new(&mut encoded_data);
let result = encoder.encode(&image, 40_000, 40_000, ColorType::Rgb8);
let result = encoder.encode(&image, 40_000, 40_000, ExtendedColorType::Rgb8);
assert!(result.is_err());
}
#[test]
fn round_trip_single_pixel_rgba() {
let image = [1, 2, 3, 4];
let decoded = round_trip_image(&image, 1, 1, ColorType::Rgba8);
let decoded = round_trip_image(&image, 1, 1, ExtendedColorType::Rgba8);
assert_eq!(&decoded[..], &image[..]);
}
#[test]
fn round_trip_3px_rgb() {
let image = [0u8; 3 * 3 * 3]; // 3x3 pixels, 3 bytes per pixel
let _decoded = round_trip_image(&image, 3, 3, ColorType::Rgb8);
let _decoded = round_trip_image(&image, 3, 3, ExtendedColorType::Rgb8);
}
#[test]
fn round_trip_gray() {
let image = [0u8, 1, 2]; // 3 pixels
let decoded = round_trip_image(&image, 3, 1, ColorType::L8);
let decoded = round_trip_image(&image, 3, 1, ExtendedColorType::L8);
// should be read back as 3 RGB pixels
assert_eq!(9, decoded.len());
assert_eq!(0, decoded[0]);
@ -390,7 +393,7 @@ mod tests {
#[test]
fn round_trip_graya() {
let image = [0u8, 0, 1, 0, 2, 0]; // 3 pixels, each with an alpha channel
let decoded = round_trip_image(&image, 1, 3, ColorType::La8);
let decoded = round_trip_image(&image, 1, 3, ExtendedColorType::La8);
// should be read back as 3 RGB pixels
assert_eq!(9, decoded.len());
assert_eq!(0, decoded[0]);

View file

@ -7,7 +7,6 @@
//!
//! Note: this module only implements bare DXT encoding/decoding, it does not parse formats that can contain DXT files like .dds
use std::convert::TryFrom;
use std::io::{self, Read};
use crate::color::ColorType;

View file

@ -16,15 +16,15 @@
//! # Related Links
//! * <https://tools.suckless.org/farbfeld/> - the farbfeld specification
use std::convert::{TryFrom, TryInto};
use std::i64;
use std::io::{self, Read, Seek, SeekFrom, Write};
use crate::color::ColorType;
use crate::color::ExtendedColorType;
use crate::error::{
DecodingError, ImageError, ImageResult, UnsupportedError, UnsupportedErrorKind,
};
use crate::image::{self, ImageDecoder, ImageDecoderRect, ImageEncoder, ImageFormat};
use crate::ColorType;
/// farbfeld Reader
pub struct FarbfeldReader<R: Read> {
@ -68,8 +68,8 @@ impl<R: Read> FarbfeldReader<R> {
if crate::utils::check_dimension_overflow(
reader.width,
reader.height,
// ColorType is always rgba16
ColorType::Rgba16.bytes_per_pixel(),
// ExtendedColorType is always rgba16
8,
) {
return Err(ImageError::Unsupported(
UnsupportedError::from_format_and_kind(
@ -297,13 +297,13 @@ impl<W: Write> ImageEncoder for FarbfeldEncoder<W> {
buf: &[u8],
width: u32,
height: u32,
color_type: ColorType,
color_type: ExtendedColorType,
) -> ImageResult<()> {
if color_type != ColorType::Rgba16 {
if color_type != ExtendedColorType::Rgba16 {
return Err(ImageError::Unsupported(
UnsupportedError::from_format_and_kind(
ImageFormat::Farbfeld.into(),
UnsupportedErrorKind::Color(color_type.into()),
UnsupportedErrorKind::Color(color_type),
),
));
}

View file

@ -26,8 +26,6 @@
//! ```
#![allow(clippy::while_let_loop)]
use std::convert::TryFrom;
use std::convert::TryInto;
use std::io::{self, Cursor, Read, Write};
use std::marker::PhantomData;
use std::mem;
@ -46,6 +44,7 @@ use crate::error::{
use crate::image::{AnimationDecoder, ImageDecoder, ImageFormat};
use crate::io::Limits;
use crate::traits::Pixel;
use crate::ExtendedColorType;
use crate::ImageBuffer;
/// GIF decoder
@ -487,18 +486,18 @@ impl<W: Write> GifEncoder<W> {
data: &[u8],
width: u32,
height: u32,
color: ColorType,
color: ExtendedColorType,
) -> ImageResult<()> {
let (width, height) = self.gif_dimensions(width, height)?;
match color {
ColorType::Rgb8 => self.encode_gif(Frame::from_rgb(width, height, data)),
ColorType::Rgba8 => {
ExtendedColorType::Rgb8 => self.encode_gif(Frame::from_rgb(width, height, data)),
ExtendedColorType::Rgba8 => {
self.encode_gif(Frame::from_rgba(width, height, &mut data.to_owned()))
}
_ => Err(ImageError::Unsupported(
UnsupportedError::from_format_and_kind(
ImageFormat::Gif.into(),
UnsupportedErrorKind::Color(color.into()),
UnsupportedErrorKind::Color(color),
),
)),
}

View file

@ -2,9 +2,7 @@ use crate::Primitive;
use num_traits::identities::Zero;
#[cfg(test)]
use std::borrow::Cow;
use std::convert::TryFrom;
use std::io::{self, BufRead, Cursor, Read, Seek};
use std::iter::Iterator;
use std::marker::PhantomData;
use std::num::{ParseFloatError, ParseIntError};
use std::path::Path;
@ -1018,7 +1016,6 @@ pub fn read_raw_file<P: AsRef<Path>>(path: P) -> ::std::io::Result<Vec<Rgb<f32>>
#[cfg(test)]
mod test {
use super::*;
use std::io::Cursor;
#[test]
fn dimension_overflow() {

View file

@ -1,5 +1,4 @@
use byteorder::{LittleEndian, ReadBytesExt};
use std::convert::TryFrom;
use std::io::{Read, Seek, SeekFrom};
use std::{error, fmt};

View file

@ -2,11 +2,11 @@ use byteorder::{LittleEndian, WriteBytesExt};
use std::borrow::Cow;
use std::io::{self, Write};
use crate::color::ColorType;
use crate::error::{ImageError, ImageResult, ParameterError, ParameterErrorKind};
use crate::image::ImageEncoder;
use crate::codecs::png::PngEncoder;
use crate::ExtendedColorType;
// Enum value indicating an ICO image (as opposed to a CUR image):
const ICO_IMAGE_TYPE: u16 = 1;
@ -28,7 +28,7 @@ pub struct IcoFrame<'a> {
width: u8,
// Stored as `0 => 256, n => n`
height: u8,
color_type: ColorType,
color_type: ExtendedColorType,
}
impl<'a> IcoFrame<'a> {
@ -39,7 +39,7 @@ impl<'a> IcoFrame<'a> {
encoded_image: impl Into<Cow<'a, [u8]>>,
width: u32,
height: u32,
color_type: ColorType,
color_type: ExtendedColorType,
) -> ImageResult<Self> {
let encoded_image = encoded_image.into();
@ -72,7 +72,12 @@ impl<'a> IcoFrame<'a> {
/// Construct a new `IcoFrame` by encoding `buf` as a PNG
///
/// The `width` and `height` must be between 1 and 256 (inclusive)
pub fn as_png(buf: &[u8], width: u32, height: u32, color_type: ColorType) -> ImageResult<Self> {
pub fn as_png(
buf: &[u8],
width: u32,
height: u32,
color_type: ExtendedColorType,
) -> ImageResult<Self> {
let mut image_data: Vec<u8> = Vec::new();
PngEncoder::new(&mut image_data).write_image(buf, width, height, color_type)?;
@ -136,10 +141,9 @@ impl<W: Write> ImageEncoder for IcoEncoder<W> {
buf: &[u8],
width: u32,
height: u32,
color_type: ColorType,
color_type: ExtendedColorType,
) -> ImageResult<()> {
let expected_buffer_len =
(width as u64 * height as u64).saturating_mul(color_type.bytes_per_pixel() as u64);
let expected_buffer_len = color_type.buffer_size(width, height);
assert_eq!(
expected_buffer_len,
buf.len() as u64,
@ -166,7 +170,7 @@ fn write_direntry<W: Write>(
w: &mut W,
width: u8,
height: u8,
color: ColorType,
color: ExtendedColorType,
data_start: u32,
data_size: u32,
) -> io::Result<()> {

View file

@ -1,7 +1,6 @@
#![allow(clippy::too_many_arguments)]
use std::borrow::Cow;
use std::convert::TryFrom;
use std::io::{self, Write};
use crate::error::{
@ -10,7 +9,7 @@ use crate::error::{
};
use crate::image::{ImageEncoder, ImageFormat};
use crate::utils::clamp;
use crate::{ColorType, GenericImageView, ImageBuffer, Luma, LumaA, Pixel, Rgb, Rgba};
use crate::{ExtendedColorType, GenericImageView, ImageBuffer, Luma, LumaA, Pixel, Rgb, Rgba};
use super::entropy::build_huff_lut_const;
use super::transform;
@ -446,10 +445,9 @@ impl<W: Write> JpegEncoder<W> {
image: &[u8],
width: u32,
height: u32,
color_type: ColorType,
color_type: ExtendedColorType,
) -> ImageResult<()> {
let expected_buffer_len =
(width as u64 * height as u64).saturating_mul(color_type.bytes_per_pixel() as u64);
let expected_buffer_len = color_type.buffer_size(width, height);
assert_eq!(
expected_buffer_len,
image.len() as u64,
@ -458,22 +456,22 @@ impl<W: Write> JpegEncoder<W> {
);
match color_type {
ColorType::L8 => {
ExtendedColorType::L8 => {
let image: ImageBuffer<Luma<_>, _> =
ImageBuffer::from_raw(width, height, image).unwrap();
self.encode_image(&image)
}
ColorType::La8 => {
ExtendedColorType::La8 => {
let image: ImageBuffer<LumaA<_>, _> =
ImageBuffer::from_raw(width, height, image).unwrap();
self.encode_image(&image)
}
ColorType::Rgb8 => {
ExtendedColorType::Rgb8 => {
let image: ImageBuffer<Rgb<_>, _> =
ImageBuffer::from_raw(width, height, image).unwrap();
self.encode_image(&image)
}
ColorType::Rgba8 => {
ExtendedColorType::Rgba8 => {
let image: ImageBuffer<Rgba<_>, _> =
ImageBuffer::from_raw(width, height, image).unwrap();
self.encode_image(&image)
@ -481,7 +479,7 @@ impl<W: Write> JpegEncoder<W> {
_ => Err(ImageError::Unsupported(
UnsupportedError::from_format_and_kind(
ImageFormat::Jpeg.into(),
UnsupportedErrorKind::Color(color_type.into()),
UnsupportedErrorKind::Color(color_type),
),
)),
}
@ -579,7 +577,7 @@ impl<W: Write> JpegEncoder<W> {
build_scan_header(&mut buf, &self.components[..num_components]);
self.writer.write_segment(SOS, &buf)?;
if color_type.has_color() {
if let ExtendedColorType::Rgb8 = color_type {
self.encode_rgb(image)
} else {
self.encode_gray(image)
@ -674,7 +672,7 @@ impl<W: Write> ImageEncoder for JpegEncoder<W> {
buf: &[u8],
width: u32,
height: u32,
color_type: ColorType,
color_type: ExtendedColorType,
) -> ImageResult<()> {
self.encode(buf, width, height, color_type)
}
@ -856,10 +854,9 @@ mod tests {
#[cfg(feature = "benchmarks")]
use test::Bencher;
use crate::color::ColorType;
use crate::error::ParameterErrorKind::DimensionMismatch;
use crate::image::ImageDecoder;
use crate::{ImageEncoder, ImageError};
use crate::{ExtendedColorType, ImageEncoder, ImageError};
use super::super::JpegDecoder;
use super::{
@ -888,7 +885,7 @@ mod tests {
{
let encoder = JpegEncoder::new_with_quality(&mut encoded_img, 100);
encoder
.write_image(&img, 1, 1, ColorType::Rgb8)
.write_image(&img, 1, 1, ExtendedColorType::Rgb8)
.expect("Could not encode image");
}
@ -914,7 +911,7 @@ mod tests {
{
let encoder = JpegEncoder::new_with_quality(&mut encoded_img, 100);
encoder
.write_image(&img[..], 2, 2, ColorType::L8)
.write_image(&img[..], 2, 2, ExtendedColorType::L8)
.expect("Could not encode image");
}
@ -964,7 +961,7 @@ mod tests {
// Try to encode an image that is too large
let mut encoded = Vec::new();
let encoder = JpegEncoder::new_with_quality(&mut encoded, 100);
let result = encoder.write_image(&img, 65_536, 1, ColorType::L8);
let result = encoder.write_image(&img, 65_536, 1, ExtendedColorType::L8);
match result {
Err(ImageError::Parameter(err)) => {
assert_eq!(err.kind(), DimensionMismatch)

View file

@ -220,36 +220,14 @@ fn write_buffer(
unaligned_bytes: &[u8],
width: u32,
height: u32,
color_type: ColorType,
color_type: ExtendedColorType,
) -> ImageResult<()> {
let width = width as usize;
let height = height as usize;
{
// check whether the buffer is large enough for the specified dimensions
let expected_byte_count = width
.checked_mul(height)
.and_then(|size| size.checked_mul(color_type.bytes_per_pixel() as usize));
// if the width and height does not match the length of the bytes, the arguments are invalid
let has_invalid_size_or_overflowed = expected_byte_count
.map(|expected_byte_count| unaligned_bytes.len() < expected_byte_count)
// otherwise, size calculation overflowed, is bigger than memory,
// therefore data is too small, so it is invalid.
.unwrap_or(true);
if has_invalid_size_or_overflowed {
return Err(ImageError::Encoding(EncodingError::new(
ImageFormatHint::Exact(ImageFormat::OpenExr),
"byte buffer not large enough for the specified dimensions and f32 pixels",
)));
}
}
let bytes_per_pixel = color_type.bytes_per_pixel() as usize;
let bytes_per_pixel = color_type.bits_per_pixel() as usize / 8;
match color_type {
ColorType::Rgb32F => {
ExtendedColorType::Rgb32F => {
exr::prelude::Image // TODO compression method zip??
::from_channels(
(width, height),
@ -270,7 +248,7 @@ fn write_buffer(
.map_err(to_image_err)?;
}
ColorType::Rgba32F => {
ExtendedColorType::Rgba32F => {
exr::prelude::Image // TODO compression method zip??
::from_channels(
(width, height),
@ -333,10 +311,9 @@ where
buf: &[u8],
width: u32,
height: u32,
color_type: ColorType,
color_type: ExtendedColorType,
) -> ImageResult<()> {
let expected_buffer_len =
(width as u64 * height as u64).saturating_mul(color_type.bytes_per_pixel() as u64);
let expected_buffer_len = color_type.buffer_size(width, height);
assert_eq!(
expected_buffer_len,
buf.len() as u64,
@ -377,7 +354,7 @@ mod test {
bytemuck::cast_slice(image.as_raw().as_slice()),
image.width(),
image.height(),
ColorType::Rgb32F,
ExtendedColorType::Rgb32F,
)
}
@ -390,7 +367,7 @@ mod test {
bytemuck::cast_slice(image.as_raw().as_slice()),
image.width(),
image.height(),
ColorType::Rgba32F,
ExtendedColorType::Rgba32F,
)
}

View file

@ -6,7 +6,6 @@
//! * <http://www.w3.org/TR/PNG/> - The PNG Specification
//!
use std::convert::TryFrom;
use std::fmt;
use std::io::{Read, Write};
@ -500,7 +499,7 @@ pub enum FilterType {
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[non_exhaustive]
enum BadPngRepresentation {
ColorType(ColorType),
ColorType(ExtendedColorType),
}
impl<W: Write> PngEncoder<W> {
@ -542,22 +541,22 @@ impl<W: Write> PngEncoder<W> {
data: &[u8],
width: u32,
height: u32,
color: ColorType,
color: ExtendedColorType,
) -> ImageResult<()> {
let (ct, bits) = match color {
ColorType::L8 => (png::ColorType::Grayscale, png::BitDepth::Eight),
ColorType::L16 => (png::ColorType::Grayscale, png::BitDepth::Sixteen),
ColorType::La8 => (png::ColorType::GrayscaleAlpha, png::BitDepth::Eight),
ColorType::La16 => (png::ColorType::GrayscaleAlpha, png::BitDepth::Sixteen),
ColorType::Rgb8 => (png::ColorType::Rgb, png::BitDepth::Eight),
ColorType::Rgb16 => (png::ColorType::Rgb, png::BitDepth::Sixteen),
ColorType::Rgba8 => (png::ColorType::Rgba, png::BitDepth::Eight),
ColorType::Rgba16 => (png::ColorType::Rgba, png::BitDepth::Sixteen),
ExtendedColorType::L8 => (png::ColorType::Grayscale, png::BitDepth::Eight),
ExtendedColorType::L16 => (png::ColorType::Grayscale, png::BitDepth::Sixteen),
ExtendedColorType::La8 => (png::ColorType::GrayscaleAlpha, png::BitDepth::Eight),
ExtendedColorType::La16 => (png::ColorType::GrayscaleAlpha, png::BitDepth::Sixteen),
ExtendedColorType::Rgb8 => (png::ColorType::Rgb, png::BitDepth::Eight),
ExtendedColorType::Rgb16 => (png::ColorType::Rgb, png::BitDepth::Sixteen),
ExtendedColorType::Rgba8 => (png::ColorType::Rgba, png::BitDepth::Eight),
ExtendedColorType::Rgba16 => (png::ColorType::Rgba, png::BitDepth::Sixteen),
_ => {
return Err(ImageError::Unsupported(
UnsupportedError::from_format_and_kind(
ImageFormat::Png.into(),
UnsupportedErrorKind::Color(color.into()),
UnsupportedErrorKind::Color(color),
),
))
}
@ -606,17 +605,16 @@ impl<W: Write> ImageEncoder for PngEncoder<W> {
buf: &[u8],
width: u32,
height: u32,
color_type: ColorType,
color_type: ExtendedColorType,
) -> ImageResult<()> {
use byteorder::{BigEndian, ByteOrder, NativeEndian};
use ColorType::*;
use ExtendedColorType::*;
let expected_bufffer_len =
(width as u64 * height as u64).saturating_mul(color_type.bytes_per_pixel() as u64);
let expected_buffer_len = color_type.buffer_size(width, height);
assert_eq!(
expected_bufffer_len,
expected_buffer_len,
buf.len() as u64,
"Invalid buffer length: expected {expected_bufffer_len} got {} for {width}x{height} image",
"Invalid buffer length: expected {expected_buffer_len} got {} for {width}x{height} image",
buf.len(),
);
@ -687,10 +685,7 @@ impl std::error::Error for BadPngRepresentation {}
#[cfg(test)]
mod tests {
use super::*;
use crate::image::ImageDecoder;
use crate::ImageFormat;
use std::io::{Cursor, Read};
use std::io::Cursor;
#[test]
fn ensure_no_decoder_off_by_one() {

View file

@ -1,5 +1,3 @@
use std::convert::TryFrom;
use std::convert::TryInto;
use std::error;
use std::fmt::{self, Display};
use std::io::{self, Read};

View file

@ -7,7 +7,7 @@ use std::io::Write;
use super::AutoBreak;
use super::{ArbitraryHeader, ArbitraryTuplType, BitmapHeader, GraymapHeader, PixmapHeader};
use super::{HeaderRecord, PnmHeader, PnmSubtype, SampleEncoding};
use crate::color::{ColorType, ExtendedColorType};
use crate::color::ExtendedColorType;
use crate::error::{
ImageError, ImageResult, ParameterError, ParameterErrorKind, UnsupportedError,
UnsupportedErrorKind,
@ -144,27 +144,20 @@ impl<W: Write> PnmEncoder<W> {
image: S,
width: u32,
height: u32,
color: ColorType,
color: ExtendedColorType,
) -> ImageResult<()>
where
S: Into<FlatSamples<'s>>,
{
let image = image.into();
match self.header {
HeaderStrategy::Dynamic => {
self.write_dynamic_header(image, width, height, color.into())
}
HeaderStrategy::Dynamic => self.write_dynamic_header(image, width, height, color),
HeaderStrategy::Subtype(subtype) => {
self.write_subtyped_header(subtype, image, width, height, color.into())
self.write_subtyped_header(subtype, image, width, height, color)
}
HeaderStrategy::Chosen(ref header) => {
Self::write_with_header(&mut self.writer, header, image, width, height, color)
}
HeaderStrategy::Chosen(ref header) => Self::write_with_header(
&mut self.writer,
header,
image,
width,
height,
color.into(),
),
}
}
@ -295,10 +288,9 @@ impl<W: Write> ImageEncoder for PnmEncoder<W> {
buf: &[u8],
width: u32,
height: u32,
color_type: ColorType,
color_type: ExtendedColorType,
) -> ImageResult<()> {
let expected_buffer_len =
(width as u64 * height as u64).saturating_mul(color_type.bytes_per_pixel() as u64);
let expected_buffer_len = color_type.buffer_size(width, height);
assert_eq!(
expected_buffer_len,
buf.len() as u64,

View file

@ -20,11 +20,11 @@ mod header;
#[cfg(test)]
mod tests {
use super::*;
use crate::color::ColorType;
use crate::image::ImageDecoder;
use crate::ExtendedColorType;
use byteorder::{ByteOrder, NativeEndian};
fn execute_roundtrip_default(buffer: &[u8], width: u32, height: u32, color: ColorType) {
fn execute_roundtrip_default(buffer: &[u8], width: u32, height: u32, color: ExtendedColorType) {
let mut encoded_buffer = Vec::new();
{
@ -47,7 +47,7 @@ mod tests {
assert_eq!(header.width(), width);
assert_eq!(header.height(), height);
assert_eq!(loaded_color, color);
assert_eq!(ExtendedColorType::from(loaded_color), color);
assert_eq!(loaded_image.as_slice(), buffer);
}
@ -55,7 +55,7 @@ mod tests {
buffer: &[u8],
width: u32,
height: u32,
color: ColorType,
color: ExtendedColorType,
subtype: PnmSubtype,
) {
let mut encoded_buffer = Vec::new();
@ -81,11 +81,11 @@ mod tests {
assert_eq!(header.width(), width);
assert_eq!(header.height(), height);
assert_eq!(header.subtype(), subtype);
assert_eq!(loaded_color, color);
assert_eq!(ExtendedColorType::from(loaded_color), color);
assert_eq!(loaded_image.as_slice(), buffer);
}
fn execute_roundtrip_u16(buffer: &[u16], width: u32, height: u32, color: ColorType) {
fn execute_roundtrip_u16(buffer: &[u16], width: u32, height: u32, color: ExtendedColorType) {
let mut encoded_buffer = Vec::new();
{
@ -111,7 +111,7 @@ mod tests {
assert_eq!(header.width(), width);
assert_eq!(header.height(), height);
assert_eq!(loaded_color, color);
assert_eq!(ExtendedColorType::from(loaded_color), color);
assert_eq!(loaded_image, buffer_u8);
}
@ -125,20 +125,20 @@ mod tests {
255, 0, 0, 0,
];
execute_roundtrip_default(&buf, 4, 4, ColorType::L8);
execute_roundtrip_with_subtype(&buf, 4, 4, ColorType::L8, PnmSubtype::ArbitraryMap);
execute_roundtrip_default(&buf, 4, 4, ExtendedColorType::L8);
execute_roundtrip_with_subtype(&buf, 4, 4, ExtendedColorType::L8, PnmSubtype::ArbitraryMap);
execute_roundtrip_with_subtype(
&buf,
4,
4,
ColorType::L8,
ExtendedColorType::L8,
PnmSubtype::Graymap(SampleEncoding::Ascii),
);
execute_roundtrip_with_subtype(
&buf,
4,
4,
ColorType::L8,
ExtendedColorType::L8,
PnmSubtype::Graymap(SampleEncoding::Binary),
);
}
@ -157,20 +157,26 @@ mod tests {
255, 255, 255,
255, 255, 255,
];
execute_roundtrip_default(&buf, 3, 3, ColorType::Rgb8);
execute_roundtrip_with_subtype(&buf, 3, 3, ColorType::Rgb8, PnmSubtype::ArbitraryMap);
execute_roundtrip_default(&buf, 3, 3, ExtendedColorType::Rgb8);
execute_roundtrip_with_subtype(
&buf,
3,
3,
ColorType::Rgb8,
ExtendedColorType::Rgb8,
PnmSubtype::ArbitraryMap,
);
execute_roundtrip_with_subtype(
&buf,
3,
3,
ExtendedColorType::Rgb8,
PnmSubtype::Pixmap(SampleEncoding::Binary),
);
execute_roundtrip_with_subtype(
&buf,
3,
3,
ColorType::Rgb8,
ExtendedColorType::Rgb8,
PnmSubtype::Pixmap(SampleEncoding::Ascii),
);
}
@ -179,6 +185,6 @@ mod tests {
fn roundtrip_u16() {
let buf: [u16; 6] = [0, 1, 0xFFFF, 0x1234, 0x3412, 0xBEAF];
execute_roundtrip_u16(&buf, 6, 1, ColorType::L16);
execute_roundtrip_u16(&buf, 6, 1, ExtendedColorType::L16);
}
}

View file

@ -2,7 +2,7 @@
use crate::{
error::{DecodingError, EncodingError},
ColorType, ImageDecoder, ImageEncoder, ImageError, ImageFormat, ImageResult,
ColorType, ExtendedColorType, ImageDecoder, ImageEncoder, ImageError, ImageFormat, ImageResult,
};
use std::io::{Read, Write};
@ -71,17 +71,19 @@ impl<W: Write> ImageEncoder for QoiEncoder<W> {
buf: &[u8],
width: u32,
height: u32,
color_type: ColorType,
color_type: ExtendedColorType,
) -> ImageResult<()> {
if !matches!(color_type, ColorType::Rgba8 | ColorType::Rgb8) {
if !matches!(
color_type,
ExtendedColorType::Rgba8 | ExtendedColorType::Rgb8
) {
return Err(ImageError::Encoding(EncodingError::new(
ImageFormat::Qoi.into(),
format!("unsupported color type {color_type:?}. Supported are Rgba8 and Rgb8."),
)));
}
let expected_buffer_len =
(width as u64 * height as u64).saturating_mul(color_type.bytes_per_pixel() as u64);
let expected_buffer_len = color_type.buffer_size(width, height);
assert_eq!(
expected_buffer_len,
buf.len() as u64,

View file

@ -7,10 +7,7 @@ use crate::{
image::{ImageDecoder, ImageFormat},
};
use byteorder::ReadBytesExt;
use std::{
convert::TryFrom,
io::{self, Read, Seek},
};
use std::io::{self, Read, Seek};
struct ColorMap {
/// sizes in bytes

View file

@ -1,9 +1,9 @@
use super::header::Header;
use crate::{
codecs::tga::header::ImageType, error::EncodingError, ColorType, ImageEncoder, ImageError,
ImageFormat, ImageResult,
codecs::tga::header::ImageType, error::EncodingError, ExtendedColorType, ImageEncoder,
ImageError, ImageFormat, ImageResult,
};
use std::{convert::TryFrom, error, fmt, io::Write};
use std::{error, fmt, io::Write};
/// Errors that can occur during encoding and saving of a TGA image.
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
@ -85,10 +85,14 @@ impl<W: Write> TgaEncoder<W> {
}
/// Writes the run-length encoded buffer to the writer
fn run_length_encode(&mut self, image: &[u8], color_type: ColorType) -> ImageResult<()> {
fn run_length_encode(
&mut self,
image: &[u8],
color_type: ExtendedColorType,
) -> ImageResult<()> {
use PacketType::*;
let bytes_per_pixel = color_type.bytes_per_pixel();
let bytes_per_pixel = color_type.bits_per_pixel() / 8;
let capacity_in_bytes = usize::from(MAX_RUN_LENGTH) * usize::from(bytes_per_pixel);
// Buffer to temporarily store pixels
@ -162,10 +166,9 @@ impl<W: Write> TgaEncoder<W> {
buf: &[u8],
width: u32,
height: u32,
color_type: ColorType,
color_type: ExtendedColorType,
) -> ImageResult<()> {
let expected_buffer_len =
(width as u64 * height as u64).saturating_mul(color_type.bytes_per_pixel() as u64);
let expected_buffer_len = color_type.buffer_size(width, height);
assert_eq!(
expected_buffer_len,
buf.len() as u64,
@ -192,10 +195,11 @@ impl<W: Write> TgaEncoder<W> {
// Write run-length encoded image data
match color_type {
ColorType::Rgb8 | ColorType::Rgba8 => {
ExtendedColorType::Rgb8 | ExtendedColorType::Rgba8 => {
let mut image = Vec::from(buf);
for pixel in image.chunks_mut(usize::from(color_type.bytes_per_pixel())) {
for pixel in image.chunks_mut(usize::from(color_type.bits_per_pixel() / 8))
{
pixel.swap(0, 2);
}
@ -210,10 +214,11 @@ impl<W: Write> TgaEncoder<W> {
// Write uncompressed image data
match color_type {
ColorType::Rgb8 | ColorType::Rgba8 => {
ExtendedColorType::Rgb8 | ExtendedColorType::Rgba8 => {
let mut image = Vec::from(buf);
for pixel in image.chunks_mut(usize::from(color_type.bytes_per_pixel())) {
for pixel in image.chunks_mut(usize::from(color_type.bits_per_pixel() / 8))
{
pixel.swap(0, 2);
}
@ -237,7 +242,7 @@ impl<W: Write> ImageEncoder for TgaEncoder<W> {
buf: &[u8],
width: u32,
height: u32,
color_type: ColorType,
color_type: ExtendedColorType,
) -> ImageResult<()> {
self.encode(buf, width, height, color_type)
}
@ -246,7 +251,7 @@ impl<W: Write> ImageEncoder for TgaEncoder<W> {
#[cfg(test)]
mod tests {
use super::{EncoderError, TgaEncoder};
use crate::{codecs::tga::TgaDecoder, ColorType, ImageDecoder, ImageError};
use crate::{codecs::tga::TgaDecoder, ExtendedColorType, ImageDecoder, ImageError};
use std::{error::Error, io::Cursor};
#[test]
@ -260,7 +265,7 @@ mod tests {
// Try to encode an image that is too large
let mut encoded = Vec::new();
let encoder = TgaEncoder::new(&mut encoded);
let result = encoder.encode(&img, dimension, 1, ColorType::L8);
let result = encoder.encode(&img, dimension, 1, ExtendedColorType::L8);
match result {
Err(ImageError::Encoding(err)) => {
@ -290,7 +295,7 @@ mod tests {
// Try to encode an image that is too large
let mut encoded = Vec::new();
let encoder = TgaEncoder::new(&mut encoded);
let result = encoder.encode(&img, 1, dimension, ColorType::L8);
let result = encoder.encode(&img, 1, dimension, ExtendedColorType::L8);
match result {
Err(ImageError::Encoding(err)) => {
@ -317,7 +322,7 @@ mod tests {
let mut encoded_data = Vec::new();
let encoder = TgaEncoder::new(&mut encoded_data).disable_rle();
encoder
.encode(&image, 5, 1, ColorType::Rgb8)
.encode(&image, 5, 1, ExtendedColorType::Rgb8)
.expect("could not encode image");
encoded_data
@ -327,7 +332,7 @@ mod tests {
let mut encoded_data = Vec::new();
let encoder = TgaEncoder::new(&mut encoded_data);
encoder
.encode(&image, 5, 1, ColorType::Rgb8)
.encode(&image, 5, 1, ExtendedColorType::Rgb8)
.expect("could not encode image");
encoded_data
@ -339,7 +344,12 @@ mod tests {
mod compressed {
use super::*;
fn round_trip_image(image: &[u8], width: u32, height: u32, c: ColorType) -> Vec<u8> {
fn round_trip_image(
image: &[u8],
width: u32,
height: u32,
c: ExtendedColorType,
) -> Vec<u8> {
let mut encoded_data = Vec::new();
{
let encoder = TgaEncoder::new(&mut encoded_data);
@ -359,7 +369,7 @@ mod tests {
let image = [
255, 255, 255, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255,
];
let decoded = round_trip_image(&image, 5, 1, ColorType::Rgb8);
let decoded = round_trip_image(&image, 5, 1, ExtendedColorType::Rgb8);
assert_eq!(decoded.len(), image.len());
assert_eq!(decoded.as_slice(), image);
}
@ -367,7 +377,7 @@ mod tests {
#[test]
fn round_trip_gray() {
let image = [0, 1, 2];
let decoded = round_trip_image(&image, 3, 1, ColorType::L8);
let decoded = round_trip_image(&image, 3, 1, ExtendedColorType::L8);
assert_eq!(decoded.len(), image.len());
assert_eq!(decoded.as_slice(), image);
}
@ -375,7 +385,7 @@ mod tests {
#[test]
fn round_trip_graya() {
let image = [0, 1, 2, 3, 4, 5];
let decoded = round_trip_image(&image, 1, 3, ColorType::La8);
let decoded = round_trip_image(&image, 1, 3, ExtendedColorType::La8);
assert_eq!(decoded.len(), image.len());
assert_eq!(decoded.as_slice(), image);
}
@ -383,7 +393,7 @@ mod tests {
#[test]
fn round_trip_single_pixel_rgb() {
let image = [0, 1, 2];
let decoded = round_trip_image(&image, 1, 1, ColorType::Rgb8);
let decoded = round_trip_image(&image, 1, 1, ExtendedColorType::Rgb8);
assert_eq!(decoded.len(), image.len());
assert_eq!(decoded.as_slice(), image);
}
@ -391,7 +401,7 @@ mod tests {
#[test]
fn round_trip_three_pixel_rgb() {
let image = [0, 1, 2, 0, 1, 2, 0, 1, 2];
let decoded = round_trip_image(&image, 3, 1, ColorType::Rgb8);
let decoded = round_trip_image(&image, 3, 1, ExtendedColorType::Rgb8);
assert_eq!(decoded.len(), image.len());
assert_eq!(decoded.as_slice(), image);
}
@ -399,7 +409,7 @@ mod tests {
#[test]
fn round_trip_3px_rgb() {
let image = [0; 3 * 3 * 3]; // 3x3 pixels, 3 bytes per pixel
let decoded = round_trip_image(&image, 3, 3, ColorType::Rgb8);
let decoded = round_trip_image(&image, 3, 3, ExtendedColorType::Rgb8);
assert_eq!(decoded.len(), image.len());
assert_eq!(decoded.as_slice(), image);
}
@ -407,7 +417,7 @@ mod tests {
#[test]
fn round_trip_different() {
let image = [0, 1, 2, 0, 1, 3, 0, 1, 4];
let decoded = round_trip_image(&image, 3, 1, ColorType::Rgb8);
let decoded = round_trip_image(&image, 3, 1, ExtendedColorType::Rgb8);
assert_eq!(decoded.len(), image.len());
assert_eq!(decoded.as_slice(), image);
}
@ -415,7 +425,7 @@ mod tests {
#[test]
fn round_trip_different_2() {
let image = [0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 4];
let decoded = round_trip_image(&image, 4, 1, ColorType::Rgb8);
let decoded = round_trip_image(&image, 4, 1, ExtendedColorType::Rgb8);
assert_eq!(decoded.len(), image.len());
assert_eq!(decoded.as_slice(), image);
}
@ -423,7 +433,7 @@ mod tests {
#[test]
fn round_trip_different_3() {
let image = [0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 4, 0, 1, 2];
let decoded = round_trip_image(&image, 5, 1, ColorType::Rgb8);
let decoded = round_trip_image(&image, 5, 1, ExtendedColorType::Rgb8);
assert_eq!(decoded.len(), image.len());
assert_eq!(decoded.as_slice(), image);
}
@ -436,7 +446,7 @@ mod tests {
let (width, height) = (image.width(), image.height());
let image = image.as_rgb8().unwrap().to_vec();
let decoded = round_trip_image(&image, width, height, ColorType::Rgb8);
let decoded = round_trip_image(&image, width, height, ExtendedColorType::Rgb8);
assert_eq!(decoded.len(), image.len());
assert_eq!(decoded.as_slice(), image);
}
@ -445,7 +455,12 @@ mod tests {
mod uncompressed {
use super::*;
fn round_trip_image(image: &[u8], width: u32, height: u32, c: ColorType) -> Vec<u8> {
fn round_trip_image(
image: &[u8],
width: u32,
height: u32,
c: ExtendedColorType,
) -> Vec<u8> {
let mut encoded_data = Vec::new();
{
let encoder = TgaEncoder::new(&mut encoded_data).disable_rle();
@ -464,7 +479,7 @@ mod tests {
#[test]
fn round_trip_single_pixel_rgb() {
let image = [0, 1, 2];
let decoded = round_trip_image(&image, 1, 1, ColorType::Rgb8);
let decoded = round_trip_image(&image, 1, 1, ExtendedColorType::Rgb8);
assert_eq!(decoded.len(), image.len());
assert_eq!(decoded.as_slice(), image);
}
@ -472,7 +487,7 @@ mod tests {
#[test]
fn round_trip_single_pixel_rgba() {
let image = [0, 1, 2, 3];
let decoded = round_trip_image(&image, 1, 1, ColorType::Rgba8);
let decoded = round_trip_image(&image, 1, 1, ExtendedColorType::Rgba8);
assert_eq!(decoded.len(), image.len());
assert_eq!(decoded.as_slice(), image);
}
@ -480,7 +495,7 @@ mod tests {
#[test]
fn round_trip_gray() {
let image = [0, 1, 2];
let decoded = round_trip_image(&image, 3, 1, ColorType::L8);
let decoded = round_trip_image(&image, 3, 1, ExtendedColorType::L8);
assert_eq!(decoded.len(), image.len());
assert_eq!(decoded.as_slice(), image);
}
@ -488,7 +503,7 @@ mod tests {
#[test]
fn round_trip_graya() {
let image = [0, 1, 2, 3, 4, 5];
let decoded = round_trip_image(&image, 1, 3, ColorType::La8);
let decoded = round_trip_image(&image, 1, 3, ExtendedColorType::La8);
assert_eq!(decoded.len(), image.len());
assert_eq!(decoded.as_slice(), image);
}
@ -496,7 +511,7 @@ mod tests {
#[test]
fn round_trip_3px_rgb() {
let image = [0; 3 * 3 * 3]; // 3x3 pixels, 3 bytes per pixel
let decoded = round_trip_image(&image, 3, 3, ColorType::Rgb8);
let decoded = round_trip_image(&image, 3, 3, ExtendedColorType::Rgb8);
assert_eq!(decoded.len(), image.len());
assert_eq!(decoded.as_slice(), image);
}

View file

@ -1,6 +1,6 @@
use crate::{
error::{UnsupportedError, UnsupportedErrorKind},
ColorType, ImageError, ImageFormat, ImageResult,
ExtendedColorType, ImageError, ImageFormat, ImageResult,
};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use std::io::{Read, Write};
@ -80,7 +80,7 @@ pub(crate) struct Header {
impl Header {
/// Load the header with values from pixel information.
pub(crate) fn from_pixel_info(
color_type: ColorType,
color_type: ExtendedColorType,
width: u16,
height: u16,
use_rle: bool,
@ -89,19 +89,19 @@ impl Header {
if width > 0 && height > 0 {
let (num_alpha_bits, other_channel_bits, image_type) = match (color_type, use_rle) {
(ColorType::Rgba8, true) => (8, 24, ImageType::RunTrueColor),
(ColorType::Rgb8, true) => (0, 24, ImageType::RunTrueColor),
(ColorType::La8, true) => (8, 8, ImageType::RunGrayScale),
(ColorType::L8, true) => (0, 8, ImageType::RunGrayScale),
(ColorType::Rgba8, false) => (8, 24, ImageType::RawTrueColor),
(ColorType::Rgb8, false) => (0, 24, ImageType::RawTrueColor),
(ColorType::La8, false) => (8, 8, ImageType::RawGrayScale),
(ColorType::L8, false) => (0, 8, ImageType::RawGrayScale),
(ExtendedColorType::Rgba8, true) => (8, 24, ImageType::RunTrueColor),
(ExtendedColorType::Rgb8, true) => (0, 24, ImageType::RunTrueColor),
(ExtendedColorType::La8, true) => (8, 8, ImageType::RunGrayScale),
(ExtendedColorType::L8, true) => (0, 8, ImageType::RunGrayScale),
(ExtendedColorType::Rgba8, false) => (8, 24, ImageType::RawTrueColor),
(ExtendedColorType::Rgb8, false) => (0, 24, ImageType::RawTrueColor),
(ExtendedColorType::La8, false) => (8, 8, ImageType::RawGrayScale),
(ExtendedColorType::L8, false) => (0, 8, ImageType::RawGrayScale),
_ => {
return Err(ImageError::Unsupported(
UnsupportedError::from_format_and_kind(
ImageFormat::Tga.into(),
UnsupportedErrorKind::Color(color_type.into()),
UnsupportedErrorKind::Color(color_type),
),
))
}

View file

@ -8,7 +8,6 @@
extern crate tiff;
use std::convert::TryFrom;
use std::io::{self, Cursor, Read, Seek, Write};
use std::marker::PhantomData;
use std::mem;
@ -325,48 +324,53 @@ impl<W: Write + Seek> TiffEncoder<W> {
///
/// Panics if `width * height * color_type.bytes_per_pixel() != data.len()`.
#[track_caller]
pub fn encode(self, data: &[u8], width: u32, height: u32, color: ColorType) -> ImageResult<()> {
let expected_buffer_len =
(width as u64 * height as u64).saturating_mul(color.bytes_per_pixel() as u64);
pub fn encode(
self,
buf: &[u8],
width: u32,
height: u32,
color_type: ExtendedColorType,
) -> ImageResult<()> {
let expected_buffer_len = color_type.buffer_size(width, height);
assert_eq!(
expected_buffer_len,
data.len() as u64,
buf.len() as u64,
"Invalid buffer length: expected {expected_buffer_len} got {} for {width}x{height} image",
data.len(),
buf.len(),
);
let mut encoder =
tiff::encoder::TiffEncoder::new(self.w).map_err(ImageError::from_tiff_encode)?;
match color {
ColorType::L8 => {
encoder.write_image::<tiff::encoder::colortype::Gray8>(width, height, data)
match color_type {
ExtendedColorType::L8 => {
encoder.write_image::<tiff::encoder::colortype::Gray8>(width, height, buf)
}
ColorType::Rgb8 => {
encoder.write_image::<tiff::encoder::colortype::RGB8>(width, height, data)
ExtendedColorType::Rgb8 => {
encoder.write_image::<tiff::encoder::colortype::RGB8>(width, height, buf)
}
ColorType::Rgba8 => {
encoder.write_image::<tiff::encoder::colortype::RGBA8>(width, height, data)
ExtendedColorType::Rgba8 => {
encoder.write_image::<tiff::encoder::colortype::RGBA8>(width, height, buf)
}
ColorType::L16 => encoder.write_image::<tiff::encoder::colortype::Gray16>(
ExtendedColorType::L16 => encoder.write_image::<tiff::encoder::colortype::Gray16>(
width,
height,
u8_slice_as_u16(data)?,
u8_slice_as_u16(buf)?,
),
ColorType::Rgb16 => encoder.write_image::<tiff::encoder::colortype::RGB16>(
ExtendedColorType::Rgb16 => encoder.write_image::<tiff::encoder::colortype::RGB16>(
width,
height,
u8_slice_as_u16(data)?,
u8_slice_as_u16(buf)?,
),
ColorType::Rgba16 => encoder.write_image::<tiff::encoder::colortype::RGBA16>(
ExtendedColorType::Rgba16 => encoder.write_image::<tiff::encoder::colortype::RGBA16>(
width,
height,
u8_slice_as_u16(data)?,
u8_slice_as_u16(buf)?,
),
_ => {
return Err(ImageError::Unsupported(
UnsupportedError::from_format_and_kind(
ImageFormat::Tiff.into(),
UnsupportedErrorKind::Color(color.into()),
UnsupportedErrorKind::Color(color_type),
),
))
}
@ -384,7 +388,7 @@ impl<W: Write + Seek> ImageEncoder for TiffEncoder<W> {
buf: &[u8],
width: u32,
height: u32,
color_type: ColorType,
color_type: ExtendedColorType,
) -> ImageResult<()> {
self.encode(buf, width, height, color_type)
}

View file

@ -1,4 +1,3 @@
use std::convert::TryFrom;
use std::io::{Read, Seek};
use crate::buffer::ConvertBuffer;

View file

@ -4,7 +4,7 @@ use std::io::Write;
use crate::{
error::{EncodingError, UnsupportedError, UnsupportedErrorKind},
ColorType, ImageEncoder, ImageError, ImageFormat, ImageResult,
ExtendedColorType, ImageEncoder, ImageError, ImageFormat, ImageResult,
};
/// WebP Encoder.
@ -30,33 +30,38 @@ impl<W: Write> WebPEncoder<W> {
///
/// Panics if `width * height * color.bytes_per_pixel() != data.len()`.
#[track_caller]
pub fn encode(self, data: &[u8], width: u32, height: u32, color: ColorType) -> ImageResult<()> {
let expected_buffer_len =
(width as u64 * height as u64).saturating_mul(color.bytes_per_pixel() as u64);
pub fn encode(
self,
buf: &[u8],
width: u32,
height: u32,
color_type: ExtendedColorType,
) -> ImageResult<()> {
let expected_buffer_len = color_type.buffer_size(width, height);
assert_eq!(
expected_buffer_len,
data.len() as u64,
buf.len() as u64,
"Invalid buffer length: expected {expected_buffer_len} got {} for {width}x{height} image",
data.len(),
buf.len(),
);
let color = match color {
ColorType::L8 => image_webp::ColorType::L8,
ColorType::La8 => image_webp::ColorType::La8,
ColorType::Rgb8 => image_webp::ColorType::Rgb8,
ColorType::Rgba8 => image_webp::ColorType::Rgba8,
let color_type = match color_type {
ExtendedColorType::L8 => image_webp::ColorType::L8,
ExtendedColorType::La8 => image_webp::ColorType::La8,
ExtendedColorType::Rgb8 => image_webp::ColorType::Rgb8,
ExtendedColorType::Rgba8 => image_webp::ColorType::Rgba8,
_ => {
return Err(ImageError::Unsupported(
UnsupportedError::from_format_and_kind(
ImageFormat::WebP.into(),
UnsupportedErrorKind::Color(color.into()),
UnsupportedErrorKind::Color(color_type),
),
))
}
};
self.inner
.encode(data, width, height, color)
.encode(buf, width, height, color_type)
.map_err(ImageError::from_webp_encode)
}
}
@ -68,7 +73,7 @@ impl<W: Write> ImageEncoder for WebPEncoder<W> {
buf: &[u8],
width: u32,
height: u32,
color_type: ColorType,
color_type: ExtendedColorType,
) -> ImageResult<()> {
self.encode(buf, width, height, color_type)
}
@ -97,7 +102,7 @@ mod tests {
img.inner_pixels(),
img.width(),
img.height(),
crate::ColorType::Rgba8,
crate::ExtendedColorType::Rgba8,
)
.unwrap();

View file

@ -187,6 +187,46 @@ impl ExtendedColorType {
| ExtendedColorType::Cmyk8 => 4,
}
}
/// Returns the number of bits per pixel for this color type.
pub fn bits_per_pixel(&self) -> u16 {
match *self {
ExtendedColorType::A8 => 8,
ExtendedColorType::L1 => 1,
ExtendedColorType::La1 => 2,
ExtendedColorType::Rgb1 => 3,
ExtendedColorType::Rgba1 => 4,
ExtendedColorType::L2 => 2,
ExtendedColorType::La2 => 4,
ExtendedColorType::Rgb2 => 6,
ExtendedColorType::Rgba2 => 8,
ExtendedColorType::L4 => 4,
ExtendedColorType::La4 => 8,
ExtendedColorType::Rgb4 => 12,
ExtendedColorType::Rgba4 => 16,
ExtendedColorType::L8 => 8,
ExtendedColorType::La8 => 16,
ExtendedColorType::Rgb8 => 24,
ExtendedColorType::Rgba8 => 32,
ExtendedColorType::L16 => 16,
ExtendedColorType::La16 => 32,
ExtendedColorType::Rgb16 => 48,
ExtendedColorType::Rgba16 => 64,
ExtendedColorType::Rgb32F => 96,
ExtendedColorType::Rgba32F => 128,
ExtendedColorType::Bgr8 => 24,
ExtendedColorType::Bgra8 => 32,
ExtendedColorType::Cmyk8 => 32,
ExtendedColorType::Unknown(bpp) => bpp as u16,
}
}
/// Returns the number of bytes required to hold a width x height image of this color type.
pub(crate) fn buffer_size(self, width: u32, height: u32) -> u64 {
let bpp = self.bits_per_pixel() as u64;
let row_pitch = (width as u64 * bpp + 7) / 8;
row_pitch.saturating_mul(height as u64)
}
}
impl From<ColorType> for ExtendedColorType {
fn from(c: ColorType) -> Self {

View file

@ -15,11 +15,11 @@ use crate::color::{self, IntoColor};
use crate::error::{ImageError, ImageResult, ParameterError, ParameterErrorKind};
use crate::flat::FlatSamples;
use crate::image::{GenericImage, GenericImageView, ImageDecoder, ImageEncoder, ImageFormat};
use crate::imageops;
use crate::io::free_functions;
use crate::math::resize_dimensions;
use crate::traits::Pixel;
use crate::{image, Luma, LumaA};
use crate::{imageops, ExtendedColorType};
use crate::{Rgb32FImage, Rgba32FImage};
/// A Dynamic Image
@ -819,7 +819,7 @@ impl DynamicImage {
pub fn write_to<W: Write + Seek>(&self, w: &mut W, format: ImageFormat) -> ImageResult<()> {
let bytes = self.inner_bytes();
let (width, height) = self.dimensions();
let color = self.color();
let color: ExtendedColorType = self.color().into();
// TODO do not repeat this match statement across the crate
@ -1108,18 +1108,15 @@ where
///
/// This will lead to corrupted files if the buffer contains malformed data. Currently only
/// jpeg, png, ico, pnm, bmp, exr and tiff files are supported.
pub fn save_buffer<P>(
path: P,
pub fn save_buffer(
path: impl AsRef<Path>,
buf: &[u8],
width: u32,
height: u32,
color: color::ColorType,
) -> ImageResult<()>
where
P: AsRef<Path>,
{
color: impl Into<ExtendedColorType>,
) -> ImageResult<()> {
// thin wrapper function to strip generics before calling save_buffer_impl
free_functions::save_buffer_impl(path.as_ref(), buf, width, height, color)
free_functions::save_buffer_impl(path.as_ref(), buf, width, height, color.into())
}
/// Saves the supplied buffer to a file at the path specified
@ -1130,19 +1127,23 @@ where
/// This will lead to corrupted files if the buffer contains
/// malformed data. Currently only jpeg, png, ico, bmp, exr and
/// tiff files are supported.
pub fn save_buffer_with_format<P>(
path: P,
pub fn save_buffer_with_format(
path: impl AsRef<Path>,
buf: &[u8],
width: u32,
height: u32,
color: color::ColorType,
color: impl Into<ExtendedColorType>,
format: ImageFormat,
) -> ImageResult<()>
where
P: AsRef<Path>,
{
) -> ImageResult<()> {
// thin wrapper function to strip generics
free_functions::save_buffer_with_format_impl(path.as_ref(), buf, width, height, color, format)
free_functions::save_buffer_with_format_impl(
path.as_ref(),
buf,
width,
height,
color.into(),
format,
)
}
/// Writes the supplied buffer to a writer in the specified format.
@ -1157,19 +1158,16 @@ where
///
/// Assumes the writer is buffered. In most cases,
/// you should wrap your writer in a `BufWriter` for best performance.
pub fn write_buffer_with_format<W>(
pub fn write_buffer_with_format<W: Write + Seek>(
buffered_writer: &mut W,
buf: &[u8],
width: u32,
height: u32,
color: color::ColorType,
color: impl Into<ExtendedColorType>,
format: ImageFormat,
) -> ImageResult<()>
where
W: Write + Seek,
{
) -> ImageResult<()> {
// thin wrapper function to strip generics
free_functions::write_buffer_impl(buffered_writer, buf, width, height, color, format)
free_functions::write_buffer_impl(buffered_writer, buf, width, height, color.into(), format)
}
/// Create a new image from a byte slice

View file

@ -1,5 +1,4 @@
#![allow(clippy::too_many_arguments)]
use std::convert::TryFrom;
use std::ffi::OsStr;
use std::io::{self, Write};
use std::ops::{Deref, DerefMut};
@ -770,7 +769,7 @@ pub trait ImageEncoder {
buf: &[u8],
width: u32,
height: u32,
color_type: ColorType,
color_type: ExtendedColorType,
) -> ImageResult<()>;
}

View file

@ -546,7 +546,7 @@ where
mod test {
use super::*;
use crate::{GrayImage, ImageBuffer};
use crate::GrayImage;
macro_rules! assert_pixels_eq {
($actual:expr, $expected:expr) => {{

View file

@ -3,17 +3,14 @@ use std::io::{BufRead, BufWriter, Seek};
use std::path::Path;
use std::u32;
use crate::codecs::*;
use crate::{codecs::*, ExtendedColorType};
use crate::dynimage::DynamicImage;
use crate::error::{ImageError, ImageFormatHint, ImageResult};
use crate::error::{UnsupportedError, UnsupportedErrorKind};
use crate::image::ImageFormat;
#[allow(unused_imports)] // When no features are supported
use crate::image::{ImageDecoder, ImageEncoder};
use crate::{
color,
error::{UnsupportedError, UnsupportedErrorKind},
};
/// Create a new image from a Reader.
///
@ -36,7 +33,7 @@ pub(crate) fn save_buffer_impl(
buf: &[u8],
width: u32,
height: u32,
color: color::ColorType,
color: ExtendedColorType,
) -> ImageResult<()> {
let format = ImageFormat::from_path(path)?;
save_buffer_with_format_impl(path, buf, width, height, color, format)
@ -49,7 +46,7 @@ pub(crate) fn save_buffer_with_format_impl(
buf: &[u8],
width: u32,
height: u32,
color: color::ColorType,
color: ExtendedColorType,
format: ImageFormat,
) -> ImageResult<()> {
let buffered_file_write = &mut BufWriter::new(File::create(path)?); // always seekable
@ -63,7 +60,7 @@ pub(crate) fn write_buffer_impl<W: std::io::Write + Seek>(
buf: &[u8],
width: u32,
height: u32,
color: color::ColorType,
color: ExtendedColorType,
format: ImageFormat,
) -> ImageResult<()> {
match format {

View file

@ -1,7 +1,5 @@
//! Input and output of images.
use std::convert::TryFrom;
use crate::{error, ColorType, ImageError, ImageResult};
pub(crate) mod free_functions;

View file

@ -5,7 +5,10 @@
use num_traits::{Bounded, Num, NumCast};
use std::ops::AddAssign;
use crate::color::{ColorType, Luma, LumaA, Rgb, Rgba};
use crate::{
color::{Luma, LumaA, Rgb, Rgba},
ExtendedColorType,
};
/// Types which are safe to treat as an immutable byte slice in a pixel layout
/// for image encoding.
@ -173,40 +176,40 @@ pub trait PixelWithColorType: Pixel + self::private::SealedPixelWithColorType {
/// such as `Rgb8`, `La16` or `Rgba32F`.
/// This is needed for automatically detecting
/// a color format when saving an image as a file.
const COLOR_TYPE: ColorType;
const COLOR_TYPE: ExtendedColorType;
}
impl PixelWithColorType for Rgb<u8> {
const COLOR_TYPE: ColorType = ColorType::Rgb8;
const COLOR_TYPE: ExtendedColorType = ExtendedColorType::Rgb8;
}
impl PixelWithColorType for Rgb<u16> {
const COLOR_TYPE: ColorType = ColorType::Rgb16;
const COLOR_TYPE: ExtendedColorType = ExtendedColorType::Rgb16;
}
impl PixelWithColorType for Rgb<f32> {
const COLOR_TYPE: ColorType = ColorType::Rgb32F;
const COLOR_TYPE: ExtendedColorType = ExtendedColorType::Rgb32F;
}
impl PixelWithColorType for Rgba<u8> {
const COLOR_TYPE: ColorType = ColorType::Rgba8;
const COLOR_TYPE: ExtendedColorType = ExtendedColorType::Rgba8;
}
impl PixelWithColorType for Rgba<u16> {
const COLOR_TYPE: ColorType = ColorType::Rgba16;
const COLOR_TYPE: ExtendedColorType = ExtendedColorType::Rgba16;
}
impl PixelWithColorType for Rgba<f32> {
const COLOR_TYPE: ColorType = ColorType::Rgba32F;
const COLOR_TYPE: ExtendedColorType = ExtendedColorType::Rgba32F;
}
impl PixelWithColorType for Luma<u8> {
const COLOR_TYPE: ColorType = ColorType::L8;
const COLOR_TYPE: ExtendedColorType = ExtendedColorType::L8;
}
impl PixelWithColorType for Luma<u16> {
const COLOR_TYPE: ColorType = ColorType::L16;
const COLOR_TYPE: ExtendedColorType = ExtendedColorType::L16;
}
impl PixelWithColorType for LumaA<u8> {
const COLOR_TYPE: ColorType = ColorType::La8;
const COLOR_TYPE: ExtendedColorType = ExtendedColorType::La8;
}
impl PixelWithColorType for LumaA<u16> {
const COLOR_TYPE: ColorType = ColorType::La16;
const COLOR_TYPE: ExtendedColorType = ExtendedColorType::La16;
}
/// Prevents down-stream users from implementing the `Primitive` trait

View file

@ -1,5 +1,4 @@
//! Compares the decoding results with reference renderings.
use std::convert::TryInto;
use std::fs;
use std::io;
use std::path::PathBuf;