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