1use std::path::Path;
13
14pub mod decoder;
15pub mod encoder;
16mod image;
17#[doc(hidden)]
18pub mod legacy;
19
20pub use decoder::DecoderError;
21pub use encoder::{EncoderError, LosslessEncodingOptions, LossyEncodingOptions};
22pub use image::ImageBuffer;
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26pub enum WebpEncoding {
27 Lossless,
29 Lossy,
31}
32
33pub fn decode(data: &[u8]) -> Result<ImageBuffer, DecoderError> {
38 let features = decoder::get_features(data)?;
39 if features.has_animation {
40 return Err(DecoderError::Unsupported(
41 "animated WebP requires animation decoder API",
42 ));
43 }
44
45 let image = match features.format {
46 decoder::WebpFormat::Lossy => decoder::decode_lossy_webp_to_rgba(data)?,
47 decoder::WebpFormat::Lossless => decoder::decode_lossless_webp_to_rgba(data)?,
48 decoder::WebpFormat::Undefined => {
49 return Err(DecoderError::Unsupported("unsupported WebP format"))
50 }
51 };
52
53 Ok(ImageBuffer {
54 width: image.width,
55 height: image.height,
56 rgba: image.rgba,
57 })
58}
59
60fn to_lossless_options(optimize: usize) -> Result<LosslessEncodingOptions, EncoderError> {
61 let optimization_level = u8::try_from(optimize)
62 .map_err(|_| EncoderError::InvalidParam("lossless optimization level must be in 0..=9"))?;
63 Ok(LosslessEncodingOptions { optimization_level })
64}
65
66fn to_lossy_options(optimize: usize, quality: usize) -> Result<LossyEncodingOptions, EncoderError> {
67 let optimization_level = u8::try_from(optimize)
68 .map_err(|_| EncoderError::InvalidParam("lossy optimization level must be in 0..=9"))?;
69 let quality = u8::try_from(quality)
70 .map_err(|_| EncoderError::InvalidParam("quality must be in 0..=100"))?;
71 Ok(LossyEncodingOptions {
72 quality,
73 optimization_level,
74 })
75}
76
77pub fn encode(
85 image: &ImageBuffer,
86 optimize: usize,
87 quality: usize,
88 compression: WebpEncoding,
89 exif: Option<&[u8]>,
90) -> Result<Vec<u8>, EncoderError> {
91 match compression {
92 WebpEncoding::Lossless => encode_lossless(image, optimize, exif),
93 WebpEncoding::Lossy => encode_lossy(image, optimize, quality, exif),
94 }
95}
96
97pub fn encode_lossy(
103 image: &ImageBuffer,
104 optimize: usize,
105 quality: usize,
106 exif: Option<&[u8]>,
107) -> Result<Vec<u8>, EncoderError> {
108 let options = to_lossy_options(optimize, quality)?;
109 encoder::encode_lossy_image_to_webp_with_options_and_exif(image, &options, exif)
110}
111
112pub fn encode_lossless(
118 image: &ImageBuffer,
119 optimize: usize,
120 exif: Option<&[u8]>,
121) -> Result<Vec<u8>, EncoderError> {
122 let options = to_lossless_options(optimize)?;
123 encoder::encode_lossless_image_to_webp_with_options_and_exif(image, &options, exif)
124}
125
126pub fn image_from_bytes(data: &[u8]) -> Result<ImageBuffer, DecoderError> {
128 decode(data)
129}
130
131#[cfg(not(target_family = "wasm"))]
133pub fn decode_file<P: AsRef<Path>>(filename: P) -> Result<ImageBuffer, Box<dyn std::error::Error>> {
134 let data = std::fs::read(filename)?;
135 Ok(decode(&data)?)
136}
137
138#[cfg(not(target_family = "wasm"))]
140pub fn image_from_file<P: AsRef<Path>>(
141 filename: P,
142) -> Result<ImageBuffer, Box<dyn std::error::Error>> {
143 decode_file(filename)
144}