Skip to content

Commit

Permalink
Use ExtendedColorType when encoding (#2142)
Browse files Browse the repository at this point in the history
  • Loading branch information
fintelia authored Feb 19, 2024
1 parent 3b1fbcf commit a0ebeab
Show file tree
Hide file tree
Showing 35 changed files with 353 additions and 335 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
```
26 changes: 13 additions & 13 deletions benches/encode.rs
Original file line number Diff line number Diff line change
@@ -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)]
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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());
}
}
}
Expand All @@ -97,37 +97,37 @@ 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);
}
}

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();
}
Expand Down
4 changes: 2 additions & 2 deletions fuzz/fuzzers/fuzzer_script_exr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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))?;
Expand Down
1 change: 0 additions & 1 deletion src/animation.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use std::cmp::Ordering;
use std::iter::Iterator;
use std::time::Duration;

use crate::error::ImageResult;
Expand Down
1 change: 0 additions & 1 deletion src/codecs/avif/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
29 changes: 14 additions & 15 deletions src/codecs/avif/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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,
Expand All @@ -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;
}

Expand All @@ -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>(
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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)))
Expand All @@ -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),
),
)),
}
Expand Down
3 changes: 1 addition & 2 deletions src/codecs/bmp/decoder.rs
Original file line number Diff line number Diff line change
@@ -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};

Expand Down
Loading

0 comments on commit a0ebeab

Please sign in to comment.