aboutsummaryrefslogtreecommitdiff
path: root/vendor/gif/src/encoder.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gif/src/encoder.rs')
-rw-r--r--vendor/gif/src/encoder.rs434
1 files changed, 0 insertions, 434 deletions
diff --git a/vendor/gif/src/encoder.rs b/vendor/gif/src/encoder.rs
deleted file mode 100644
index 693a8cb..0000000
--- a/vendor/gif/src/encoder.rs
+++ /dev/null
@@ -1,434 +0,0 @@
-//! # Minimal gif encoder
-use std::io;
-use std::io::prelude::*;
-use std::fmt;
-use std::error;
-use std::borrow::Cow;
-
-use weezl::{BitOrder, encode::Encoder as LzwEncoder};
-
-use crate::traits::{WriteBytesExt};
-use crate::common::{AnyExtension, Block, DisposalMethod, Extension, Frame};
-
-#[derive(Debug)]
-enum FormatErrorKind {
- /// The image has too many colors.
- TooManyColors,
- /// The image has no color palette which is required.
- MissingColorPalette,
-}
-
-/// The image has incorrect properties, making it impossible to encode as a gif.
-#[derive(Debug)]
-pub struct EncodingFormatError {
- kind: FormatErrorKind
-}
-
-impl error::Error for EncodingFormatError {}
-impl fmt::Display for EncodingFormatError {
- fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self.kind {
- FormatErrorKind::TooManyColors => write!(fmt, "the image has too many colors"),
- FormatErrorKind::MissingColorPalette => write!(fmt, "the GIF format requires a color palette but none was given")
- }
- }
-}
-
-impl From<FormatErrorKind> for EncodingFormatError {
- fn from(kind: FormatErrorKind) -> Self {
- EncodingFormatError { kind }
- }
-}
-
-#[derive(Debug)]
-/// Encoding error.
-pub enum EncodingError {
- /// Returned if the to image is not encodable as a gif.
- Format(EncodingFormatError),
- /// Wraps `std::io::Error`.
- Io(io::Error),
-}
-
-impl fmt::Display for EncodingError {
- fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- match self {
- EncodingError::Io(err) => err.fmt(fmt),
- EncodingError::Format(err) => err.fmt(fmt),
- }
- }
-}
-
-impl error::Error for EncodingError {
- fn source(&self) -> Option<&(dyn error::Error + 'static)> {
- match self {
- EncodingError::Io(err) => Some(err),
- EncodingError::Format(err) => Some(err),
- }
- }
-}
-
-impl From<io::Error> for EncodingError {
- fn from(err: io::Error) -> Self {
- EncodingError::Io(err)
- }
-}
-
-impl From<EncodingFormatError> for EncodingError {
- fn from(err: EncodingFormatError) -> Self {
- EncodingError::Format(err)
- }
-}
-
-impl From<FormatErrorKind> for EncodingError {
- fn from(kind: FormatErrorKind) -> Self {
- EncodingError::Format(kind.into())
- }
-}
-
-
-/// Number of repetitions
-#[derive(Copy, Clone, Debug)]
-pub enum Repeat {
- /// Finite number of repetitions
- Finite(u16),
- /// Infinite number of repetitions
- Infinite
-}
-
-/// Extension data.
-pub enum ExtensionData {
- /// Control extension. Use `ExtensionData::new_control_ext` to construct.
- Control {
- /// Flags.
- flags: u8,
- /// Frame delay.
- delay: u16,
- /// Transparent index.
- trns: u8
- },
- /// Sets the number of repetitions
- Repetitions(Repeat)
-}
-
-impl ExtensionData {
- /// Constructor for control extension data.
- ///
- /// `delay` is given in units of 10 ms.
- pub fn new_control_ext(delay: u16, dispose: DisposalMethod,
- needs_user_input: bool, trns: Option<u8>) -> ExtensionData {
- let mut flags = 0;
- let trns = match trns {
- Some(trns) => {
- flags |= 1;
- trns as u8
- },
- None => 0
- };
- flags |= (needs_user_input as u8) << 1;
- flags |= (dispose as u8) << 2;
- ExtensionData::Control {
- flags: flags,
- delay: delay,
- trns: trns
- }
- }
-}
-
-impl<W: Write> Encoder<W> {
- /// Creates a new encoder.
- ///
- /// `global_palette` gives the global color palette in the format `[r, g, b, ...]`,
- /// if no global palette shall be used an empty slice may be supplied.
- pub fn new(w: W, width: u16, height: u16, global_palette: &[u8]) -> Result<Self, EncodingError> {
- let buffer_size = (width as usize) * (height as usize);
- Encoder {
- w: Some(w),
- global_palette: false,
- width: width,
- height: height,
- buffer: Vec::with_capacity(buffer_size)
- }.write_global_palette(global_palette)
- }
-
- /// Write an extension block that signals a repeat behaviour.
- pub fn set_repeat(&mut self, repeat: Repeat) -> Result<(), EncodingError> {
- self.write_extension(ExtensionData::Repetitions(repeat))
- }
-
- /// Writes the global color palette.
- pub fn write_global_palette(mut self, palette: &[u8]) -> Result<Self, EncodingError> {
- self.global_palette = true;
- let mut flags = 0;
- flags |= 0b1000_0000;
- let num_colors = palette.len() / 3;
- if num_colors > 256 {
- return Err(EncodingError::from(FormatErrorKind::TooManyColors));
- }
- // Size of global color table.
- flags |= flag_size(num_colors);
- // Color resolution .. FIXME. This is mostly ignored (by ImageMagick at least) but hey, we
- // should use some sensible value here or even allow configuring it?
- flags |= flag_size(num_colors) << 4; // wtf flag
- self.write_screen_desc(flags)?;
- self.write_color_table(palette)?;
- Ok(self)
- }
-
- /// Writes a frame to the image.
- ///
- /// Note: This function also writes a control extension if necessary.
- pub fn write_frame(&mut self, frame: &Frame) -> Result<(), EncodingError> {
- self.write_frame_header(frame)?;
- self.write_image_block(&frame.buffer)
- }
-
- fn write_frame_header(&mut self, frame: &Frame) -> Result<(), EncodingError> {
- // TODO commented off to pass test in lib.rs
- //if frame.delay > 0 || frame.transparent.is_some() {
- self.write_extension(ExtensionData::new_control_ext(
- frame.delay,
- frame.dispose,
- frame.needs_user_input,
- frame.transparent
-
- ))?;
- //}
- let writer = self.w.as_mut().unwrap();
- writer.write_le(Block::Image as u8)?;
- writer.write_le(frame.left)?;
- writer.write_le(frame.top)?;
- writer.write_le(frame.width)?;
- writer.write_le(frame.height)?;
- let mut flags = 0;
- if frame.interlaced {
- flags |= 0b0100_0000;
- }
- match frame.palette {
- Some(ref palette) => {
- flags |= 0b1000_0000;
- let num_colors = palette.len() / 3;
- if num_colors > 256 {
- return Err(EncodingError::from(FormatErrorKind::TooManyColors));
- }
- flags |= flag_size(num_colors);
- writer.write_le(flags)?;
- self.write_color_table(palette)
- },
- None => if !self.global_palette {
- Err(EncodingError::from(FormatErrorKind::MissingColorPalette))
- } else {
- writer.write_le(flags).map_err(Into::into)
- }
- }
- }
-
- fn write_image_block(&mut self, data: &[u8]) -> Result<(), EncodingError> {
- self.buffer.clear();
- lzw_encode(data, &mut self.buffer);
-
- let writer = self.w.as_mut().unwrap();
- Self::write_encoded_image_block(writer, &self.buffer)
- }
-
- fn write_encoded_image_block(writer: &mut W, data_with_min_code_size: &[u8]) -> Result<(), EncodingError> {
- let (&min_code_size, data) = data_with_min_code_size.split_first().unwrap_or((&2, &[]));
- writer.write_le(min_code_size)?;
-
- // Write blocks. `chunks_exact` seems to be slightly faster
- // than `chunks` according to both Rust docs and benchmark results.
- let mut iter = data.chunks_exact(0xFF);
- while let Some(full_block) = iter.next() {
- writer.write_le(0xFFu8)?;
- writer.write_all(full_block)?;
- }
- let last_block = iter.remainder();
- if !last_block.is_empty() {
- writer.write_le(last_block.len() as u8)?;
- writer.write_all(last_block)?;
- }
- writer.write_le(0u8).map_err(Into::into)
- }
-
- fn write_color_table(&mut self, table: &[u8]) -> Result<(), EncodingError> {
- let writer = self.w.as_mut().unwrap();
- let num_colors = table.len() / 3;
- if num_colors > 256 {
- return Err(EncodingError::from(FormatErrorKind::TooManyColors));
- }
- let size = flag_size(num_colors);
- writer.write_all(&table[..num_colors * 3])?;
- // Waste some space as of gif spec
- for _ in 0..((2 << size) - num_colors) {
- writer.write_all(&[0, 0, 0])?
- }
- Ok(())
- }
-
- /// Writes an extension to the image.
- ///
- /// It is normally not necessary to call this method manually.
- pub fn write_extension(&mut self, extension: ExtensionData) -> Result<(), EncodingError> {
- use self::ExtensionData::*;
- // 0 finite repetitions can only be achieved
- // if the corresponting extension is not written
- if let Repetitions(Repeat::Finite(0)) = extension {
- return Ok(())
- }
- let writer = self.w.as_mut().unwrap();
- writer.write_le(Block::Extension as u8)?;
- match extension {
- Control { flags, delay, trns } => {
- writer.write_le(Extension::Control as u8)?;
- writer.write_le(4u8)?;
- writer.write_le(flags)?;
- writer.write_le(delay)?;
- writer.write_le(trns)?;
- }
- Repetitions(repeat) => {
- writer.write_le(Extension::Application as u8)?;
- writer.write_le(11u8)?;
- writer.write_all(b"NETSCAPE2.0")?;
- writer.write_le(3u8)?;
- writer.write_le(1u8)?;
- match repeat {
- Repeat::Finite(no) => writer.write_le(no)?,
- Repeat::Infinite => writer.write_le(0u16)?,
- }
- }
- }
- writer.write_le(0u8).map_err(Into::into)
- }
-
- /// Writes a raw extension to the image.
- ///
- /// This method can be used to write an unsupported extension to the file. `func` is the extension
- /// identifier (e.g. `Extension::Application as u8`). `data` are the extension payload blocks. If any
- /// contained slice has a lenght > 255 it is automatically divided into sub-blocks.
- pub fn write_raw_extension(&mut self, func: AnyExtension, data: &[&[u8]]) -> io::Result<()> {
- let writer = self.w.as_mut().unwrap();
- writer.write_le(Block::Extension as u8)?;
- writer.write_le(func.0)?;
- for block in data {
- for chunk in block.chunks(0xFF) {
- writer.write_le(chunk.len() as u8)?;
- writer.write_all(chunk)?;
- }
- }
- writer.write_le(0u8)
- }
-
- /// Writes a frame to the image, but expects `Frame.buffer` to contain LZW-encoded data
- /// from [`Frame::make_lzw_pre_encoded`].
- ///
- /// Note: This function also writes a control extension if necessary.
- pub fn write_lzw_pre_encoded_frame(&mut self, frame: &Frame) -> Result<(), EncodingError> {
- self.write_frame_header(frame)?;
- let writer = self.w.as_mut().unwrap();
- Self::write_encoded_image_block(writer, &frame.buffer)
- }
-
- /// Writes the logical screen desriptor
- fn write_screen_desc(&mut self, flags: u8) -> io::Result<()> {
- let writer = self.w.as_mut().unwrap();
- writer.write_all(b"GIF89a")?;
- writer.write_le(self.width)?;
- writer.write_le(self.height)?;
- writer.write_le(flags)?; // packed field
- writer.write_le(0u8)?; // bg index
- writer.write_le(0u8) // aspect ratio
- }
-
- /// Gets a reference to the writer instance used by this encoder.
- pub fn get_ref(&self) -> &W {
- self.w.as_ref().unwrap()
- }
-
- /// Gets a mutable reference to the writer instance used by this encoder.
- ///
- /// It is inadvisable to directly write to the underlying writer.
- pub fn get_mut(&mut self) -> &mut W {
- self.w.as_mut().unwrap()
- }
-
- /// Returns writer instance used by this encoder
- pub fn into_inner(mut self) -> io::Result<W> {
- self.write_trailer()?;
- Ok(self.w.take().unwrap())
- }
-
- /// Write the final tailer.
- fn write_trailer(&mut self) -> io::Result<()> {
- self.w.as_mut().unwrap().write_le(Block::Trailer as u8)
- }
-}
-
-/// Encodes the data into the provided buffer.
-///
-/// The first byte is the minimum code size, followed by LZW data.
-fn lzw_encode(data: &[u8], buffer: &mut Vec<u8>) {
- let min_code_size = match flag_size(1 + data.iter().copied().max().unwrap_or(0) as usize) + 1 {
- 1 => 2, // As per gif spec: The minimal code size has to be >= 2
- n => n
- };
- buffer.push(min_code_size);
- let mut enc = LzwEncoder::new(BitOrder::Lsb, min_code_size);
- let len = enc.into_vec(buffer).encode_all(data).consumed_out;
- buffer.truncate(len+1);
-}
-
-impl Frame<'_> {
- /// Replace frame's buffer with a LZW-compressed one for use with [`Encoder::write_lzw_pre_encoded_frame`].
- ///
- /// Frames can be compressed in any order, separately from the `Encoder`, which can be used to compress frames in parallel.
- pub fn make_lzw_pre_encoded(&mut self) {
- let mut buffer = Vec::with_capacity(self.buffer.len() / 2);
- lzw_encode(&self.buffer, &mut buffer);
- self.buffer = Cow::Owned(buffer);
- }
-}
-
-/// GIF encoder.
-pub struct Encoder<W: Write> {
- w: Option<W>,
- global_palette: bool,
- width: u16,
- height: u16,
- buffer: Vec<u8>
-}
-
-impl<W: Write> Drop for Encoder<W> {
-
- #[cfg(feature = "raii_no_panic")]
- fn drop(&mut self) {
- if self.w.is_some() {
- let _ = self.write_trailer();
- }
- }
-
- #[cfg(not(feature = "raii_no_panic"))]
- fn drop(&mut self) {
- if self.w.is_some() {
- self.write_trailer().unwrap();
- }
- }
-}
-
-// Color table size converted to flag bits
-fn flag_size(size: usize) -> u8 {
- match size {
- 0 ..=2 => 0,
- 3 ..=4 => 1,
- 5 ..=8 => 2,
- 9 ..=16 => 3,
- 17 ..=32 => 4,
- 33 ..=64 => 5,
- 65 ..=128 => 6,
- 129..=256 => 7,
- _ => 7
- }
-}
-
-#[test]
-fn error_cast() {
- let _ : Box<dyn error::Error> = EncodingError::from(FormatErrorKind::MissingColorPalette).into();
-}