1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
//! # Overview
//!
//! This crate provides a high-level Rust wrapper for decoding and encoding
//! [WebP](https://en.wikipedia.org/wiki/WebP) animations.
//! Underlying WebP format processing is handled by C-based
//! [libwebp](https://developers.google.com/speed/webp/docs/container-api) library by Google,
//! which is interfaced through Rust [libwebp-sys2](https://crates.io/crates/libwebp-sys2)
//! crate
//!
//! # Usage
//! Have a look at [`Decoder`] and [`Encoder`] for use-case specific examples.

use std::fmt::Debug;

mod decoder;
mod encoder;
mod encoder_config;
mod frame;
mod webp_data;

pub use decoder::*;
pub use encoder::*;
pub use encoder_config::*;
pub use frame::*;
pub use webp_data::*;

pub mod prelude {
    // general
    pub use crate::ColorMode;

    // decoder
    pub use crate::{Decoder, DecoderOptions};

    // encoder
    pub use crate::{Encoder, EncoderOptions, EncodingConfig, EncodingType, LossyEncodingConfig};
}

const PIXEL_BYTES: usize = 4;

/// Color Mode that configures the output type of [`Decoder`] [`Frame`]'s
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum ColorMode {
    /// Rgba (red, green, blue, alpha)
    Rgba,
    /// Bgra (blue, green, red, alpha)
    Bgra,
    // what about MODE_rgbA and MODE_bgrA ?
}

/// Error type produced by `webp_animation` code
#[derive(PartialEq)]
pub enum Error {
    /// Initializing webp options failed, internal (memory allocation?) failure
    OptionsInitFailed,

    /// Decoder init failed, input contains wrong bytes
    DecodeFailed,

    /// Decoder could not get metadata of webp stream. Corrupt data?
    DecoderGetInfoFailed,

    /// Webp stream contains too large canvas. For now, size is limited to 3840 * 2160 pixels
    /// See `MAX_CANVAS_SIZE` variable from code
    TooLargeCanvas(u32, u32, usize),

    /// Encoder create failed. Wrong options combination?
    EncoderCreateFailed,

    /// Data input buffer size did not match encoder metadata (width * height * 4)
    BufferSizeFailed(usize, usize),

    /// Raw data could not be converted into webp frame by underlying libwebp library
    PictureImportFailed,

    /// Frame could not be added to webp stream by underlying libwebp library
    EncoderAddFailed,

    /// Underlying data is in different color mode
    WrongColorMode(ColorMode, ColorMode),

    /// Timestamp must be higher value than previous frame timestamp
    TimestampMustBeHigherThanPrevious(i32, i32),

    /// Timestamp must be higher or equal to the previous frame timestamp
    TimestampMustBeEqualOrHigherThanPrevious(i32, i32),

    /// Encoder webp assembly failed
    EncoderAssmebleFailed,

    /// Supplied dimensions must be positive
    DimensionsMustbePositive,

    /// No frames have been supplied to encoder
    NoFramesAdded,

    /// Supplied zero-sized buffer where bytes where expected
    ZeroSizeBuffer,

    /// Encoder config validation failed
    InvalidEncodingConfig,
}

impl Debug for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Error::OptionsInitFailed => write!(f, "OptionsInitFailed: Initializing webp options failed, internal (memory allocation?) failure"),
            Error::DecodeFailed => write!(f, "DecodeFailed: Could not decode input bytes, possibly malformed data"),
            Error::DecoderGetInfoFailed => write!(f, "DecoderGetInfoFailed: Decoder could not get metadata of webp stream. Corrupt data?"),
            Error::TooLargeCanvas(width, height, max_size) => write!(f, "TooLargeCanvas: Decodable canvas is too large ({} x {} = {} pixels). For now, size is limited to 3840 * 2160 = {} pixels", width, height, width * height, max_size),
            Error::EncoderCreateFailed => write!(f, "EncoderCreateFailed: Encoder create failed. Wrong options combination?"),
            Error::BufferSizeFailed(expected, received) => write!(f, "BufferSizeFailed: Expected (width * height * 4 = {}) bytes as input buffer, got {} bytes", expected, received),
            Error::PictureImportFailed => write!(f, "PictureImportFailed: Raw data could not be converted into webp frame by underlying libwebp library"),
            Error::EncoderAddFailed => write!(f, "EncoderAddFailed: Frame could not be added to webp stream by underlying libwebp library"),
            Error::WrongColorMode(requested, expected) => write!(f, "WrongColorMode: Requested image in {:?} format but underlying is stored as {:?}", expected, requested),
            Error::TimestampMustBeHigherThanPrevious(requested, previous) => write!(f, "TimestampMustBeHigherThanPrevious: Supplied timestamp (got {}) must be higher than {}", requested, previous),
            Error::TimestampMustBeEqualOrHigherThanPrevious(requested, previous) => write!(f, "TimestampMustBeEqualOrHigherThanPrevious: Supplied timestamp (got {}) must be higher or equal to {}", requested, previous),
            Error::EncoderAssmebleFailed => write!(f, "EncoderAssmebleFailed: Encoder webp assembly failed"),
            Error::DimensionsMustbePositive => write!(f, "DimensionsMustbePositive: Supplied dimensions must be positive"),
            Error::NoFramesAdded => write!(f, "NoFramesAdded: No frames have been added yet"),
            Error::ZeroSizeBuffer => write!(f, "ZeroSizeBuffer: Buffer contains no data"),
            Error::InvalidEncodingConfig => write!(f, "InvalidEncodingConfig: encoding configuration validation failed")
        }
    }
}