Skip to main content

webp_rust/encoder/lossless/
api.rs

1//! Public entry points for lossless still-image WebP encoding.
2
3use super::plans::*;
4use super::*;
5
6/// Encodes RGBA pixels to a raw lossless `VP8L` frame payload with explicit options.
7pub fn encode_lossless_rgba_to_vp8l_with_options(
8    width: usize,
9    height: usize,
10    rgba: &[u8],
11    options: &LosslessEncodingOptions,
12) -> Result<Vec<u8>, EncoderError> {
13    validate_rgba(width, height, rgba)?;
14    validate_options(options)?;
15
16    let argb = rgba_to_argb(rgba);
17    let subtract_green = apply_subtract_green_transform(&argb);
18    let mut best = None;
19
20    for profile in lossless_candidate_profiles(options.optimization_level) {
21        let mut profile_best =
22            if let Some(candidate) = build_palette_candidate(width, height, &argb)? {
23                Some(encode_palette_candidate_to_vp8l(
24                    width, height, rgba, &candidate, &profile,
25                )?)
26            } else {
27                None
28            };
29
30        let plans = collect_transform_plans(width, height, &argb, &subtract_green, &profile);
31        let ranked_plans = shortlist_transform_plans(width, plans, &profile)?;
32        for (estimate, plan) in ranked_plans {
33            if profile_best
34                .as_ref()
35                .map(|encoded| should_stop_transform_search(encoded.len(), estimate, &profile))
36                .unwrap_or(false)
37            {
38                break;
39            }
40
41            let encoded = encode_transform_plan_to_vp8l(width, height, rgba, &plan, &profile)?;
42            if profile_best
43                .as_ref()
44                .map(|current| encoded.len() < current.len())
45                .unwrap_or(true)
46            {
47                profile_best = Some(encoded);
48            }
49        }
50
51        if let Some(encoded) = profile_best {
52            if best
53                .as_ref()
54                .map(|current: &Vec<u8>| encoded.len() < current.len())
55                .unwrap_or(true)
56            {
57                best = Some(encoded);
58            }
59        }
60    }
61
62    best.ok_or(EncoderError::Bitstream(
63        "lossless encoder produced no candidate",
64    ))
65}
66
67/// Encodes RGBA pixels to a raw lossless `VP8L` frame payload.
68pub fn encode_lossless_rgba_to_vp8l(
69    width: usize,
70    height: usize,
71    rgba: &[u8],
72) -> Result<Vec<u8>, EncoderError> {
73    encode_lossless_rgba_to_vp8l_with_options(
74        width,
75        height,
76        rgba,
77        &LosslessEncodingOptions::default(),
78    )
79}
80
81/// Encodes RGBA pixels to a still lossless WebP container with explicit options.
82pub fn encode_lossless_rgba_to_webp_with_options(
83    width: usize,
84    height: usize,
85    rgba: &[u8],
86    options: &LosslessEncodingOptions,
87) -> Result<Vec<u8>, EncoderError> {
88    encode_lossless_rgba_to_webp_with_options_and_exif(width, height, rgba, options, None)
89}
90
91/// Encodes RGBA pixels to a still lossless WebP container with explicit options and EXIF.
92pub fn encode_lossless_rgba_to_webp_with_options_and_exif(
93    width: usize,
94    height: usize,
95    rgba: &[u8],
96    options: &LosslessEncodingOptions,
97    exif: Option<&[u8]>,
98) -> Result<Vec<u8>, EncoderError> {
99    let vp8l = encode_lossless_rgba_to_vp8l_with_options(width, height, rgba, options)?;
100    wrap_still_webp(
101        StillImageChunk {
102            fourcc: *b"VP8L",
103            payload: &vp8l,
104            width,
105            height,
106            has_alpha: rgba_has_alpha(rgba),
107        },
108        exif,
109    )
110}
111
112/// Encodes RGBA pixels to a still lossless WebP container.
113pub fn encode_lossless_rgba_to_webp(
114    width: usize,
115    height: usize,
116    rgba: &[u8],
117) -> Result<Vec<u8>, EncoderError> {
118    encode_lossless_rgba_to_webp_with_options(
119        width,
120        height,
121        rgba,
122        &LosslessEncodingOptions::default(),
123    )
124}
125
126/// Encodes an [`ImageBuffer`] to a still lossless WebP container with explicit options.
127pub fn encode_lossless_image_to_webp_with_options(
128    image: &ImageBuffer,
129    options: &LosslessEncodingOptions,
130) -> Result<Vec<u8>, EncoderError> {
131    encode_lossless_image_to_webp_with_options_and_exif(image, options, None)
132}
133
134/// Encodes an [`ImageBuffer`] to a still lossless WebP container with explicit options and EXIF.
135pub fn encode_lossless_image_to_webp_with_options_and_exif(
136    image: &ImageBuffer,
137    options: &LosslessEncodingOptions,
138    exif: Option<&[u8]>,
139) -> Result<Vec<u8>, EncoderError> {
140    encode_lossless_rgba_to_webp_with_options_and_exif(
141        image.width,
142        image.height,
143        &image.rgba,
144        options,
145        exif,
146    )
147}
148
149/// Encodes an [`ImageBuffer`] to a still lossless WebP container.
150pub fn encode_lossless_image_to_webp(image: &ImageBuffer) -> Result<Vec<u8>, EncoderError> {
151    encode_lossless_image_to_webp_with_options(image, &LosslessEncodingOptions::default())
152}