1 // Copyright 2024 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #[cfg(feature = "libyuv")]
16 use super::libyuv;
17
18 use super::rgb;
19
20 use crate::decoder::Category;
21 use crate::image::Plane;
22 use crate::internal_utils::*;
23 use crate::reformat::rgb::Format;
24 use crate::*;
25
premultiply_u8(pixel: u8, alpha: u8) -> u826 fn premultiply_u8(pixel: u8, alpha: u8) -> u8 {
27 ((pixel as f32) * (alpha as f32) / 255.0).floor() as u8
28 }
29
premultiply_u16(pixel: u16, alpha: u16, max_channel_f: f32) -> u1630 fn premultiply_u16(pixel: u16, alpha: u16, max_channel_f: f32) -> u16 {
31 ((pixel as f32) * (alpha as f32) / max_channel_f).floor() as u16
32 }
33
unpremultiply_u8(pixel: u8, alpha: u8) -> u834 fn unpremultiply_u8(pixel: u8, alpha: u8) -> u8 {
35 ((pixel as f32) * 255.0 / (alpha as f32)).floor().min(255.0) as u8
36 }
37
unpremultiply_u16(pixel: u16, alpha: u16, max_channel_f: f32) -> u1638 fn unpremultiply_u16(pixel: u16, alpha: u16, max_channel_f: f32) -> u16 {
39 ((pixel as f32) * max_channel_f / (alpha as f32))
40 .floor()
41 .min(max_channel_f) as u16
42 }
43
44 impl rgb::Image {
premultiply_alpha(&mut self) -> AvifResult<()>45 pub fn premultiply_alpha(&mut self) -> AvifResult<()> {
46 if self.pixels().is_null() || self.row_bytes == 0 {
47 return Err(AvifError::ReformatFailed);
48 }
49 if !self.has_alpha() {
50 return Err(AvifError::InvalidArgument);
51 }
52
53 #[cfg(feature = "libyuv")]
54 match libyuv::process_alpha(self, true) {
55 Ok(_) => return Ok(()),
56 Err(err) => {
57 if err != AvifError::NotImplemented {
58 return Err(err);
59 }
60 }
61 }
62
63 let (alpha_offset, rgb_offsets) = match self.format {
64 Format::Rgba | Format::Bgra => (3, [0, 1, 2]),
65 _ => (0, [1, 2, 3]),
66 };
67
68 if self.depth > 8 {
69 let max_channel = self.max_channel();
70 let max_channel_f = self.max_channel_f();
71 for j in 0..self.height {
72 let width = self.width;
73 let row = self.row16_mut(j)?;
74 for i in 0..width as usize {
75 let offset = i * 4;
76 let alpha = row[offset + alpha_offset];
77 if alpha >= max_channel {
78 continue;
79 }
80 if alpha == 0 {
81 for rgb_offset in rgb_offsets {
82 row[offset + rgb_offset] = 0;
83 }
84 continue;
85 }
86 for rgb_offset in rgb_offsets {
87 row[offset + rgb_offset] =
88 premultiply_u16(row[offset + rgb_offset], alpha, max_channel_f);
89 }
90 }
91 }
92 } else {
93 for j in 0..self.height {
94 let width = self.width;
95 let row = self.row_mut(j)?;
96 for i in 0..width as usize {
97 let offset = i * 4;
98 let alpha = row[offset + alpha_offset];
99 match alpha {
100 0 => {
101 for rgb_offset in rgb_offsets {
102 row[offset + rgb_offset] = 0;
103 }
104 }
105 255 => {}
106 _ => {
107 for rgb_offset in rgb_offsets {
108 row[offset + rgb_offset] =
109 premultiply_u8(row[offset + rgb_offset], alpha);
110 }
111 }
112 }
113 }
114 }
115 }
116 Ok(())
117 }
118
unpremultiply_alpha(&mut self) -> AvifResult<()>119 pub fn unpremultiply_alpha(&mut self) -> AvifResult<()> {
120 if self.pixels().is_null() || self.row_bytes == 0 {
121 return Err(AvifError::ReformatFailed);
122 }
123 if !self.has_alpha() {
124 return Err(AvifError::InvalidArgument);
125 }
126
127 #[cfg(feature = "libyuv")]
128 match libyuv::process_alpha(self, false) {
129 Ok(_) => return Ok(()),
130 Err(err) => {
131 if err != AvifError::NotImplemented {
132 return Err(err);
133 }
134 }
135 }
136
137 let (alpha_offset, rgb_offsets) = match self.format {
138 Format::Rgba | Format::Bgra => (3, [0, 1, 2]),
139 _ => (0, [1, 2, 3]),
140 };
141
142 if self.depth > 8 {
143 let max_channel = self.max_channel();
144 let max_channel_f = self.max_channel_f();
145 for j in 0..self.height {
146 let width = self.width;
147 let row = self.row16_mut(j)?;
148 for i in 0..width as usize {
149 let offset = i * 4;
150 let alpha = row[offset + alpha_offset];
151 if alpha >= max_channel {
152 continue;
153 }
154 if alpha == 0 {
155 for rgb_offset in rgb_offsets {
156 row[offset + rgb_offset] = 0;
157 }
158 continue;
159 }
160 for rgb_offset in rgb_offsets {
161 row[offset + rgb_offset] =
162 unpremultiply_u16(row[offset + rgb_offset], alpha, max_channel_f);
163 }
164 }
165 }
166 } else {
167 for j in 0..self.height {
168 let width = self.width;
169 let row = self.row_mut(j)?;
170 for i in 0..width as usize {
171 let offset = i * 4;
172 let alpha = row[offset + alpha_offset];
173 match alpha {
174 0 => {
175 for rgb_offset in rgb_offsets {
176 row[offset + rgb_offset] = 0;
177 }
178 }
179 255 => {}
180 _ => {
181 for rgb_offset in rgb_offsets {
182 row[offset + rgb_offset] =
183 unpremultiply_u8(row[offset + rgb_offset], alpha);
184 }
185 }
186 }
187 }
188 }
189 }
190 Ok(())
191 }
192
set_opaque(&mut self) -> AvifResult<()>193 pub fn set_opaque(&mut self) -> AvifResult<()> {
194 if !self.has_alpha() {
195 return Ok(());
196 }
197 if self.format == rgb::Format::Rgb565 {
198 return Err(AvifError::NotImplemented);
199 }
200 let alpha_offset = self.format.alpha_offset();
201 let width = usize_from_u32(self.width)?;
202 if self.depth > 8 {
203 let max_channel = self.max_channel();
204 for y in 0..self.height {
205 let row = self.row16_mut(y)?;
206 for x in 0..width {
207 row[(x * 4) + alpha_offset] = max_channel;
208 }
209 }
210 } else {
211 for y in 0..self.height {
212 let row = self.row_mut(y)?;
213 for x in 0..width {
214 row[(x * 4) + alpha_offset] = 255;
215 }
216 }
217 }
218 Ok(())
219 }
220
rescale_alpha_value(value: u16, src_max_channel_f: f32, dst_max_channel: u16) -> u16221 fn rescale_alpha_value(value: u16, src_max_channel_f: f32, dst_max_channel: u16) -> u16 {
222 let alpha_f = (value as f32) / src_max_channel_f;
223 let dst_max_channel_f = dst_max_channel as f32;
224 let alpha = (0.5 + (alpha_f * dst_max_channel_f)) as u16;
225 clamp_u16(alpha, 0, dst_max_channel)
226 }
227
import_alpha_from(&mut self, image: &image::Image) -> AvifResult<()>228 pub fn import_alpha_from(&mut self, image: &image::Image) -> AvifResult<()> {
229 if !self.has_alpha()
230 || !image.has_alpha()
231 || self.width != image.width
232 || self.height != image.height
233 {
234 return Err(AvifError::InvalidArgument);
235 }
236 let width = usize_from_u32(self.width)?;
237 let dst_alpha_offset = self.format.alpha_offset();
238 if self.depth == image.depth {
239 if self.depth > 8 {
240 for y in 0..self.height {
241 let dst_row = self.row16_mut(y)?;
242 let src_row = image.row16(Plane::A, y)?;
243 for x in 0..width {
244 dst_row[(x * 4) + dst_alpha_offset] = src_row[x];
245 }
246 }
247 return Ok(());
248 }
249 for y in 0..self.height {
250 let dst_row = self.row_mut(y)?;
251 let src_row = image.row(Plane::A, y)?;
252 for x in 0..width {
253 dst_row[(x * 4) + dst_alpha_offset] = src_row[x];
254 }
255 }
256 return Ok(());
257 }
258 let max_channel = self.max_channel();
259 if image.depth > 8 {
260 if self.depth > 8 {
261 // u16 to u16 depth rescaling.
262 for y in 0..self.height {
263 let dst_row = self.row16_mut(y)?;
264 let src_row = image.row16(Plane::A, y)?;
265 for x in 0..width {
266 dst_row[(x * 4) + dst_alpha_offset] = Self::rescale_alpha_value(
267 src_row[x],
268 image.max_channel_f(),
269 max_channel,
270 );
271 }
272 }
273 return Ok(());
274 }
275 // u16 to u8 depth rescaling.
276 for y in 0..self.height {
277 let dst_row = self.row_mut(y)?;
278 let src_row = image.row16(Plane::A, y)?;
279 for x in 0..width {
280 dst_row[(x * 4) + dst_alpha_offset] =
281 Self::rescale_alpha_value(src_row[x], image.max_channel_f(), max_channel)
282 as u8;
283 }
284 }
285 return Ok(());
286 }
287 // u8 to u16 depth rescaling.
288 for y in 0..self.height {
289 let dst_row = self.row16_mut(y)?;
290 let src_row = image.row(Plane::A, y)?;
291 for x in 0..width {
292 dst_row[(x * 4) + dst_alpha_offset] = Self::rescale_alpha_value(
293 src_row[x] as u16,
294 image.max_channel_f(),
295 max_channel,
296 );
297 }
298 }
299 Ok(())
300 }
301 }
302
303 impl image::Image {
alpha_to_full_range(&mut self) -> AvifResult<()>304 pub fn alpha_to_full_range(&mut self) -> AvifResult<()> {
305 if self.planes[3].is_none() {
306 return Ok(());
307 }
308 let width = self.width as usize;
309 let depth = self.depth;
310 if self.planes[3].unwrap_ref().is_pointer() {
311 let src = image::Image {
312 width: self.width,
313 height: self.height,
314 depth: self.depth,
315 yuv_format: self.yuv_format,
316 planes: [
317 None,
318 None,
319 None,
320 self.planes[3].unwrap_ref().clone_pointer(),
321 ],
322 row_bytes: [0, 0, 0, self.row_bytes[3]],
323 ..image::Image::default()
324 };
325 self.allocate_planes(Category::Alpha)?;
326 if depth > 8 {
327 for y in 0..self.height {
328 let src_row = src.row16(Plane::A, y)?;
329 let dst_row = self.row16_mut(Plane::A, y)?;
330 for x in 0..width {
331 dst_row[x] = limited_to_full_y(depth, src_row[x]);
332 }
333 }
334 } else {
335 for y in 0..self.height {
336 let src_row = src.row(Plane::A, y)?;
337 let dst_row = self.row_mut(Plane::A, y)?;
338 for x in 0..width {
339 dst_row[x] = limited_to_full_y(8, src_row[x] as u16) as u8;
340 }
341 }
342 }
343 } else if depth > 8 {
344 for y in 0..self.height {
345 let row = self.row16_mut(Plane::A, y)?;
346 for pixel in row.iter_mut().take(width) {
347 *pixel = limited_to_full_y(depth, *pixel);
348 }
349 }
350 } else {
351 for y in 0..self.height {
352 let row = self.row_mut(Plane::A, y)?;
353 for pixel in row.iter_mut().take(width) {
354 *pixel = limited_to_full_y(8, *pixel as u16) as u8;
355 }
356 }
357 }
358 Ok(())
359 }
360 }
361
362 #[cfg(test)]
363 mod tests {
364 use super::*;
365
366 use crate::internal_utils::pixels::*;
367
368 use rand::Rng;
369 use test_case::test_matrix;
370
371 const ALPHA_RGB_FORMATS: [rgb::Format; 4] = [
372 rgb::Format::Rgba,
373 rgb::Format::Argb,
374 rgb::Format::Bgra,
375 rgb::Format::Abgr,
376 ];
377
rgb_image( width: u32, height: u32, depth: u8, format: rgb::Format, use_pointer: bool, buffer: &mut Vec<u8>, ) -> AvifResult<rgb::Image>378 fn rgb_image(
379 width: u32,
380 height: u32,
381 depth: u8,
382 format: rgb::Format,
383 use_pointer: bool,
384 buffer: &mut Vec<u8>,
385 ) -> AvifResult<rgb::Image> {
386 let mut rgb = rgb::Image {
387 width,
388 height,
389 depth,
390 format,
391 ..rgb::Image::default()
392 };
393 if use_pointer {
394 let pixel_size = if depth == 8 { 1 } else { 2 };
395 let buffer_size = (width * height * 4 * pixel_size) as usize;
396 buffer.reserve_exact(buffer_size);
397 buffer.resize(buffer_size, 0);
398 rgb.row_bytes = width * 4 * pixel_size;
399 // Use a pointer to mimic C API calls.
400 rgb.pixels = Some(Pixels::from_raw_pointer(
401 buffer.as_mut_ptr(),
402 rgb.depth as u32,
403 height,
404 rgb.row_bytes,
405 )?);
406 } else {
407 rgb.allocate()?;
408 }
409 Ok(rgb)
410 }
411
412 #[test_matrix(20, 10, [8, 10, 12, 16], 0..4, [true, false])]
fill_alpha( width: u32, height: u32, depth: u8, format_index: usize, use_pointer: bool, ) -> AvifResult<()>413 fn fill_alpha(
414 width: u32,
415 height: u32,
416 depth: u8,
417 format_index: usize,
418 use_pointer: bool,
419 ) -> AvifResult<()> {
420 let format = ALPHA_RGB_FORMATS[format_index];
421 let mut buffer: Vec<u8> = vec![];
422 let mut rgb = rgb_image(width, height, depth, format, use_pointer, &mut buffer)?;
423
424 rgb.set_opaque()?;
425
426 let alpha_offset = rgb.format.alpha_offset();
427 if depth == 8 {
428 for y in 0..height {
429 let row = rgb.row(y)?;
430 assert_eq!(row.len(), (width * 4) as usize);
431 for x in 0..width as usize {
432 for idx in 0..4usize {
433 let expected_value = if idx == alpha_offset { 255 } else { 0 };
434 assert_eq!(row[x * 4 + idx], expected_value);
435 }
436 }
437 }
438 } else {
439 let max_channel = ((1 << depth) - 1) as u16;
440 for y in 0..height {
441 let row = rgb.row16(y)?;
442 assert_eq!(row.len(), (width * 4) as usize);
443 for x in 0..width as usize {
444 for idx in 0..4usize {
445 let expected_value = if idx == alpha_offset { max_channel } else { 0 };
446 assert_eq!(row[x * 4 + idx], expected_value);
447 }
448 }
449 }
450 }
451 Ok(())
452 }
453
454 #[test]
rescale_alpha_value()455 fn rescale_alpha_value() {
456 // 8bit to 10bit.
457 assert_eq!(rgb::Image::rescale_alpha_value(0, 255.0, 1023), 0);
458 assert_eq!(rgb::Image::rescale_alpha_value(100, 255.0, 1023), 401);
459 assert_eq!(rgb::Image::rescale_alpha_value(128, 255.0, 1023), 514);
460 assert_eq!(rgb::Image::rescale_alpha_value(255, 255.0, 1023), 1023);
461 // 10bit to 8bit.
462 assert_eq!(rgb::Image::rescale_alpha_value(0, 1023.0, 255), 0);
463 assert_eq!(rgb::Image::rescale_alpha_value(401, 1023.0, 255), 100);
464 assert_eq!(rgb::Image::rescale_alpha_value(514, 1023.0, 255), 128);
465 assert_eq!(rgb::Image::rescale_alpha_value(1023, 1023.0, 255), 255);
466 // 8bit to 12bit.
467 assert_eq!(rgb::Image::rescale_alpha_value(0, 255.0, 4095), 0);
468 assert_eq!(rgb::Image::rescale_alpha_value(100, 255.0, 4095), 1606);
469 assert_eq!(rgb::Image::rescale_alpha_value(128, 255.0, 4095), 2056);
470 assert_eq!(rgb::Image::rescale_alpha_value(255, 255.0, 4095), 4095);
471 // 12bit to 8bit.
472 assert_eq!(rgb::Image::rescale_alpha_value(0, 4095.0, 255), 0);
473 assert_eq!(rgb::Image::rescale_alpha_value(1606, 4095.0, 255), 100);
474 assert_eq!(rgb::Image::rescale_alpha_value(2056, 4095.0, 255), 128);
475 assert_eq!(rgb::Image::rescale_alpha_value(4095, 4095.0, 255), 255);
476 // 10bit to 12bit.
477 assert_eq!(rgb::Image::rescale_alpha_value(0, 1023.0, 4095), 0);
478 assert_eq!(rgb::Image::rescale_alpha_value(401, 1023.0, 4095), 1605);
479 assert_eq!(rgb::Image::rescale_alpha_value(514, 1023.0, 4095), 2058);
480 assert_eq!(rgb::Image::rescale_alpha_value(1023, 1023.0, 4095), 4095);
481 // 12bit to 10bit.
482 assert_eq!(rgb::Image::rescale_alpha_value(0, 4095.0, 1023), 0);
483 assert_eq!(rgb::Image::rescale_alpha_value(1606, 4095.0, 1023), 401);
484 assert_eq!(rgb::Image::rescale_alpha_value(2056, 4095.0, 1023), 514);
485 assert_eq!(rgb::Image::rescale_alpha_value(4095, 4095.0, 1023), 1023);
486 }
487
488 #[test_matrix(20, 10, [8, 10, 12, 16], 0..4, [8, 10, 12], [true, false])]
reformat_alpha( width: u32, height: u32, rgb_depth: u8, format_index: usize, yuv_depth: u8, use_pointer: bool, ) -> AvifResult<()>489 fn reformat_alpha(
490 width: u32,
491 height: u32,
492 rgb_depth: u8,
493 format_index: usize,
494 yuv_depth: u8,
495 use_pointer: bool,
496 ) -> AvifResult<()> {
497 // Note: This test simply makes sure reformat_alpha puts the alpha pixels in the right
498 // place in the rgb image (with scaling). It does not check for the actual validity of the
499 // scaled pixels.
500 let format = ALPHA_RGB_FORMATS[format_index];
501 let mut buffer: Vec<u8> = vec![];
502 let mut rgb = rgb_image(width, height, rgb_depth, format, use_pointer, &mut buffer)?;
503
504 let mut image = image::Image::default();
505 image.width = width;
506 image.height = height;
507 image.depth = yuv_depth;
508 image.allocate_planes(Category::Alpha)?;
509
510 let mut rng = rand::thread_rng();
511 let mut expected_values: Vec<u16> = Vec::new();
512 let image_max_channel_f = image.max_channel_f();
513 if yuv_depth == 8 {
514 for y in 0..height {
515 let row = image.row_mut(Plane::A, y)?;
516 for x in 0..width as usize {
517 let value = rng.gen_range(0..256) as u8;
518 if rgb.depth == 8 {
519 expected_values.push(value as u16);
520 } else {
521 expected_values.push(rgb::Image::rescale_alpha_value(
522 value as u16,
523 image_max_channel_f,
524 rgb.max_channel(),
525 ));
526 }
527 row[x] = value;
528 }
529 }
530 } else {
531 for y in 0..height {
532 let row = image.row16_mut(Plane::A, y)?;
533 for x in 0..width as usize {
534 let value = rng.gen_range(0..(1i32 << yuv_depth)) as u16;
535 if rgb.depth == yuv_depth {
536 expected_values.push(value);
537 } else {
538 expected_values.push(rgb::Image::rescale_alpha_value(
539 value as u16,
540 image_max_channel_f,
541 rgb.max_channel(),
542 ));
543 }
544 row[x] = value;
545 }
546 }
547 }
548
549 rgb.import_alpha_from(&image)?;
550
551 let alpha_offset = rgb.format.alpha_offset();
552 let mut expected_values = expected_values.into_iter();
553 if rgb_depth == 8 {
554 for y in 0..height {
555 let rgb_row = rgb.row(y)?;
556 assert_eq!(rgb_row.len(), (width * 4) as usize);
557 for x in 0..width as usize {
558 for idx in 0..4usize {
559 let expected_value =
560 if idx == alpha_offset { expected_values.next().unwrap() } else { 0 };
561 assert_eq!(rgb_row[x * 4 + idx], expected_value as u8);
562 }
563 }
564 }
565 } else {
566 for y in 0..height {
567 let rgb_row = rgb.row16(y)?;
568 assert_eq!(rgb_row.len(), (width * 4) as usize);
569 for x in 0..width as usize {
570 for idx in 0..4usize {
571 let expected_value =
572 if idx == alpha_offset { expected_values.next().unwrap() } else { 0 };
573 assert_eq!(rgb_row[x * 4 + idx], expected_value);
574 }
575 }
576 }
577 }
578 Ok(())
579 }
580 }
581