webp_rust/encoder/lossless/
api.rs1use super::plans::*;
4use super::*;
5
6pub 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
67pub 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
81pub 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
91pub 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
112pub 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
126pub 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
134pub 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
149pub fn encode_lossless_image_to_webp(image: &ImageBuffer) -> Result<Vec<u8>, EncoderError> {
151 encode_lossless_image_to_webp_with_options(image, &LosslessEncodingOptions::default())
152}