1#[cfg(not(target_family = "wasm"))]
13use std::path::Path;
14
15pub mod compat;
16pub mod decoder;
17pub mod encoder;
18mod image;
19#[doc(hidden)]
20pub mod legacy;
21
22pub use compat::{
23 CallbackResponse, DataMap, DecodeOptions, DrawCallback, DrawOptions, ImageRect, InitOptions,
24 Metadata, NextBlend, NextDispose, NextOption, NextOptions, ResponseCommand, RGBA,
25};
26pub use decoder::DecoderError;
27pub use encoder::{
28 AlphaFilter, EncoderError, LosslessEncodingConfig, LossyEncodingConfig, WebpPreset,
29};
30#[cfg(feature = "legacy")]
31pub use encoder::{LosslessEncodingOptions, LossyEncodingOptions};
32pub use image::ImageBuffer;
33pub use legacy::{read_header, read_u24, AnimationControl, AnimationFrame, WebpHeader};
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq)]
37pub enum WebpEncoding {
38 Lossless,
40 Lossy,
42}
43
44pub fn decode(data: &[u8]) -> Result<ImageBuffer, DecoderError> {
49 let features = decoder::get_features(data)?;
50 if features.has_animation {
51 return Err(DecoderError::Unsupported(
52 "animated WebP requires animation decoder API",
53 ));
54 }
55
56 let image = match features.format {
57 decoder::WebpFormat::Lossy => decoder::decode_lossy_webp_to_rgba(data)?,
58 decoder::WebpFormat::Lossless => decoder::decode_lossless_webp_to_rgba(data)?,
59 decoder::WebpFormat::Undefined => {
60 return Err(DecoderError::Unsupported("unsupported WebP format"))
61 }
62 };
63
64 Ok(ImageBuffer {
65 width: image.width,
66 height: image.height,
67 rgba: image.rgba,
68 })
69}
70
71pub fn encode_lossy_with_config(
73 image: &ImageBuffer,
74 config: &LossyEncodingConfig,
75 exif: Option<&[u8]>,
76) -> Result<Vec<u8>, EncoderError> {
77 encoder::encode_lossy_image_to_webp_with_config_and_exif(image, config, exif)
78}
79
80pub fn encode_lossless_with_config(
82 image: &ImageBuffer,
83 config: &LosslessEncodingConfig,
84 exif: Option<&[u8]>,
85) -> Result<Vec<u8>, EncoderError> {
86 encoder::encode_lossless_image_to_webp_with_config_and_exif(image, config, exif)
87}
88
89#[cfg(feature = "legacy")]
90fn to_lossless_options(optimize: usize) -> Result<LosslessEncodingOptions, EncoderError> {
91 let optimization_level = u8::try_from(optimize)
92 .map_err(|_| EncoderError::InvalidParam("lossless optimization level must be in 0..=9"))?;
93 Ok(LosslessEncodingOptions { optimization_level })
94}
95
96#[cfg(feature = "legacy")]
97fn to_lossy_options(optimize: usize, quality: usize) -> Result<LossyEncodingOptions, EncoderError> {
98 let optimization_level = u8::try_from(optimize)
99 .map_err(|_| EncoderError::InvalidParam("lossy optimization level must be in 0..=9"))?;
100 let quality = u8::try_from(quality)
101 .map_err(|_| EncoderError::InvalidParam("quality must be in 0..=100"))?;
102 Ok(LossyEncodingOptions {
103 quality,
104 optimization_level,
105 })
106}
107
108#[cfg(feature = "legacy")]
116pub fn encode(
117 image: &ImageBuffer,
118 optimize: usize,
119 quality: usize,
120 compression: WebpEncoding,
121 exif: Option<&[u8]>,
122) -> Result<Vec<u8>, EncoderError> {
123 match compression {
124 WebpEncoding::Lossless => encode_lossless(image, optimize, exif),
125 WebpEncoding::Lossy => encode_lossy(image, optimize, quality, exif),
126 }
127}
128
129#[cfg(feature = "legacy")]
135pub fn encode_lossy(
136 image: &ImageBuffer,
137 optimize: usize,
138 quality: usize,
139 exif: Option<&[u8]>,
140) -> Result<Vec<u8>, EncoderError> {
141 let options = to_lossy_options(optimize, quality)?;
142 encoder::encode_lossy_image_to_webp_with_options_and_exif(image, &options, exif)
143}
144
145#[cfg(feature = "legacy")]
151pub fn encode_lossless(
152 image: &ImageBuffer,
153 optimize: usize,
154 exif: Option<&[u8]>,
155) -> Result<Vec<u8>, EncoderError> {
156 let options = to_lossless_options(optimize)?;
157 encoder::encode_lossless_image_to_webp_with_options_and_exif(image, &options, exif)
158}
159
160pub fn image_from_bytes(data: &[u8]) -> Result<ImageBuffer, DecoderError> {
162 decode(data)
163}
164
165#[cfg(not(target_family = "wasm"))]
167pub fn decode_file<P: AsRef<Path>>(filename: P) -> Result<ImageBuffer, Box<dyn std::error::Error>> {
168 let data = std::fs::read(filename)?;
169 Ok(decode(&data)?)
170}
171
172#[cfg(not(target_family = "wasm"))]
174pub fn image_from_file<P: AsRef<Path>>(
175 filename: P,
176) -> Result<ImageBuffer, Box<dyn std::error::Error>> {
177 decode_file(filename)
178}