aboutsummaryrefslogtreecommitdiff
path: root/vendor/qoi/src/encode.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/qoi/src/encode.rs')
-rw-r--r--vendor/qoi/src/encode.rs210
1 files changed, 0 insertions, 210 deletions
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)
- }
-}