diff --git a/README.md b/README.md index 547207e7bb..2f2de73a26 100644 --- a/README.md +++ b/README.md @@ -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() } ``` diff --git a/benches/encode.rs b/benches/encode.rs index f64e7701a5..8c1fd955db 100644 --- a/benches/encode.rs +++ b/benches/encode.rs @@ -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, im: &[u8], dims: u32, color: ColorType); - fn encode_bufvec(&self, into: &mut Vec, 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, im: &[u8], dims: u32, color: ExtendedColorType); + fn encode_bufvec(&self, into: &mut Vec, 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 Encoder for T { - fn encode_raw(&self, into: &mut Vec, im: &[u8], dims: u32, color: ColorType) { + fn encode_raw(&self, into: &mut Vec, im: &[u8], dims: u32, color: ExtendedColorType) { into.clear(); self.encode(into, im, dims, color); } - fn encode_bufvec(&self, into: &mut Vec, im: &[u8], dims: u32, color: ColorType) { + fn encode_bufvec(&self, into: &mut Vec, 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 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(); } diff --git a/fuzz/fuzzers/fuzzer_script_exr.rs b/fuzz/fuzzers/fuzzer_script_exr.rs index 645150ab37..c07d23ee15 100644 --- a/fuzz/fuzzers/fuzzer_script_exr.rs +++ b/fuzz/fuzzers/fuzzer_script_exr.rs @@ -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), ) -> 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))?; diff --git a/src/animation.rs b/src/animation.rs index 01a6c4d88f..f598eeeacc 100644 --- a/src/animation.rs +++ b/src/animation.rs @@ -1,5 +1,4 @@ use std::cmp::Ordering; -use std::iter::Iterator; use std::time::Duration; use crate::error::ImageResult; diff --git a/src/codecs/avif/decoder.rs b/src/codecs/avif/decoder.rs index 2914beb011..33318cdb28 100644 --- a/src/codecs/avif/decoder.rs +++ b/src/codecs/avif/decoder.rs @@ -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; diff --git a/src/codecs/avif/encoder.rs b/src/codecs/avif/encoder.rs index 900a10e648..c29e2d1a5e 100644 --- a/src/codecs/avif/encoder.rs +++ b/src/codecs/avif/encoder.rs @@ -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 ImageEncoder for AvifEncoder { 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 ImageEncoder for AvifEncoder { impl AvifEncoder { // 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 AvifEncoder { data: &'buf [u8], width: u32, height: u32, - color: ColorType, + color: ExtendedColorType, ) -> ImageResult> { // Error wrapping utility for color dependent buffer dimensions. fn try_from_raw( @@ -210,7 +209,7 @@ impl AvifEncoder { } 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::>(data, width, height)?; // Now, internally ravif uses u32 but it takes usize. We could do some checked @@ -227,7 +226,7 @@ impl AvifEncoder { 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::>(data, width, height)?; // Now, internally ravif uses u32 but it takes usize. We could do some checked @@ -245,31 +244,31 @@ impl AvifEncoder { ))) } // we need a separate buffer.. - ColorType::L8 => { + ExtendedColorType::L8 => { let image = try_from_raw::>(data, width, height)?; Ok(RgbColor::Rgba8(convert_into(fallback, image))) } - ColorType::La8 => { + ExtendedColorType::La8 => { let image = try_from_raw::>(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::>(&buffer, width, height)?; Ok(RgbColor::Rgba8(convert_into(fallback, image))) } - ColorType::La16 => { + ExtendedColorType::La16 => { let buffer = cast_buffer(data)?; let image = try_from_raw::>(&buffer, width, height)?; Ok(RgbColor::Rgba8(convert_into(fallback, image))) } - ColorType::Rgb16 => { + ExtendedColorType::Rgb16 => { let buffer = cast_buffer(data)?; let image = try_from_raw::>(&buffer, width, height)?; Ok(RgbColor::Rgba8(convert_into(fallback, image))) } - ColorType::Rgba16 => { + ExtendedColorType::Rgba16 => { let buffer = cast_buffer(data)?; let image = try_from_raw::>(&buffer, width, height)?; Ok(RgbColor::Rgba8(convert_into(fallback, image))) @@ -278,7 +277,7 @@ impl AvifEncoder { _ => Err(ImageError::Unsupported( UnsupportedError::from_format_and_kind( ImageFormat::Avif.into(), - UnsupportedErrorKind::Color(color.into()), + UnsupportedErrorKind::Color(color), ), )), } diff --git a/src/codecs/bmp/decoder.rs b/src/codecs/bmp/decoder.rs index 1b4c5e6992..1154976572 100644 --- a/src/codecs/bmp/decoder.rs +++ b/src/codecs/bmp/decoder.rs @@ -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}; diff --git a/src/codecs/bmp/encoder.rs b/src/codecs/bmp/encoder.rs index c3e1ae08f4..512d25ace5 100644 --- a/src/codecs/bmp/encoder.rs +++ b/src/codecs/bmp/encoder.rs @@ -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 { + fn round_trip_image(image: &[u8], width: u32, height: u32, c: ExtendedColorType) -> Vec { 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]); diff --git a/src/codecs/dxt.rs b/src/codecs/dxt.rs index 48ecf1f8a1..108f6e1a64 100644 --- a/src/codecs/dxt.rs +++ b/src/codecs/dxt.rs @@ -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; diff --git a/src/codecs/farbfeld.rs b/src/codecs/farbfeld.rs index 73416da36e..10950ce45b 100644 --- a/src/codecs/farbfeld.rs +++ b/src/codecs/farbfeld.rs @@ -16,15 +16,15 @@ //! # Related Links //! * - 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 { @@ -68,8 +68,8 @@ impl FarbfeldReader { 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 ImageEncoder for FarbfeldEncoder { 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), ), )); } diff --git a/src/codecs/gif.rs b/src/codecs/gif.rs index 28b9f4b1c3..b6946f3cdd 100644 --- a/src/codecs/gif.rs +++ b/src/codecs/gif.rs @@ -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 GifEncoder { 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), ), )), } diff --git a/src/codecs/hdr/decoder.rs b/src/codecs/hdr/decoder.rs index 4d7a176cdb..7a64d48355 100644 --- a/src/codecs/hdr/decoder.rs +++ b/src/codecs/hdr/decoder.rs @@ -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>(path: P) -> ::std::io::Result> #[cfg(test)] mod test { use super::*; - use std::io::Cursor; #[test] fn dimension_overflow() { diff --git a/src/codecs/ico/decoder.rs b/src/codecs/ico/decoder.rs index df26ebe397..760ac0bec0 100644 --- a/src/codecs/ico/decoder.rs +++ b/src/codecs/ico/decoder.rs @@ -1,5 +1,4 @@ use byteorder::{LittleEndian, ReadBytesExt}; -use std::convert::TryFrom; use std::io::{Read, Seek, SeekFrom}; use std::{error, fmt}; diff --git a/src/codecs/ico/encoder.rs b/src/codecs/ico/encoder.rs index c9242ac899..88facebff8 100644 --- a/src/codecs/ico/encoder.rs +++ b/src/codecs/ico/encoder.rs @@ -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>, width: u32, height: u32, - color_type: ColorType, + color_type: ExtendedColorType, ) -> ImageResult { 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 { + pub fn as_png( + buf: &[u8], + width: u32, + height: u32, + color_type: ExtendedColorType, + ) -> ImageResult { let mut image_data: Vec = Vec::new(); PngEncoder::new(&mut image_data).write_image(buf, width, height, color_type)?; @@ -136,10 +141,9 @@ impl ImageEncoder for IcoEncoder { 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: &mut W, width: u8, height: u8, - color: ColorType, + color: ExtendedColorType, data_start: u32, data_size: u32, ) -> io::Result<()> { diff --git a/src/codecs/jpeg/encoder.rs b/src/codecs/jpeg/encoder.rs index 21f12a13b4..ebf2532524 100644 --- a/src/codecs/jpeg/encoder.rs +++ b/src/codecs/jpeg/encoder.rs @@ -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 JpegEncoder { 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 JpegEncoder { ); match color_type { - ColorType::L8 => { + ExtendedColorType::L8 => { let image: ImageBuffer, _> = ImageBuffer::from_raw(width, height, image).unwrap(); self.encode_image(&image) } - ColorType::La8 => { + ExtendedColorType::La8 => { let image: ImageBuffer, _> = ImageBuffer::from_raw(width, height, image).unwrap(); self.encode_image(&image) } - ColorType::Rgb8 => { + ExtendedColorType::Rgb8 => { let image: ImageBuffer, _> = ImageBuffer::from_raw(width, height, image).unwrap(); self.encode_image(&image) } - ColorType::Rgba8 => { + ExtendedColorType::Rgba8 => { let image: ImageBuffer, _> = ImageBuffer::from_raw(width, height, image).unwrap(); self.encode_image(&image) @@ -481,7 +479,7 @@ impl JpegEncoder { _ => 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 JpegEncoder { 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 ImageEncoder for JpegEncoder { 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) diff --git a/src/codecs/openexr.rs b/src/codecs/openexr.rs index deae32b4d7..86ca2a9298 100644 --- a/src/codecs/openexr.rs +++ b/src/codecs/openexr.rs @@ -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, ) } diff --git a/src/codecs/png.rs b/src/codecs/png.rs index b0d51bc01f..8458b8d060 100644 --- a/src/codecs/png.rs +++ b/src/codecs/png.rs @@ -6,7 +6,6 @@ //! * - 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 PngEncoder { @@ -542,22 +541,22 @@ impl PngEncoder { 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 ImageEncoder for PngEncoder { 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() { diff --git a/src/codecs/pnm/decoder.rs b/src/codecs/pnm/decoder.rs index 7a7f0b6386..1c619c6fb1 100644 --- a/src/codecs/pnm/decoder.rs +++ b/src/codecs/pnm/decoder.rs @@ -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}; diff --git a/src/codecs/pnm/encoder.rs b/src/codecs/pnm/encoder.rs index 87c62f730a..bd86cdb52a 100644 --- a/src/codecs/pnm/encoder.rs +++ b/src/codecs/pnm/encoder.rs @@ -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 PnmEncoder { image: S, width: u32, height: u32, - color: ColorType, + color: ExtendedColorType, ) -> ImageResult<()> where S: Into>, { 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 ImageEncoder for PnmEncoder { 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, diff --git a/src/codecs/pnm/mod.rs b/src/codecs/pnm/mod.rs index de8612d3eb..ac9d390fa9 100644 --- a/src/codecs/pnm/mod.rs +++ b/src/codecs/pnm/mod.rs @@ -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); } } diff --git a/src/codecs/qoi.rs b/src/codecs/qoi.rs index 2a47f63a10..809b9f9131 100644 --- a/src/codecs/qoi.rs +++ b/src/codecs/qoi.rs @@ -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 ImageEncoder for QoiEncoder { 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, diff --git a/src/codecs/tga/decoder.rs b/src/codecs/tga/decoder.rs index 0d0f47ad75..9da2392635 100644 --- a/src/codecs/tga/decoder.rs +++ b/src/codecs/tga/decoder.rs @@ -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 diff --git a/src/codecs/tga/encoder.rs b/src/codecs/tga/encoder.rs index 171dde7e30..ec74c905f8 100644 --- a/src/codecs/tga/encoder.rs +++ b/src/codecs/tga/encoder.rs @@ -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 TgaEncoder { } /// 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 TgaEncoder { 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 TgaEncoder { // 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 TgaEncoder { // 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 ImageEncoder for TgaEncoder { 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 ImageEncoder for TgaEncoder { #[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 { + fn round_trip_image( + image: &[u8], + width: u32, + height: u32, + c: ExtendedColorType, + ) -> Vec { 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 { + fn round_trip_image( + image: &[u8], + width: u32, + height: u32, + c: ExtendedColorType, + ) -> Vec { 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); } diff --git a/src/codecs/tga/header.rs b/src/codecs/tga/header.rs index c73770f24e..4460610100 100644 --- a/src/codecs/tga/header.rs +++ b/src/codecs/tga/header.rs @@ -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), ), )) } diff --git a/src/codecs/tiff.rs b/src/codecs/tiff.rs index d69a0c2532..d6426fd53f 100644 --- a/src/codecs/tiff.rs +++ b/src/codecs/tiff.rs @@ -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 TiffEncoder { /// /// 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::(width, height, data) + match color_type { + ExtendedColorType::L8 => { + encoder.write_image::(width, height, buf) } - ColorType::Rgb8 => { - encoder.write_image::(width, height, data) + ExtendedColorType::Rgb8 => { + encoder.write_image::(width, height, buf) } - ColorType::Rgba8 => { - encoder.write_image::(width, height, data) + ExtendedColorType::Rgba8 => { + encoder.write_image::(width, height, buf) } - ColorType::L16 => encoder.write_image::( + ExtendedColorType::L16 => encoder.write_image::( width, height, - u8_slice_as_u16(data)?, + u8_slice_as_u16(buf)?, ), - ColorType::Rgb16 => encoder.write_image::( + ExtendedColorType::Rgb16 => encoder.write_image::( width, height, - u8_slice_as_u16(data)?, + u8_slice_as_u16(buf)?, ), - ColorType::Rgba16 => encoder.write_image::( + ExtendedColorType::Rgba16 => encoder.write_image::( 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 ImageEncoder for TiffEncoder { buf: &[u8], width: u32, height: u32, - color_type: ColorType, + color_type: ExtendedColorType, ) -> ImageResult<()> { self.encode(buf, width, height, color_type) } diff --git a/src/codecs/webp/decoder.rs b/src/codecs/webp/decoder.rs index 3bacdc6379..df1985b84b 100644 --- a/src/codecs/webp/decoder.rs +++ b/src/codecs/webp/decoder.rs @@ -1,4 +1,3 @@ -use std::convert::TryFrom; use std::io::{Read, Seek}; use crate::buffer::ConvertBuffer; diff --git a/src/codecs/webp/encoder.rs b/src/codecs/webp/encoder.rs index 9d3b2acb2d..fbc87fddb5 100644 --- a/src/codecs/webp/encoder.rs +++ b/src/codecs/webp/encoder.rs @@ -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 WebPEncoder { /// /// 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 ImageEncoder for WebPEncoder { 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(); diff --git a/src/color.rs b/src/color.rs index a3cc9f9be9..d646b85272 100644 --- a/src/color.rs +++ b/src/color.rs @@ -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 for ExtendedColorType { fn from(c: ColorType) -> Self { diff --git a/src/dynimage.rs b/src/dynimage.rs index 1df1c2c596..2fd3b56a7c 100644 --- a/src/dynimage.rs +++ b/src/dynimage.rs @@ -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(&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

( - path: P, +pub fn save_buffer( + path: impl AsRef, buf: &[u8], width: u32, height: u32, - color: color::ColorType, -) -> ImageResult<()> -where - P: AsRef, -{ + color: impl Into, +) -> 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

( - path: P, +pub fn save_buffer_with_format( + path: impl AsRef, buf: &[u8], width: u32, height: u32, - color: color::ColorType, + color: impl Into, format: ImageFormat, -) -> ImageResult<()> -where - P: AsRef, -{ +) -> 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( +pub fn write_buffer_with_format( buffered_writer: &mut W, buf: &[u8], width: u32, height: u32, - color: color::ColorType, + color: impl Into, 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 diff --git a/src/image.rs b/src/image.rs index 20dd10561b..d5727de686 100644 --- a/src/image.rs +++ b/src/image.rs @@ -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<()>; } diff --git a/src/imageops/colorops.rs b/src/imageops/colorops.rs index b37c6e9d14..86d53ecaf5 100644 --- a/src/imageops/colorops.rs +++ b/src/imageops/colorops.rs @@ -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) => {{ diff --git a/src/io/free_functions.rs b/src/io/free_functions.rs index f810bd396b..ef4bac0d68 100644 --- a/src/io/free_functions.rs +++ b/src/io/free_functions.rs @@ -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( buf: &[u8], width: u32, height: u32, - color: color::ColorType, + color: ExtendedColorType, format: ImageFormat, ) -> ImageResult<()> { match format { diff --git a/src/io/mod.rs b/src/io/mod.rs index e6c85f49a5..7f27dd26da 100644 --- a/src/io/mod.rs +++ b/src/io/mod.rs @@ -1,7 +1,5 @@ //! Input and output of images. -use std::convert::TryFrom; - use crate::{error, ColorType, ImageError, ImageResult}; pub(crate) mod free_functions; diff --git a/src/traits.rs b/src/traits.rs index 56daaa0ddf..fba0c4eedf 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -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 { - const COLOR_TYPE: ColorType = ColorType::Rgb8; + const COLOR_TYPE: ExtendedColorType = ExtendedColorType::Rgb8; } impl PixelWithColorType for Rgb { - const COLOR_TYPE: ColorType = ColorType::Rgb16; + const COLOR_TYPE: ExtendedColorType = ExtendedColorType::Rgb16; } impl PixelWithColorType for Rgb { - const COLOR_TYPE: ColorType = ColorType::Rgb32F; + const COLOR_TYPE: ExtendedColorType = ExtendedColorType::Rgb32F; } impl PixelWithColorType for Rgba { - const COLOR_TYPE: ColorType = ColorType::Rgba8; + const COLOR_TYPE: ExtendedColorType = ExtendedColorType::Rgba8; } impl PixelWithColorType for Rgba { - const COLOR_TYPE: ColorType = ColorType::Rgba16; + const COLOR_TYPE: ExtendedColorType = ExtendedColorType::Rgba16; } impl PixelWithColorType for Rgba { - const COLOR_TYPE: ColorType = ColorType::Rgba32F; + const COLOR_TYPE: ExtendedColorType = ExtendedColorType::Rgba32F; } impl PixelWithColorType for Luma { - const COLOR_TYPE: ColorType = ColorType::L8; + const COLOR_TYPE: ExtendedColorType = ExtendedColorType::L8; } impl PixelWithColorType for Luma { - const COLOR_TYPE: ColorType = ColorType::L16; + const COLOR_TYPE: ExtendedColorType = ExtendedColorType::L16; } impl PixelWithColorType for LumaA { - const COLOR_TYPE: ColorType = ColorType::La8; + const COLOR_TYPE: ExtendedColorType = ExtendedColorType::La8; } impl PixelWithColorType for LumaA { - const COLOR_TYPE: ColorType = ColorType::La16; + const COLOR_TYPE: ExtendedColorType = ExtendedColorType::La16; } /// Prevents down-stream users from implementing the `Primitive` trait diff --git a/tests/reference_images.rs b/tests/reference_images.rs index 651884b21f..2f10a5f8ee 100644 --- a/tests/reference_images.rs +++ b/tests/reference_images.rs @@ -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;