aboutsummaryrefslogtreecommitdiff
path: root/vendor/image/src/codecs/avif
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/image/src/codecs/avif')
-rw-r--r--vendor/image/src/codecs/avif/decoder.rs177
-rw-r--r--vendor/image/src/codecs/avif/encoder.rs274
-rw-r--r--vendor/image/src/codecs/avif/mod.rs14
3 files changed, 0 insertions, 465 deletions
diff --git a/vendor/image/src/codecs/avif/decoder.rs b/vendor/image/src/codecs/avif/decoder.rs
deleted file mode 100644
index acba4f8..0000000
--- a/vendor/image/src/codecs/avif/decoder.rs
+++ /dev/null
@@ -1,177 +0,0 @@
-//! Decoding of AVIF images.
-///
-/// 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::{self, Cursor, Read};
-use std::marker::PhantomData;
-use std::mem;
-
-use crate::error::DecodingError;
-use crate::{ColorType, ImageDecoder, ImageError, ImageFormat, ImageResult};
-
-use dav1d::{PixelLayout, PlanarImageComponent};
-use dcv_color_primitives as dcp;
-use mp4parse::{read_avif, ParseStrictness};
-
-fn error_map<E: Into<Box<dyn Error + Send + Sync>>>(err: E) -> ImageError {
- ImageError::Decoding(DecodingError::new(ImageFormat::Avif.into(), err))
-}
-
-/// AVIF Decoder.
-///
-/// Reads one image into the chosen input.
-pub struct AvifDecoder<R> {
- inner: PhantomData<R>,
- picture: dav1d::Picture,
- alpha_picture: Option<dav1d::Picture>,
- icc_profile: Option<Vec<u8>>,
-}
-
-impl<R: Read> AvifDecoder<R> {
- /// Create a new decoder that reads its input from `r`.
- pub fn new(mut r: R) -> ImageResult<Self> {
- let ctx = read_avif(&mut r, ParseStrictness::Normal).map_err(error_map)?;
- let coded = ctx.primary_item_coded_data().unwrap_or_default();
-
- let mut primary_decoder = dav1d::Decoder::new();
- primary_decoder
- .send_data(coded, None, None, None)
- .map_err(error_map)?;
- let picture = primary_decoder.get_picture().map_err(error_map)?;
- let alpha_item = ctx.alpha_item_coded_data().unwrap_or_default();
- let alpha_picture = if !alpha_item.is_empty() {
- let mut alpha_decoder = dav1d::Decoder::new();
- alpha_decoder
- .send_data(alpha_item, None, None, None)
- .map_err(error_map)?;
- Some(alpha_decoder.get_picture().map_err(error_map)?)
- } else {
- None
- };
- let icc_profile = ctx
- .icc_colour_information()
- .map(|x| x.ok().unwrap_or_default())
- .map(|x| x.to_vec());
-
- assert_eq!(picture.bit_depth(), 8);
- Ok(AvifDecoder {
- inner: PhantomData,
- picture,
- alpha_picture,
- icc_profile,
- })
- }
-}
-
-/// Wrapper struct around a `Cursor<Vec<u8>>`
-pub struct AvifReader<R>(Cursor<Vec<u8>>, PhantomData<R>);
-impl<R> Read for AvifReader<R> {
- fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
- self.0.read(buf)
- }
- fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
- if self.0.position() == 0 && buf.is_empty() {
- mem::swap(buf, self.0.get_mut());
- Ok(buf.len())
- } else {
- self.0.read_to_end(buf)
- }
- }
-}
-
-impl<'a, R: 'a + Read> ImageDecoder<'a> for AvifDecoder<R> {
- type Reader = AvifReader<R>;
-
- fn dimensions(&self) -> (u32, u32) {
- (self.picture.width(), self.picture.height())
- }
-
- fn color_type(&self) -> ColorType {
- ColorType::Rgba8
- }
-
- fn icc_profile(&mut self) -> Option<Vec<u8>> {
- self.icc_profile.clone()
- }
-
- fn into_reader(self) -> ImageResult<Self::Reader> {
- let plane = self.picture.plane(PlanarImageComponent::Y);
- Ok(AvifReader(
- Cursor::new(plane.as_ref().to_vec()),
- PhantomData,
- ))
- }
-
- fn read_image(self, buf: &mut [u8]) -> ImageResult<()> {
- assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes()));
-
- dcp::initialize();
-
- if self.picture.pixel_layout() != PixelLayout::I400 {
- let pixel_format = match self.picture.pixel_layout() {
- PixelLayout::I400 => todo!(),
- PixelLayout::I420 => dcp::PixelFormat::I420,
- PixelLayout::I422 => dcp::PixelFormat::I422,
- PixelLayout::I444 => dcp::PixelFormat::I444,
- PixelLayout::Unknown => panic!("Unknown pixel layout"),
- };
- let src_format = dcp::ImageFormat {
- pixel_format,
- color_space: dcp::ColorSpace::Bt601,
- num_planes: 3,
- };
- let dst_format = dcp::ImageFormat {
- pixel_format: dcp::PixelFormat::Rgba,
- color_space: dcp::ColorSpace::Lrgb,
- num_planes: 1,
- };
- let (width, height) = self.dimensions();
- let planes = &[
- self.picture.plane(PlanarImageComponent::Y),
- self.picture.plane(PlanarImageComponent::U),
- self.picture.plane(PlanarImageComponent::V),
- ];
- let src_buffers = planes.iter().map(AsRef::as_ref).collect::<Vec<_>>();
- let strides = &[
- self.picture.stride(PlanarImageComponent::Y) as usize,
- self.picture.stride(PlanarImageComponent::U) as usize,
- self.picture.stride(PlanarImageComponent::V) as usize,
- ];
- let dst_buffers = &mut [&mut buf[..]];
- dcp::convert_image(
- width,
- height,
- &src_format,
- Some(strides),
- &src_buffers,
- &dst_format,
- None,
- dst_buffers,
- )
- .map_err(error_map)?;
- } else {
- let plane = self.picture.plane(PlanarImageComponent::Y);
- buf.copy_from_slice(plane.as_ref());
- }
-
- if let Some(picture) = self.alpha_picture {
- assert_eq!(picture.pixel_layout(), PixelLayout::I400);
- let stride = picture.stride(PlanarImageComponent::Y) as usize;
- let plane = picture.plane(PlanarImageComponent::Y);
- let width = picture.width();
- for (buf, slice) in Iterator::zip(
- buf.chunks_exact_mut(width as usize * 4),
- plane.as_ref().chunks_exact(stride),
- ) {
- for i in 0..width as usize {
- buf[3 + i * 4] = slice[i];
- }
- }
- }
-
- Ok(())
- }
-}
diff --git a/vendor/image/src/codecs/avif/encoder.rs b/vendor/image/src/codecs/avif/encoder.rs
deleted file mode 100644
index 7484ff1..0000000
--- a/vendor/image/src/codecs/avif/encoder.rs
+++ /dev/null
@@ -1,274 +0,0 @@
-//! Encoding of AVIF images.
-///
-/// The [AVIF] specification defines an image derivative of the AV1 bitstream, an open video codec.
-///
-/// [AVIF]: https://aomediacodec.github.io/av1-avif/
-use std::borrow::Cow;
-use std::cmp::min;
-use std::io::Write;
-
-use crate::buffer::ConvertBuffer;
-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::{ImageError, ImageResult};
-
-use bytemuck::{try_cast_slice, try_cast_slice_mut, Pod, PodCastError};
-use num_traits::Zero;
-use ravif::{Encoder, Img, RGB8, RGBA8};
-use rgb::AsPixels;
-
-/// AVIF Encoder.
-///
-/// Writes one image into the chosen output.
-pub struct AvifEncoder<W> {
- inner: W,
- encoder: Encoder,
-}
-
-/// An enumeration over supported AVIF color spaces
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-#[non_exhaustive]
-pub enum ColorSpace {
- /// sRGB colorspace
- Srgb,
- /// BT.709 colorspace
- Bt709,
-}
-
-impl ColorSpace {
- fn to_ravif(self) -> ravif::ColorSpace {
- match self {
- Self::Srgb => ravif::ColorSpace::RGB,
- Self::Bt709 => ravif::ColorSpace::YCbCr,
- }
- }
-}
-
-enum RgbColor<'buf> {
- Rgb8(Img<&'buf [RGB8]>),
- Rgba8(Img<&'buf [RGBA8]>),
-}
-
-impl<W: Write> AvifEncoder<W> {
- /// Create a new encoder that writes its output to `w`.
- pub fn new(w: W) -> Self {
- AvifEncoder::new_with_speed_quality(w, 4, 80) // `cavif` uses these defaults
- }
-
- /// Create a new encoder with specified speed and quality, that writes its output to `w`.
- /// `speed` accepts a value in the range 0-10, where 0 is the slowest and 10 is the fastest.
- /// `quality` accepts a value in the range 0-100, where 0 is the worst and 100 is the best.
- pub fn new_with_speed_quality(w: W, speed: u8, quality: u8) -> Self {
- // Clamp quality and speed to range
- let quality = min(quality, 100);
- let speed = min(speed, 10);
-
- let encoder = Encoder::new()
- .with_quality(f32::from(quality))
- .with_alpha_quality(f32::from(quality))
- .with_speed(speed);
-
- AvifEncoder { inner: w, encoder }
- }
-
- /// Encode with the specified `color_space`.
- pub fn with_colorspace(mut self, color_space: ColorSpace) -> Self {
- self.encoder = self
- .encoder
- .with_internal_color_space(color_space.to_ravif());
- self
- }
-
- /// Configures `rayon` thread pool size.
- /// The default `None` is to use all threads in the default `rayon` thread pool.
- pub fn with_num_threads(mut self, num_threads: Option<usize>) -> Self {
- self.encoder = self.encoder.with_num_threads(num_threads);
- self
- }
-}
-
-impl<W: Write> ImageEncoder for AvifEncoder<W> {
- /// Encode image data with the indicated color type.
- ///
- /// The encoder currently requires all data to be RGBA8, it will be converted internally if
- /// necessary. When data is suitably aligned, i.e. u16 channels to two bytes, then the
- /// conversion may be more efficient.
- fn write_image(
- mut self,
- data: &[u8],
- width: u32,
- height: u32,
- color: ColorType,
- ) -> ImageResult<()> {
- self.set_color(color);
- // `ravif` needs strongly typed data so let's convert. We can either use a temporarily
- // owned version in our own buffer or zero-copy if possible by using the input buffer.
- // This requires going through `rgb`.
- let mut fallback = vec![]; // This vector is used if we need to do a color conversion.
- let result = match Self::encode_as_img(&mut fallback, data, width, height, color)? {
- RgbColor::Rgb8(buffer) => self.encoder.encode_rgb(buffer),
- RgbColor::Rgba8(buffer) => self.encoder.encode_rgba(buffer),
- };
- let data = result.map_err(|err| {
- ImageError::Encoding(EncodingError::new(ImageFormat::Avif.into(), err))
- })?;
- self.inner.write_all(&data.avif_file)?;
- Ok(())
- }
-}
-
-impl<W: Write> AvifEncoder<W> {
- // Does not currently do anything. Mirrors behaviour of old config function.
- fn set_color(&mut self, _color: ColorType) {
- // self.config.color_space = ColorSpace::RGB;
- }
-
- fn encode_as_img<'buf>(
- fallback: &'buf mut Vec<u8>,
- data: &'buf [u8],
- width: u32,
- height: u32,
- color: ColorType,
- ) -> ImageResult<RgbColor<'buf>> {
- // Error wrapping utility for color dependent buffer dimensions.
- fn try_from_raw<P: Pixel + 'static>(
- data: &[P::Subpixel],
- width: u32,
- height: u32,
- ) -> ImageResult<ImageBuffer<P, &[P::Subpixel]>> {
- ImageBuffer::from_raw(width, height, data).ok_or_else(|| {
- ImageError::Parameter(ParameterError::from_kind(
- ParameterErrorKind::DimensionMismatch,
- ))
- })
- }
-
- // Convert to target color type using few buffer allocations.
- fn convert_into<'buf, P>(
- buf: &'buf mut Vec<u8>,
- image: ImageBuffer<P, &[P::Subpixel]>,
- ) -> Img<&'buf [RGBA8]>
- where
- P: Pixel + 'static,
- Rgba<u8>: FromColor<P>,
- {
- let (width, height) = image.dimensions();
- // TODO: conversion re-using the target buffer?
- let image: ImageBuffer<Rgba<u8>, _> = image.convert();
- *buf = image.into_raw();
- Img::new(buf.as_pixels(), width as usize, height as usize)
- }
-
- // Cast the input slice using few buffer allocations if possible.
- // In particular try not to allocate if the caller did the infallible reverse.
- fn cast_buffer<Channel>(buf: &[u8]) -> ImageResult<Cow<[Channel]>>
- where
- Channel: Pod + Zero,
- {
- match try_cast_slice(buf) {
- Ok(slice) => Ok(Cow::Borrowed(slice)),
- Err(PodCastError::OutputSliceWouldHaveSlop) => Err(ImageError::Parameter(
- ParameterError::from_kind(ParameterErrorKind::DimensionMismatch),
- )),
- Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned) => {
- // Sad, but let's allocate.
- // bytemuck checks alignment _before_ slop but size mismatch before this..
- if buf.len() % std::mem::size_of::<Channel>() != 0 {
- Err(ImageError::Parameter(ParameterError::from_kind(
- ParameterErrorKind::DimensionMismatch,
- )))
- } else {
- let len = buf.len() / std::mem::size_of::<Channel>();
- let mut data = vec![Channel::zero(); len];
- let view = try_cast_slice_mut::<_, u8>(data.as_mut_slice()).unwrap();
- view.copy_from_slice(buf);
- Ok(Cow::Owned(data))
- }
- }
- Err(err) => {
- // Are you trying to encode a ZST??
- Err(ImageError::Parameter(ParameterError::from_kind(
- ParameterErrorKind::Generic(format!("{:?}", err)),
- )))
- }
- }
- }
-
- match color {
- ColorType::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
- // conversion but instead we use that a non-empty image must be addressable.
- if img.pixels().len() == 0 {
- return Err(ImageError::Parameter(ParameterError::from_kind(
- ParameterErrorKind::DimensionMismatch,
- )));
- }
-
- Ok(RgbColor::Rgb8(Img::new(
- rgb::AsPixels::as_pixels(data),
- width as usize,
- height as usize,
- )))
- }
- ColorType::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
- // conversion but instead we use that a non-empty image must be addressable.
- if img.pixels().len() == 0 {
- return Err(ImageError::Parameter(ParameterError::from_kind(
- ParameterErrorKind::DimensionMismatch,
- )));
- }
-
- Ok(RgbColor::Rgba8(Img::new(
- rgb::AsPixels::as_pixels(data),
- width as usize,
- height as usize,
- )))
- }
- // we need a separate buffer..
- ColorType::L8 => {
- let image = try_from_raw::<Luma<u8>>(data, width, height)?;
- Ok(RgbColor::Rgba8(convert_into(fallback, image)))
- }
- ColorType::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 => {
- let buffer = cast_buffer(data)?;
- let image = try_from_raw::<Luma<u16>>(&buffer, width, height)?;
- Ok(RgbColor::Rgba8(convert_into(fallback, image)))
- }
- ColorType::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 => {
- let buffer = cast_buffer(data)?;
- let image = try_from_raw::<Rgb<u16>>(&buffer, width, height)?;
- Ok(RgbColor::Rgba8(convert_into(fallback, image)))
- }
- ColorType::Rgba16 => {
- let buffer = cast_buffer(data)?;
- let image = try_from_raw::<Rgba<u16>>(&buffer, width, height)?;
- Ok(RgbColor::Rgba8(convert_into(fallback, image)))
- }
- // for cases we do not support at all?
- _ => Err(ImageError::Unsupported(
- UnsupportedError::from_format_and_kind(
- ImageFormat::Avif.into(),
- UnsupportedErrorKind::Color(color.into()),
- ),
- )),
- }
- }
-}
diff --git a/vendor/image/src/codecs/avif/mod.rs b/vendor/image/src/codecs/avif/mod.rs
deleted file mode 100644
index f74217c..0000000
--- a/vendor/image/src/codecs/avif/mod.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-//! Encoding of AVIF images.
-///
-/// The [AVIF] specification defines an image derivative of the AV1 bitstream, an open video codec.
-///
-/// [AVIF]: https://aomediacodec.github.io/av1-avif/
-#[cfg(feature = "avif-decoder")]
-pub use self::decoder::AvifDecoder;
-#[cfg(feature = "avif-encoder")]
-pub use self::encoder::{AvifEncoder, ColorSpace};
-
-#[cfg(feature = "avif-decoder")]
-mod decoder;
-#[cfg(feature = "avif-encoder")]
-mod encoder;