aboutsummaryrefslogtreecommitdiff
path: root/vendor/qoi/src
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/qoi/src')
-rw-r--r--vendor/qoi/src/consts.rs17
-rw-r--r--vendor/qoi/src/decode.rs396
-rw-r--r--vendor/qoi/src/encode.rs210
-rw-r--r--vendor/qoi/src/error.rs82
-rw-r--r--vendor/qoi/src/header.rs120
-rw-r--r--vendor/qoi/src/lib.rs95
-rw-r--r--vendor/qoi/src/pixel.rs183
-rw-r--r--vendor/qoi/src/types.rs113
-rw-r--r--vendor/qoi/src/utils.rs107
9 files changed, 0 insertions, 1323 deletions
diff --git a/vendor/qoi/src/consts.rs b/vendor/qoi/src/consts.rs
deleted file mode 100644
index 2281c24..0000000
--- a/vendor/qoi/src/consts.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-pub const QOI_OP_INDEX: u8 = 0x00; // 00xxxxxx
-pub const QOI_OP_DIFF: u8 = 0x40; // 01xxxxxx
-pub const QOI_OP_LUMA: u8 = 0x80; // 10xxxxxx
-pub const QOI_OP_RUN: u8 = 0xc0; // 11xxxxxx
-pub const QOI_OP_RGB: u8 = 0xfe; // 11111110
-pub const QOI_OP_RGBA: u8 = 0xff; // 11111111
-
-pub const QOI_MASK_2: u8 = 0xc0; // (11)000000
-
-pub const QOI_HEADER_SIZE: usize = 14;
-
-pub const QOI_PADDING: [u8; 8] = [0, 0, 0, 0, 0, 0, 0, 0x01]; // 7 zeros and one 0x01 marker
-pub const QOI_PADDING_SIZE: usize = 8;
-
-pub const QOI_MAGIC: u32 = u32::from_be_bytes(*b"qoif");
-
-pub const QOI_PIXELS_MAX: usize = 400_000_000;
diff --git a/vendor/qoi/src/decode.rs b/vendor/qoi/src/decode.rs
deleted file mode 100644
index 019dac2..0000000
--- a/vendor/qoi/src/decode.rs
+++ /dev/null
@@ -1,396 +0,0 @@
-#[cfg(any(feature = "std", feature = "alloc"))]
-use alloc::{vec, vec::Vec};
-#[cfg(feature = "std")]
-use std::io::Read;
-
-// TODO: can be removed once https://github.com/rust-lang/rust/issues/74985 is stable
-use bytemuck::{cast_slice_mut, Pod};
-
-use crate::consts::{
- QOI_HEADER_SIZE, QOI_OP_DIFF, QOI_OP_INDEX, QOI_OP_LUMA, QOI_OP_RGB, QOI_OP_RGBA, QOI_OP_RUN,
- QOI_PADDING, QOI_PADDING_SIZE,
-};
-use crate::error::{Error, Result};
-use crate::header::Header;
-use crate::pixel::{Pixel, SupportedChannels};
-use crate::types::Channels;
-use crate::utils::{cold, unlikely};
-
-const QOI_OP_INDEX_END: u8 = QOI_OP_INDEX | 0x3f;
-const QOI_OP_RUN_END: u8 = QOI_OP_RUN | 0x3d; // <- note, 0x3d (not 0x3f)
-const QOI_OP_DIFF_END: u8 = QOI_OP_DIFF | 0x3f;
-const QOI_OP_LUMA_END: u8 = QOI_OP_LUMA | 0x3f;
-
-#[inline]
-fn decode_impl_slice<const N: usize, const RGBA: bool>(data: &[u8], out: &mut [u8]) -> Result<usize>
-where
- Pixel<N>: SupportedChannels,
- [u8; N]: Pod,
-{
- let mut pixels = cast_slice_mut::<_, [u8; N]>(out);
- let data_len = data.len();
- let mut data = data;
-
- let mut index = [Pixel::<4>::new(); 256];
- let mut px = Pixel::<N>::new().with_a(0xff);
- let mut px_rgba: Pixel<4>;
-
- while let [px_out, ptail @ ..] = pixels {
- pixels = ptail;
- match data {
- [b1 @ QOI_OP_INDEX..=QOI_OP_INDEX_END, dtail @ ..] => {
- px_rgba = index[*b1 as usize];
- px.update(px_rgba);
- *px_out = px.into();
- data = dtail;
- continue;
- }
- [QOI_OP_RGB, r, g, b, dtail @ ..] => {
- px.update_rgb(*r, *g, *b);
- data = dtail;
- }
- [QOI_OP_RGBA, r, g, b, a, dtail @ ..] if RGBA => {
- px.update_rgba(*r, *g, *b, *a);
- data = dtail;
- }
- [b1 @ QOI_OP_RUN..=QOI_OP_RUN_END, dtail @ ..] => {
- *px_out = px.into();
- let run = ((b1 & 0x3f) as usize).min(pixels.len());
- let (phead, ptail) = pixels.split_at_mut(run); // can't panic
- phead.fill(px.into());
- pixels = ptail;
- data = dtail;
- continue;
- }
- [b1 @ QOI_OP_DIFF..=QOI_OP_DIFF_END, dtail @ ..] => {
- px.update_diff(*b1);
- data = dtail;
- }
- [b1 @ QOI_OP_LUMA..=QOI_OP_LUMA_END, b2, dtail @ ..] => {
- px.update_luma(*b1, *b2);
- data = dtail;
- }
- _ => {
- cold();
- if unlikely(data.len() < QOI_PADDING_SIZE) {
- return Err(Error::UnexpectedBufferEnd);
- }
- }
- }
-
- px_rgba = px.as_rgba(0xff);
- index[px_rgba.hash_index() as usize] = px_rgba;
- *px_out = px.into();
- }
-
- if unlikely(data.len() < QOI_PADDING_SIZE) {
- return Err(Error::UnexpectedBufferEnd);
- } else if unlikely(data[..QOI_PADDING_SIZE] != QOI_PADDING) {
- return Err(Error::InvalidPadding);
- }
-
- Ok(data_len.saturating_sub(data.len()).saturating_sub(QOI_PADDING_SIZE))
-}
-
-#[inline]
-fn decode_impl_slice_all(
- data: &[u8], out: &mut [u8], channels: u8, src_channels: u8,
-) -> Result<usize> {
- match (channels, src_channels) {
- (3, 3) => decode_impl_slice::<3, false>(data, out),
- (3, 4) => decode_impl_slice::<3, true>(data, out),
- (4, 3) => decode_impl_slice::<4, false>(data, out),
- (4, 4) => decode_impl_slice::<4, true>(data, out),
- _ => {
- cold();
- Err(Error::InvalidChannels { channels })
- }
- }
-}
-
-/// Decode the image into a pre-allocated buffer.
-///
-/// Note: the resulting number of channels will match the header. In order to change
-/// the number of channels, use [`Decoder::with_channels`].
-#[inline]
-pub fn decode_to_buf(buf: impl AsMut<[u8]>, data: impl AsRef<[u8]>) -> Result<Header> {
- let mut decoder = Decoder::new(&data)?;
- decoder.decode_to_buf(buf)?;
- Ok(*decoder.header())
-}
-
-/// Decode the image into a newly allocated vector.
-///
-/// Note: the resulting number of channels will match the header. In order to change
-/// the number of channels, use [`Decoder::with_channels`].
-#[cfg(any(feature = "std", feature = "alloc"))]
-#[inline]
-pub fn decode_to_vec(data: impl AsRef<[u8]>) -> Result<(Header, Vec<u8>)> {
- let mut decoder = Decoder::new(&data)?;
- let out = decoder.decode_to_vec()?;
- Ok((*decoder.header(), out))
-}
-
-/// Decode the image header from a slice of bytes.
-#[inline]
-pub fn decode_header(data: impl AsRef<[u8]>) -> Result<Header> {
- Header::decode(data)
-}
-
-#[cfg(any(feature = "std"))]
-#[inline]
-fn decode_impl_stream<R: Read, const N: usize, const RGBA: bool>(
- data: &mut R, out: &mut [u8],
-) -> Result<()>
-where
- Pixel<N>: SupportedChannels,
- [u8; N]: Pod,
-{
- let mut pixels = cast_slice_mut::<_, [u8; N]>(out);
-
- let mut index = [Pixel::<N>::new(); 256];
- let mut px = Pixel::<N>::new().with_a(0xff);
-
- while let [px_out, ptail @ ..] = pixels {
- pixels = ptail;
- let mut p = [0];
- data.read_exact(&mut p)?;
- let [b1] = p;
- match b1 {
- QOI_OP_INDEX..=QOI_OP_INDEX_END => {
- px = index[b1 as usize];
- *px_out = px.into();
- continue;
- }
- QOI_OP_RGB => {
- let mut p = [0; 3];
- data.read_exact(&mut p)?;
- px.update_rgb(p[0], p[1], p[2]);
- }
- QOI_OP_RGBA if RGBA => {
- let mut p = [0; 4];
- data.read_exact(&mut p)?;
- px.update_rgba(p[0], p[1], p[2], p[3]);
- }
- QOI_OP_RUN..=QOI_OP_RUN_END => {
- *px_out = px.into();
- let run = ((b1 & 0x3f) as usize).min(pixels.len());
- let (phead, ptail) = pixels.split_at_mut(run); // can't panic
- phead.fill(px.into());
- pixels = ptail;
- continue;
- }
- QOI_OP_DIFF..=QOI_OP_DIFF_END => {
- px.update_diff(b1);
- }
- QOI_OP_LUMA..=QOI_OP_LUMA_END => {
- let mut p = [0];
- data.read_exact(&mut p)?;
- let [b2] = p;
- px.update_luma(b1, b2);
- }
- _ => {
- cold();
- }
- }
-
- index[px.hash_index() as usize] = px;
- *px_out = px.into();
- }
-
- let mut p = [0_u8; QOI_PADDING_SIZE];
- data.read_exact(&mut p)?;
- if unlikely(p != QOI_PADDING) {
- return Err(Error::InvalidPadding);
- }
-
- Ok(())
-}
-
-#[cfg(feature = "std")]
-#[inline]
-fn decode_impl_stream_all<R: Read>(
- data: &mut R, out: &mut [u8], channels: u8, src_channels: u8,
-) -> Result<()> {
- match (channels, src_channels) {
- (3, 3) => decode_impl_stream::<_, 3, false>(data, out),
- (3, 4) => decode_impl_stream::<_, 3, true>(data, out),
- (4, 3) => decode_impl_stream::<_, 4, false>(data, out),
- (4, 4) => decode_impl_stream::<_, 4, true>(data, out),
- _ => {
- cold();
- Err(Error::InvalidChannels { channels })
- }
- }
-}
-
-#[doc(hidden)]
-pub trait Reader: Sized {
- fn decode_header(&mut self) -> Result<Header>;
- fn decode_image(&mut self, out: &mut [u8], channels: u8, src_channels: u8) -> Result<()>;
-}
-
-pub struct Bytes<'a>(&'a [u8]);
-
-impl<'a> Bytes<'a> {
- #[inline]
- pub const fn new(buf: &'a [u8]) -> Self {
- Self(buf)
- }
-
- #[inline]
- pub const fn as_slice(&self) -> &[u8] {
- self.0
- }
-}
-
-impl<'a> Reader for Bytes<'a> {
- #[inline]
- fn decode_header(&mut self) -> Result<Header> {
- let header = Header::decode(self.0)?;
- self.0 = &self.0[QOI_HEADER_SIZE..]; // can't panic
- Ok(header)
- }
-
- #[inline]
- fn decode_image(&mut self, out: &mut [u8], channels: u8, src_channels: u8) -> Result<()> {
- let n_read = decode_impl_slice_all(self.0, out, channels, src_channels)?;
- self.0 = &self.0[n_read..];
- Ok(())
- }
-}
-
-#[cfg(feature = "std")]
-impl<R: Read> Reader for R {
- #[inline]
- fn decode_header(&mut self) -> Result<Header> {
- let mut b = [0; QOI_HEADER_SIZE];
- self.read_exact(&mut b)?;
- Header::decode(b)
- }
-
- #[inline]
- fn decode_image(&mut self, out: &mut [u8], channels: u8, src_channels: u8) -> Result<()> {
- decode_impl_stream_all(self, out, channels, src_channels)
- }
-}
-
-/// Decode QOI images from slices or from streams.
-#[derive(Clone)]
-pub struct Decoder<R> {
- reader: R,
- header: Header,
- channels: Channels,
-}
-
-impl<'a> Decoder<Bytes<'a>> {
- /// Creates a new decoder from a slice of bytes.
- ///
- /// The header will be decoded immediately upon construction.
- ///
- /// Note: this provides the most efficient decoding, but requires the source data to
- /// be loaded in memory in order to decode it. In order to decode from a generic
- /// stream, use [`Decoder::from_stream`] instead.
- #[inline]
- pub fn new(data: &'a (impl AsRef<[u8]> + ?Sized)) -> Result<Self> {
- Self::new_impl(Bytes::new(data.as_ref()))
- }
-
- /// Returns the undecoded tail of the input slice of bytes.
- #[inline]
- pub const fn data(&self) -> &[u8] {
- self.reader.as_slice()
- }
-}
-
-#[cfg(feature = "std")]
-impl<R: Read> Decoder<R> {
- /// Creates a new decoder from a generic reader that implements [`Read`](std::io::Read).
- ///
- /// The header will be decoded immediately upon construction.
- ///
- /// Note: while it's possible to pass a `&[u8]` slice here since it implements `Read`, it
- /// would be more efficient to use a specialized constructor instead: [`Decoder::new`].
- #[inline]
- pub fn from_stream(reader: R) -> Result<Self> {
- Self::new_impl(reader)
- }
-
- /// Returns an immutable reference to the underlying reader.
- #[inline]
- pub const fn reader(&self) -> &R {
- &self.reader
- }
-
- /// Consumes the decoder and returns the underlying reader back.
- #[inline]
- #[allow(clippy::missing_const_for_fn)]
- pub fn into_reader(self) -> R {
- self.reader
- }
-}
-
-impl<R: Reader> Decoder<R> {
- #[inline]
- fn new_impl(mut reader: R) -> Result<Self> {
- let header = reader.decode_header()?;
- Ok(Self { reader, header, channels: header.channels })
- }
-
- /// Returns a new decoder with modified number of channels.
- ///
- /// By default, the number of channels in the decoded image will be equal
- /// to whatever is specified in the header. However, it is also possible
- /// to decode RGB into RGBA (in which case the alpha channel will be set
- /// to 255), and vice versa (in which case the alpha channel will be ignored).
- #[inline]
- pub const fn with_channels(mut self, channels: Channels) -> Self {
- self.channels = channels;
- self
- }
-
- /// Returns the number of channels in the decoded image.
- ///
- /// Note: this may differ from the number of channels specified in the header.
- #[inline]
- pub const fn channels(&self) -> Channels {
- self.channels
- }
-
- /// Returns the decoded image header.
- #[inline]
- pub const fn header(&self) -> &Header {
- &self.header
- }
-
- /// The number of bytes the decoded image will take.
- ///
- /// Can be used to pre-allocate the buffer to decode the image into.
- #[inline]
- pub const fn required_buf_len(&self) -> usize {
- self.header.n_pixels().saturating_mul(self.channels.as_u8() as usize)
- }
-
- /// Decodes the image to a pre-allocated buffer and returns the number of bytes written.
- ///
- /// The minimum size of the buffer can be found via [`Decoder::required_buf_len`].
- #[inline]
- pub fn decode_to_buf(&mut self, mut buf: impl AsMut<[u8]>) -> Result<usize> {
- let buf = buf.as_mut();
- let size = self.required_buf_len();
- if unlikely(buf.len() < size) {
- return Err(Error::OutputBufferTooSmall { size: buf.len(), required: size });
- }
- self.reader.decode_image(buf, self.channels.as_u8(), self.header.channels.as_u8())?;
- Ok(size)
- }
-
- /// Decodes the image into a newly allocated vector of bytes and returns it.
- #[cfg(any(feature = "std", feature = "alloc"))]
- #[inline]
- pub fn decode_to_vec(&mut self) -> Result<Vec<u8>> {
- let mut out = vec![0; self.header.n_pixels() * self.channels.as_u8() as usize];
- let _ = self.decode_to_buf(&mut out)?;
- Ok(out)
- }
-}
diff --git a/vendor/qoi/src/encode.rs b/vendor/qoi/src/encode.rs
deleted file mode 100644
index 0ed8476..0000000
--- a/vendor/qoi/src/encode.rs
+++ /dev/null
@@ -1,210 +0,0 @@
-#[cfg(any(feature = "std", feature = "alloc"))]
-use alloc::{vec, vec::Vec};
-use core::convert::TryFrom;
-#[cfg(feature = "std")]
-use std::io::Write;
-
-use bytemuck::Pod;
-
-use crate::consts::{QOI_HEADER_SIZE, QOI_OP_INDEX, QOI_OP_RUN, QOI_PADDING, QOI_PADDING_SIZE};
-use crate::error::{Error, Result};
-use crate::header::Header;
-use crate::pixel::{Pixel, SupportedChannels};
-use crate::types::{Channels, ColorSpace};
-#[cfg(feature = "std")]
-use crate::utils::GenericWriter;
-use crate::utils::{unlikely, BytesMut, Writer};
-
-#[allow(clippy::cast_possible_truncation, unused_assignments, unused_variables)]
-fn encode_impl<W: Writer, const N: usize>(mut buf: W, data: &[u8]) -> Result<usize>
-where
- Pixel<N>: SupportedChannels,
- [u8; N]: Pod,
-{
- let cap = buf.capacity();
-
- let mut index = [Pixel::new(); 256];
- let mut px_prev = Pixel::new().with_a(0xff);
- let mut hash_prev = px_prev.hash_index();
- let mut run = 0_u8;
- let mut px = Pixel::<N>::new().with_a(0xff);
- let mut index_allowed = false;
-
- let n_pixels = data.len() / N;
-
- for (i, chunk) in data.chunks_exact(N).enumerate() {
- px.read(chunk);
- if px == px_prev {
- run += 1;
- if run == 62 || unlikely(i == n_pixels - 1) {
- buf = buf.write_one(QOI_OP_RUN | (run - 1))?;
- run = 0;
- }
- } else {
- if run != 0 {
- #[cfg(not(feature = "reference"))]
- {
- // credits for the original idea: @zakarumych (had to be fixed though)
- buf = buf.write_one(if run == 1 && index_allowed {
- QOI_OP_INDEX | hash_prev
- } else {
- QOI_OP_RUN | (run - 1)
- })?;
- }
- #[cfg(feature = "reference")]
- {
- buf = buf.write_one(QOI_OP_RUN | (run - 1))?;
- }
- run = 0;
- }
- index_allowed = true;
- let px_rgba = px.as_rgba(0xff);
- hash_prev = px_rgba.hash_index();
- let index_px = &mut index[hash_prev as usize];
- if *index_px == px_rgba {
- buf = buf.write_one(QOI_OP_INDEX | hash_prev)?;
- } else {
- *index_px = px_rgba;
- buf = px.encode_into(px_prev, buf)?;
- }
- px_prev = px;
- }
- }
-
- buf = buf.write_many(&QOI_PADDING)?;
- Ok(cap.saturating_sub(buf.capacity()))
-}
-
-#[inline]
-fn encode_impl_all<W: Writer>(out: W, data: &[u8], channels: Channels) -> Result<usize> {
- match channels {
- Channels::Rgb => encode_impl::<_, 3>(out, data),
- Channels::Rgba => encode_impl::<_, 4>(out, data),
- }
-}
-
-/// The maximum number of bytes the encoded image will take.
-///
-/// Can be used to pre-allocate the buffer to encode the image into.
-#[inline]
-pub fn encode_max_len(width: u32, height: u32, channels: impl Into<u8>) -> usize {
- let (width, height) = (width as usize, height as usize);
- let n_pixels = width.saturating_mul(height);
- QOI_HEADER_SIZE
- + n_pixels.saturating_mul(channels.into() as usize)
- + n_pixels
- + QOI_PADDING_SIZE
-}
-
-/// Encode the image into a pre-allocated buffer.
-///
-/// Returns the total number of bytes written.
-#[inline]
-pub fn encode_to_buf(
- buf: impl AsMut<[u8]>, data: impl AsRef<[u8]>, width: u32, height: u32,
-) -> Result<usize> {
- Encoder::new(&data, width, height)?.encode_to_buf(buf)
-}
-
-/// Encode the image into a newly allocated vector.
-#[cfg(any(feature = "alloc", feature = "std"))]
-#[inline]
-pub fn encode_to_vec(data: impl AsRef<[u8]>, width: u32, height: u32) -> Result<Vec<u8>> {
- Encoder::new(&data, width, height)?.encode_to_vec()
-}
-
-/// Encode QOI images into buffers or into streams.
-pub struct Encoder<'a> {
- data: &'a [u8],
- header: Header,
-}
-
-impl<'a> Encoder<'a> {
- /// Creates a new encoder from a given array of pixel data and image dimensions.
- ///
- /// The number of channels will be inferred automatically (the valid values
- /// are 3 or 4). The color space will be set to sRGB by default.
- #[inline]
- #[allow(clippy::cast_possible_truncation)]
- pub fn new(data: &'a (impl AsRef<[u8]> + ?Sized), width: u32, height: u32) -> Result<Self> {
- let data = data.as_ref();
- let mut header =
- Header::try_new(width, height, Channels::default(), ColorSpace::default())?;
- let size = data.len();
- let n_channels = size / header.n_pixels();
- if header.n_pixels() * n_channels != size {
- return Err(Error::InvalidImageLength { size, width, height });
- }
- header.channels = Channels::try_from(n_channels.min(0xff) as u8)?;
- Ok(Self { data, header })
- }
-
- /// Returns a new encoder with modified color space.
- ///
- /// Note: the color space doesn't affect encoding or decoding in any way, it's
- /// a purely informative field that's stored in the image header.
- #[inline]
- pub const fn with_colorspace(mut self, colorspace: ColorSpace) -> Self {
- self.header = self.header.with_colorspace(colorspace);
- self
- }
-
- /// Returns the inferred number of channels.
- #[inline]
- pub const fn channels(&self) -> Channels {
- self.header.channels
- }
-
- /// Returns the header that will be stored in the encoded image.
- #[inline]
- pub const fn header(&self) -> &Header {
- &self.header
- }
-
- /// The maximum number of bytes the encoded image will take.
- ///
- /// Can be used to pre-allocate the buffer to encode the image into.
- #[inline]
- pub fn required_buf_len(&self) -> usize {
- self.header.encode_max_len()
- }
-
- /// Encodes the image to a pre-allocated buffer and returns the number of bytes written.
- ///
- /// The minimum size of the buffer can be found via [`Encoder::required_buf_len`].
- #[inline]
- pub fn encode_to_buf(&self, mut buf: impl AsMut<[u8]>) -> Result<usize> {
- let buf = buf.as_mut();
- let size_required = self.required_buf_len();
- if unlikely(buf.len() < size_required) {
- return Err(Error::OutputBufferTooSmall { size: buf.len(), required: size_required });
- }
- let (head, tail) = buf.split_at_mut(QOI_HEADER_SIZE); // can't panic
- head.copy_from_slice(&self.header.encode());
- let n_written = encode_impl_all(BytesMut::new(tail), self.data, self.header.channels)?;
- Ok(QOI_HEADER_SIZE + n_written)
- }
-
- /// Encodes the image into a newly allocated vector of bytes and returns it.
- #[cfg(any(feature = "alloc", feature = "std"))]
- #[inline]
- pub fn encode_to_vec(&self) -> Result<Vec<u8>> {
- let mut out = vec![0_u8; self.required_buf_len()];
- let size = self.encode_to_buf(&mut out)?;
- out.truncate(size);
- Ok(out)
- }
-
- /// Encodes the image directly to a generic writer that implements [`Write`](std::io::Write).
- ///
- /// Note: while it's possible to pass a `&mut [u8]` slice here since it implements `Write`,
- /// it would more effficient to use a specialized method instead: [`Encoder::encode_to_buf`].
- #[cfg(feature = "std")]
- #[inline]
- pub fn encode_to_stream<W: Write>(&self, writer: &mut W) -> Result<usize> {
- writer.write_all(&self.header.encode())?;
- let n_written =
- encode_impl_all(GenericWriter::new(writer), self.data, self.header.channels)?;
- Ok(n_written + QOI_HEADER_SIZE)
- }
-}
diff --git a/vendor/qoi/src/error.rs b/vendor/qoi/src/error.rs
deleted file mode 100644
index 2b90636..0000000
--- a/vendor/qoi/src/error.rs
+++ /dev/null
@@ -1,82 +0,0 @@
-use core::convert::Infallible;
-use core::fmt::{self, Display};
-
-use crate::consts::QOI_MAGIC;
-
-/// Errors that can occur during encoding or decoding.
-#[derive(Debug)]
-pub enum Error {
- /// Leading 4 magic bytes don't match when decoding
- InvalidMagic { magic: u32 },
- /// Invalid number of channels: expected 3 or 4
- InvalidChannels { channels: u8 },
- /// Invalid color space: expected 0 or 1
- InvalidColorSpace { colorspace: u8 },
- /// Invalid image dimensions: can't be empty or larger than 400Mp
- InvalidImageDimensions { width: u32, height: u32 },
- /// Image dimensions are inconsistent with image buffer length
- InvalidImageLength { size: usize, width: u32, height: u32 },
- /// Output buffer is too small to fit encoded/decoded image
- OutputBufferTooSmall { size: usize, required: usize },
- /// Input buffer ended unexpectedly before decoding was finished
- UnexpectedBufferEnd,
- /// Invalid stream end marker encountered when decoding
- InvalidPadding,
- #[cfg(feature = "std")]
- /// Generic I/O error from the wrapped reader/writer
- IoError(std::io::Error),
-}
-
-/// Alias for [`Result`](std::result::Result) with the error type of [`Error`].
-pub type Result<T> = core::result::Result<T, Error>;
-
-impl Display for Error {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match *self {
- Self::InvalidMagic { magic } => {
- write!(f, "invalid magic: expected {:?}, got {:?}", QOI_MAGIC, magic.to_be_bytes())
- }
- Self::InvalidChannels { channels } => {
- write!(f, "invalid number of channels: {}", channels)
- }
- Self::InvalidColorSpace { colorspace } => {
- write!(f, "invalid color space: {} (expected 0 or 1)", colorspace)
- }
- Self::InvalidImageDimensions { width, height } => {
- write!(f, "invalid image dimensions: {}x{}", width, height)
- }
- Self::InvalidImageLength { size, width, height } => {
- write!(f, "invalid image length: {} bytes for {}x{}", size, width, height)
- }
- Self::OutputBufferTooSmall { size, required } => {
- write!(f, "output buffer size too small: {} (required: {})", size, required)
- }
- Self::UnexpectedBufferEnd => {
- write!(f, "unexpected input buffer end while decoding")
- }
- Self::InvalidPadding => {
- write!(f, "invalid padding (stream end marker mismatch)")
- }
- #[cfg(feature = "std")]
- Self::IoError(ref err) => {
- write!(f, "i/o error: {}", err)
- }
- }
- }
-}
-
-#[cfg(feature = "std")]
-impl std::error::Error for Error {}
-
-impl From<Infallible> for Error {
- fn from(_: Infallible) -> Self {
- unreachable!()
- }
-}
-
-#[cfg(feature = "std")]
-impl From<std::io::Error> for Error {
- fn from(err: std::io::Error) -> Self {
- Self::IoError(err)
- }
-}
diff --git a/vendor/qoi/src/header.rs b/vendor/qoi/src/header.rs
deleted file mode 100644
index ccdb1cc..0000000
--- a/vendor/qoi/src/header.rs
+++ /dev/null
@@ -1,120 +0,0 @@
-use core::convert::TryInto;
-
-use bytemuck::cast_slice;
-
-use crate::consts::{QOI_HEADER_SIZE, QOI_MAGIC, QOI_PIXELS_MAX};
-use crate::encode_max_len;
-use crate::error::{Error, Result};
-use crate::types::{Channels, ColorSpace};
-use crate::utils::unlikely;
-
-/// Image header: dimensions, channels, color space.
-///
-/// ### Notes
-/// A valid image header must satisfy the following conditions:
-/// * Both width and height must be non-zero.
-/// * Maximum number of pixels is 400Mp (=4e8 pixels).
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
-pub struct Header {
- /// Image width in pixels
- pub width: u32,
- /// Image height in pixels
- pub height: u32,
- /// Number of 8-bit channels per pixel
- pub channels: Channels,
- /// Color space (informative field, doesn't affect encoding)
- pub colorspace: ColorSpace,
-}
-
-impl Default for Header {
- #[inline]
- fn default() -> Self {
- Self {
- width: 1,
- height: 1,
- channels: Channels::default(),
- colorspace: ColorSpace::default(),
- }
- }
-}
-
-impl Header {
- /// Creates a new header and validates image dimensions.
- #[inline]
- pub const fn try_new(
- width: u32, height: u32, channels: Channels, colorspace: ColorSpace,
- ) -> Result<Self> {
- let n_pixels = (width as usize).saturating_mul(height as usize);
- if unlikely(n_pixels == 0 || n_pixels > QOI_PIXELS_MAX) {
- return Err(Error::InvalidImageDimensions { width, height });
- }
- Ok(Self { width, height, channels, colorspace })
- }
-
- /// Creates a new header with modified channels.
- #[inline]
- pub const fn with_channels(mut self, channels: Channels) -> Self {
- self.channels = channels;
- self
- }
-
- /// Creates a new header with modified color space.
- #[inline]
- pub const fn with_colorspace(mut self, colorspace: ColorSpace) -> Self {
- self.colorspace = colorspace;
- self
- }
-
- /// Serializes the header into a bytes array.
- #[inline]
- pub(crate) fn encode(&self) -> [u8; QOI_HEADER_SIZE] {
- let mut out = [0; QOI_HEADER_SIZE];
- out[..4].copy_from_slice(&QOI_MAGIC.to_be_bytes());
- out[4..8].copy_from_slice(&self.width.to_be_bytes());
- out[8..12].copy_from_slice(&self.height.to_be_bytes());
- out[12] = self.channels.into();
- out[13] = self.colorspace.into();
- out
- }
-
- /// Deserializes the header from a byte array.
- #[inline]
- pub(crate) fn decode(data: impl AsRef<[u8]>) -> Result<Self> {
- let data = data.as_ref();
- if unlikely(data.len() < QOI_HEADER_SIZE) {
- return Err(Error::UnexpectedBufferEnd);
- }
- let v = cast_slice::<_, [u8; 4]>(&data[..12]);
- let magic = u32::from_be_bytes(v[0]);
- let width = u32::from_be_bytes(v[1]);
- let height = u32::from_be_bytes(v[2]);
- let channels = data[12].try_into()?;
- let colorspace = data[13].try_into()?;
- if unlikely(magic != QOI_MAGIC) {
- return Err(Error::InvalidMagic { magic });
- }
- Self::try_new(width, height, channels, colorspace)
- }
-
- /// Returns a number of pixels in the image.
- #[inline]
- pub const fn n_pixels(&self) -> usize {
- (self.width as usize).saturating_mul(self.height as usize)
- }
-
- /// Returns the total number of bytes in the raw pixel array.
- ///
- /// This may come useful when pre-allocating a buffer to decode the image into.
- #[inline]
- pub const fn n_bytes(&self) -> usize {
- self.n_pixels() * self.channels.as_u8() as usize
- }
-
- /// The maximum number of bytes the encoded image will take.
- ///
- /// Can be used to pre-allocate the buffer to encode the image into.
- #[inline]
- pub fn encode_max_len(&self) -> usize {
- encode_max_len(self.width, self.height, self.channels)
- }
-}
diff --git a/vendor/qoi/src/lib.rs b/vendor/qoi/src/lib.rs
deleted file mode 100644
index f77506b..0000000
--- a/vendor/qoi/src/lib.rs
+++ /dev/null
@@ -1,95 +0,0 @@
-//! Fast encoder/decoder for [QOI image format](https://qoiformat.org/), implemented in pure and safe Rust.
-//!
-//! - One of the [fastest](#benchmarks) QOI encoders/decoders out there.
-//! - Compliant with the [latest](https://qoiformat.org/qoi-specification.pdf) QOI format specification.
-//! - Zero unsafe code.
-//! - Supports decoding from / encoding to `std::io` streams directly.
-//! - `no_std` support.
-//! - Roundtrip-tested vs the reference C implementation; fuzz-tested.
-//!
-//! ### Examples
-//!
-//! ```rust
-//! use qoi::{encode_to_vec, decode_to_vec};
-//!
-//! let encoded = encode_to_vec(&pixels, width, height)?;
-//! let (header, decoded) = decode_to_vec(&encoded)?;
-//!
-//! assert_eq!(header.width, width);
-//! assert_eq!(header.height, height);
-//! assert_eq!(decoded, pixels);
-//! ```
-//!
-//! ### Benchmarks
-//!
-//! ```
-//! decode:Mp/s encode:Mp/s decode:MB/s encode:MB/s
-//! qoi.h 282.9 225.3 978.3 778.9
-//! qoi-rust 427.4 290.0 1477.7 1002.9
-//! ```
-//!
-//! - Reference C implementation:
-//! [phoboslab/qoi@00e34217](https://github.com/phoboslab/qoi/commit/00e34217).
-//! - Benchmark timings were collected on an Apple M1 laptop.
-//! - 2846 images from the suite provided upstream
-//! ([tarball](https://phoboslab.org/files/qoibench/qoi_benchmark_suite.tar)):
-//! all pngs except two with broken checksums.
-//! - 1.32 GPixels in total with 4.46 GB of raw pixel data.
-//!
-//! Benchmarks have also been run for all of the other Rust implementations
-//! of QOI for comparison purposes and, at the time of writing this document,
-//! this library proved to be the fastest one by a noticeable margin.
-//!
-//! ### Rust version
-//!
-//! The minimum supported Rust version is 1.51.0 (any changes to this would be
-//! considered to be a breaking change).
-//!
-//! ### `no_std`
-//!
-//! This crate supports `no_std` mode. By default, std is enabled via the `std`
-//! feature. You can deactivate the `default-features` to target core instead.
-//! In that case anything related to `std::io`, `std::error::Error` and heap
-//! allocations is disabled. There is an additional `alloc` feature that can
-//! be activated to bring back the support for heap allocations.
-
-#![forbid(unsafe_code)]
-#![warn(clippy::all, clippy::pedantic, clippy::nursery, clippy::cargo)]
-#![allow(
- clippy::inline_always,
- clippy::similar_names,
- clippy::missing_errors_doc,
- clippy::must_use_candidate,
- clippy::module_name_repetitions,
- clippy::cargo_common_metadata,
- clippy::doc_markdown,
- clippy::return_self_not_must_use,
-)]
-#![cfg_attr(not(any(feature = "std", test)), no_std)]
-#[cfg(all(feature = "alloc", not(any(feature = "std", test))))]
-extern crate alloc;
-#[cfg(any(feature = "std", test))]
-extern crate std as alloc;
-
-mod decode;
-mod encode;
-mod error;
-mod header;
-mod pixel;
-mod types;
-mod utils;
-
-#[doc(hidden)]
-pub mod consts;
-
-#[cfg(any(feature = "alloc", feature = "std"))]
-pub use crate::decode::decode_to_vec;
-pub use crate::decode::{decode_header, decode_to_buf, Decoder};
-
-#[cfg(any(feature = "alloc", feature = "std"))]
-pub use crate::encode::encode_to_vec;
-pub use crate::encode::{encode_max_len, encode_to_buf, Encoder};
-
-pub use crate::error::{Error, Result};
-pub use crate::header::Header;
-pub use crate::types::{Channels, ColorSpace};
diff --git a/vendor/qoi/src/pixel.rs b/vendor/qoi/src/pixel.rs
deleted file mode 100644
index d103494..0000000
--- a/vendor/qoi/src/pixel.rs
+++ /dev/null
@@ -1,183 +0,0 @@
-use crate::consts::{QOI_OP_DIFF, QOI_OP_LUMA, QOI_OP_RGB, QOI_OP_RGBA};
-use crate::error::Result;
-use crate::utils::Writer;
-use bytemuck::{cast, Pod};
-
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-#[repr(transparent)]
-pub struct Pixel<const N: usize>([u8; N]);
-
-impl<const N: usize> Pixel<N> {
- #[inline]
- pub const fn new() -> Self {
- Self([0; N])
- }
-
- #[inline]
- pub fn read(&mut self, s: &[u8]) {
- if s.len() == N {
- let mut i = 0;
- while i < N {
- self.0[i] = s[i];
- i += 1;
- }
- } else {
- unreachable!();
- }
- }
-
- #[inline]
- pub fn update<const M: usize>(&mut self, px: Pixel<M>) {
- let mut i = 0;
- while i < M && i < N {
- self.0[i] = px.0[i];
- i += 1;
- }
- }
-
- #[inline]
- pub fn update_rgb(&mut self, r: u8, g: u8, b: u8) {
- self.0[0] = r;
- self.0[1] = g;
- self.0[2] = b;
- }
-
- #[inline]
- pub fn update_rgba(&mut self, r: u8, g: u8, b: u8, a: u8) {
- self.0[0] = r;
- self.0[1] = g;
- self.0[2] = b;
- if N >= 4 {
- self.0[3] = a;
- }
- }
-
- #[inline]
- pub fn update_diff(&mut self, b1: u8) {
- self.0[0] = self.0[0].wrapping_add((b1 >> 4) & 0x03).wrapping_sub(2);
- self.0[1] = self.0[1].wrapping_add((b1 >> 2) & 0x03).wrapping_sub(2);
- self.0[2] = self.0[2].wrapping_add(b1 & 0x03).wrapping_sub(2);
- }
-
- #[inline]
- pub fn update_luma(&mut self, b1: u8, b2: u8) {
- let vg = (b1 & 0x3f).wrapping_sub(32);
- let vg_8 = vg.wrapping_sub(8);
- let vr = vg_8.wrapping_add((b2 >> 4) & 0x0f);
- let vb = vg_8.wrapping_add(b2 & 0x0f);
- self.0[0] = self.0[0].wrapping_add(vr);
- self.0[1] = self.0[1].wrapping_add(vg);
- self.0[2] = self.0[2].wrapping_add(vb);
- }
-
- #[inline]
- pub const fn as_rgba(self, with_a: u8) -> Pixel<4> {
- let mut i = 0;
- let mut out = Pixel::new();
- while i < N {
- out.0[i] = self.0[i];
- i += 1;
- }
- if N < 4 {
- out.0[3] = with_a;
- }
- out
- }
-
- #[inline]
- pub const fn r(self) -> u8 {
- self.0[0]
- }
-
- #[inline]
- pub const fn g(self) -> u8 {
- self.0[1]
- }
-
- #[inline]
- pub const fn b(self) -> u8 {
- self.0[2]
- }
-
- #[inline]
- pub const fn with_a(mut self, value: u8) -> Self {
- if N >= 4 {
- self.0[3] = value;
- }
- self
- }
-
- #[inline]
- pub const fn a_or(self, value: u8) -> u8 {
- if N < 4 {
- value
- } else {
- self.0[3]
- }
- }
-
- #[inline]
- #[allow(clippy::cast_lossless, clippy::cast_possible_truncation)]
- pub fn hash_index(self) -> u8
- where
- [u8; N]: Pod,
- {
- // credits for the initial idea: @zakarumych
- let v = if N == 4 {
- u32::from_ne_bytes(cast(self.0))
- } else {
- u32::from_ne_bytes([self.0[0], self.0[1], self.0[2], 0xff])
- } as u64;
- let s = ((v & 0xff00_ff00) << 32) | (v & 0x00ff_00ff);
- s.wrapping_mul(0x0300_0700_0005_000b_u64).to_le().swap_bytes() as u8 & 63
- }
-
- #[inline]
- pub fn rgb_add(&mut self, r: u8, g: u8, b: u8) {
- self.0[0] = self.0[0].wrapping_add(r);
- self.0[1] = self.0[1].wrapping_add(g);
- self.0[2] = self.0[2].wrapping_add(b);
- }
-
- #[inline]
- pub fn encode_into<W: Writer>(&self, px_prev: Self, buf: W) -> Result<W> {
- if N == 3 || self.a_or(0) == px_prev.a_or(0) {
- let vg = self.g().wrapping_sub(px_prev.g());
- let vg_32 = vg.wrapping_add(32);
- if vg_32 | 63 == 63 {
- let vr = self.r().wrapping_sub(px_prev.r());
- let vb = self.b().wrapping_sub(px_prev.b());
- let vg_r = vr.wrapping_sub(vg);
- let vg_b = vb.wrapping_sub(vg);
- let (vr_2, vg_2, vb_2) =
- (vr.wrapping_add(2), vg.wrapping_add(2), vb.wrapping_add(2));
- if vr_2 | vg_2 | vb_2 | 3 == 3 {
- buf.write_one(QOI_OP_DIFF | vr_2 << 4 | vg_2 << 2 | vb_2)
- } else {
- let (vg_r_8, vg_b_8) = (vg_r.wrapping_add(8), vg_b.wrapping_add(8));
- if vg_r_8 | vg_b_8 | 15 == 15 {
- buf.write_many(&[QOI_OP_LUMA | vg_32, vg_r_8 << 4 | vg_b_8])
- } else {
- buf.write_many(&[QOI_OP_RGB, self.r(), self.g(), self.b()])
- }
- }
- } else {
- buf.write_many(&[QOI_OP_RGB, self.r(), self.g(), self.b()])
- }
- } else {
- buf.write_many(&[QOI_OP_RGBA, self.r(), self.g(), self.b(), self.a_or(0xff)])
- }
- }
-}
-
-impl<const N: usize> From<Pixel<N>> for [u8; N] {
- #[inline(always)]
- fn from(px: Pixel<N>) -> Self {
- px.0
- }
-}
-
-pub trait SupportedChannels {}
-
-impl SupportedChannels for Pixel<3> {}
-impl SupportedChannels for Pixel<4> {}
diff --git a/vendor/qoi/src/types.rs b/vendor/qoi/src/types.rs
deleted file mode 100644
index 81229d4..0000000
--- a/vendor/qoi/src/types.rs
+++ /dev/null
@@ -1,113 +0,0 @@
-use core::convert::TryFrom;
-
-use crate::error::{Error, Result};
-use crate::utils::unlikely;
-
-/// Image color space.
-///
-/// Note: the color space is purely informative. Although it is saved to the
-/// file header, it does not affect encoding/decoding in any way.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
-#[repr(u8)]
-pub enum ColorSpace {
- /// sRGB with linear alpha
- Srgb = 0,
- /// All channels are linear
- Linear = 1,
-}
-
-impl ColorSpace {
- /// Returns true if the color space is sRGB with linear alpha.
- pub const fn is_srgb(self) -> bool {
- matches!(self, Self::Srgb)
- }
-
- /// Returns true is all channels are linear.
- pub const fn is_linear(self) -> bool {
- matches!(self, Self::Linear)
- }
-
- /// Converts to an integer (0 if sRGB, 1 if all linear).
- pub const fn as_u8(self) -> u8 {
- self as u8
- }
-}
-
-impl Default for ColorSpace {
- fn default() -> Self {
- Self::Srgb
- }
-}
-
-impl From<ColorSpace> for u8 {
- #[inline]
- fn from(colorspace: ColorSpace) -> Self {
- colorspace as Self
- }
-}
-
-impl TryFrom<u8> for ColorSpace {
- type Error = Error;
-
- #[inline]
- fn try_from(colorspace: u8) -> Result<Self> {
- if unlikely(colorspace | 1 != 1) {
- Err(Error::InvalidColorSpace { colorspace })
- } else {
- Ok(if colorspace == 0 { Self::Srgb } else { Self::Linear })
- }
- }
-}
-
-/// Number of 8-bit channels in a pixel.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
-#[repr(u8)]
-pub enum Channels {
- /// Three 8-bit channels (RGB)
- Rgb = 3,
- /// Four 8-bit channels (RGBA)
- Rgba = 4,
-}
-
-impl Channels {
- /// Returns true if there are 3 channels (RGB).
- pub const fn is_rgb(self) -> bool {
- matches!(self, Self::Rgb)
- }
-
- /// Returns true if there are 4 channels (RGBA).
- pub const fn is_rgba(self) -> bool {
- matches!(self, Self::Rgba)
- }
-
- /// Converts to an integer (3 if RGB, 4 if RGBA).
- pub const fn as_u8(self) -> u8 {
- self as u8
- }
-}
-
-impl Default for Channels {
- fn default() -> Self {
- Self::Rgb
- }
-}
-
-impl From<Channels> for u8 {
- #[inline]
- fn from(channels: Channels) -> Self {
- channels as Self
- }
-}
-
-impl TryFrom<u8> for Channels {
- type Error = Error;
-
- #[inline]
- fn try_from(channels: u8) -> Result<Self> {
- if unlikely(channels != 3 && channels != 4) {
- Err(Error::InvalidChannels { channels })
- } else {
- Ok(if channels == 3 { Self::Rgb } else { Self::Rgba })
- }
- }
-}
diff --git a/vendor/qoi/src/utils.rs b/vendor/qoi/src/utils.rs
deleted file mode 100644
index d0c37a6..0000000
--- a/vendor/qoi/src/utils.rs
+++ /dev/null
@@ -1,107 +0,0 @@
-#[cfg(feature = "std")]
-use std::io::Write;
-
-use crate::error::Result;
-
-#[inline(always)]
-#[cold]
-pub const fn cold() {}
-
-#[inline(always)]
-#[allow(unused)]
-pub const fn likely(b: bool) -> bool {
- if !b {
- cold();
- }
- b
-}
-
-#[inline(always)]
-pub const fn unlikely(b: bool) -> bool {
- if b {
- cold();
- }
- b
-}
-
-pub trait Writer: Sized {
- fn write_one(self, v: u8) -> Result<Self>;
- fn write_many(self, v: &[u8]) -> Result<Self>;
- fn capacity(&self) -> usize;
-}
-
-pub struct BytesMut<'a>(&'a mut [u8]);
-
-impl<'a> BytesMut<'a> {
- pub fn new(buf: &'a mut [u8]) -> Self {
- Self(buf)
- }
-
- #[inline]
- pub fn write_one(self, v: u8) -> Self {
- if let Some((first, tail)) = self.0.split_first_mut() {
- *first = v;
- Self(tail)
- } else {
- unreachable!()
- }
- }
-
- #[inline]
- pub fn write_many(self, v: &[u8]) -> Self {
- if v.len() <= self.0.len() {
- let (head, tail) = self.0.split_at_mut(v.len());
- head.copy_from_slice(v);
- Self(tail)
- } else {
- unreachable!()
- }
- }
-}
-
-impl<'a> Writer for BytesMut<'a> {
- #[inline]
- fn write_one(self, v: u8) -> Result<Self> {
- Ok(BytesMut::write_one(self, v))
- }
-
- #[inline]
- fn write_many(self, v: &[u8]) -> Result<Self> {
- Ok(BytesMut::write_many(self, v))
- }
-
- #[inline]
- fn capacity(&self) -> usize {
- self.0.len()
- }
-}
-
-#[cfg(feature = "std")]
-pub struct GenericWriter<W> {
- writer: W,
- n_written: usize,
-}
-
-#[cfg(feature = "std")]
-impl<W: Write> GenericWriter<W> {
- pub const fn new(writer: W) -> Self {
- Self { writer, n_written: 0 }
- }
-}
-
-#[cfg(feature = "std")]
-impl<W: Write> Writer for GenericWriter<W> {
- fn write_one(mut self, v: u8) -> Result<Self> {
- self.n_written += 1;
- self.writer.write_all(&[v]).map(|_| self).map_err(Into::into)
- }
-
- fn write_many(mut self, v: &[u8]) -> Result<Self> {
- self.n_written += v.len();
- self.writer.write_all(v).map(|_| self).map_err(Into::into)
- }
-
- fn capacity(&self) -> usize {
- usize::MAX - self.n_written
- }
-}