• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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::image::Plane;
21 use crate::internal_utils::*;
22 use crate::reformat::rgb::Format;
23 use crate::*;
24 
premultiply_u8(pixel: u8, alpha: u8) -> u825 fn premultiply_u8(pixel: u8, alpha: u8) -> u8 {
26     ((pixel as f32) * (alpha as f32) / 255.0).floor() as u8
27 }
28 
premultiply_u16(pixel: u16, alpha: u16, max_channel_f: f32) -> u1629 fn premultiply_u16(pixel: u16, alpha: u16, max_channel_f: f32) -> u16 {
30     ((pixel as f32) * (alpha as f32) / max_channel_f).floor() as u16
31 }
32 
unpremultiply_u8(pixel: u8, alpha: u8) -> u833 fn unpremultiply_u8(pixel: u8, alpha: u8) -> u8 {
34     ((pixel as f32) * 255.0 / (alpha as f32)).floor().min(255.0) as u8
35 }
36 
unpremultiply_u16(pixel: u16, alpha: u16, max_channel_f: f32) -> u1637 fn unpremultiply_u16(pixel: u16, alpha: u16, max_channel_f: f32) -> u16 {
38     ((pixel as f32) * max_channel_f / (alpha as f32))
39         .floor()
40         .min(max_channel_f) as u16
41 }
42 
43 macro_rules! alpha_index_in_rgba_1010102 {
44     ($x:expr) => {{
45         // The index of the alpha pixel depends on the endianness since each pixel is a u32 in this
46         // case. The alpha value is the 2-bit MSB of the pixel at this index.
47         $x * 2 + if cfg!(target_endian = "little") { 1 } else { 0 }
48     }};
49 }
50 
51 impl rgb::Image {
premultiply_alpha(&mut self) -> AvifResult<()>52     pub(crate) fn premultiply_alpha(&mut self) -> AvifResult<()> {
53         if self.pixels().is_null() || self.row_bytes == 0 {
54             return Err(AvifError::ReformatFailed);
55         }
56         if !self.has_alpha() {
57             return Err(AvifError::InvalidArgument);
58         }
59 
60         #[cfg(feature = "libyuv")]
61         match libyuv::process_alpha(self, true) {
62             Ok(_) => return Ok(()),
63             Err(err) => {
64                 if err != AvifError::NotImplemented {
65                     return Err(err);
66                 }
67             }
68         }
69 
70         let (alpha_offset, rgb_offsets) = match self.format {
71             Format::Rgba | Format::Bgra => (3, [0, 1, 2]),
72             _ => (0, [1, 2, 3]),
73         };
74 
75         if self.depth > 8 {
76             let max_channel = self.max_channel();
77             let max_channel_f = self.max_channel_f();
78             for j in 0..self.height {
79                 let width = self.width;
80                 let row = self.row16_mut(j)?;
81                 for i in 0..width as usize {
82                     let offset = i * 4;
83                     let alpha = row[offset + alpha_offset];
84                     if alpha >= max_channel {
85                         continue;
86                     }
87                     if alpha == 0 {
88                         for rgb_offset in rgb_offsets {
89                             row[offset + rgb_offset] = 0;
90                         }
91                         continue;
92                     }
93                     for rgb_offset in rgb_offsets {
94                         row[offset + rgb_offset] =
95                             premultiply_u16(row[offset + rgb_offset], alpha, max_channel_f);
96                     }
97                 }
98             }
99         } else {
100             for j in 0..self.height {
101                 let width = self.width;
102                 let row = self.row_mut(j)?;
103                 for i in 0..width as usize {
104                     let offset = i * 4;
105                     let alpha = row[offset + alpha_offset];
106                     match alpha {
107                         0 => {
108                             for rgb_offset in rgb_offsets {
109                                 row[offset + rgb_offset] = 0;
110                             }
111                         }
112                         255 => {}
113                         _ => {
114                             for rgb_offset in rgb_offsets {
115                                 row[offset + rgb_offset] =
116                                     premultiply_u8(row[offset + rgb_offset], alpha);
117                             }
118                         }
119                     }
120                 }
121             }
122         }
123         Ok(())
124     }
125 
unpremultiply_alpha(&mut self) -> AvifResult<()>126     pub(crate) fn unpremultiply_alpha(&mut self) -> AvifResult<()> {
127         if self.pixels().is_null() || self.row_bytes == 0 {
128             return Err(AvifError::ReformatFailed);
129         }
130         if !self.has_alpha() {
131             return Err(AvifError::InvalidArgument);
132         }
133 
134         #[cfg(feature = "libyuv")]
135         match libyuv::process_alpha(self, false) {
136             Ok(_) => return Ok(()),
137             Err(err) => {
138                 if err != AvifError::NotImplemented {
139                     return Err(err);
140                 }
141             }
142         }
143 
144         let (alpha_offset, rgb_offsets) = match self.format {
145             Format::Rgba | Format::Bgra => (3, [0, 1, 2]),
146             _ => (0, [1, 2, 3]),
147         };
148 
149         if self.depth > 8 {
150             let max_channel = self.max_channel();
151             let max_channel_f = self.max_channel_f();
152             for j in 0..self.height {
153                 let width = self.width;
154                 let row = self.row16_mut(j)?;
155                 for i in 0..width as usize {
156                     let offset = i * 4;
157                     let alpha = row[offset + alpha_offset];
158                     if alpha >= max_channel {
159                         continue;
160                     }
161                     if alpha == 0 {
162                         for rgb_offset in rgb_offsets {
163                             row[offset + rgb_offset] = 0;
164                         }
165                         continue;
166                     }
167                     for rgb_offset in rgb_offsets {
168                         row[offset + rgb_offset] =
169                             unpremultiply_u16(row[offset + rgb_offset], alpha, max_channel_f);
170                     }
171                 }
172             }
173         } else {
174             for j in 0..self.height {
175                 let width = self.width;
176                 let row = self.row_mut(j)?;
177                 for i in 0..width as usize {
178                     let offset = i * 4;
179                     let alpha = row[offset + alpha_offset];
180                     match alpha {
181                         0 => {
182                             for rgb_offset in rgb_offsets {
183                                 row[offset + rgb_offset] = 0;
184                             }
185                         }
186                         255 => {}
187                         _ => {
188                             for rgb_offset in rgb_offsets {
189                                 row[offset + rgb_offset] =
190                                     unpremultiply_u8(row[offset + rgb_offset], alpha);
191                             }
192                         }
193                     }
194                 }
195             }
196         }
197         Ok(())
198     }
199 
set_opaque(&mut self) -> AvifResult<()>200     pub(crate) fn set_opaque(&mut self) -> AvifResult<()> {
201         if !self.has_alpha() {
202             return Ok(());
203         }
204         if self.format == rgb::Format::Rgb565 {
205             return Err(AvifError::NotImplemented);
206         }
207         let alpha_offset = self.format.alpha_offset();
208         let width = usize_from_u32(self.width)?;
209         if self.depth > 8 {
210             let max_channel = self.max_channel();
211             for y in 0..self.height {
212                 let row = self.row16_mut(y)?;
213                 for x in 0..width {
214                     row[(x * 4) + alpha_offset] = max_channel;
215                 }
216             }
217         } else {
218             for y in 0..self.height {
219                 let row = self.row_mut(y)?;
220                 for x in 0..width {
221                     row[(x * 4) + alpha_offset] = 255;
222                 }
223             }
224         }
225         Ok(())
226     }
227 
rescale_alpha_value(value: u16, src_max_channel_f: f32, dst_max_channel: u16) -> u16228     fn rescale_alpha_value(value: u16, src_max_channel_f: f32, dst_max_channel: u16) -> u16 {
229         let alpha_f = (value as f32) / src_max_channel_f;
230         let dst_max_channel_f = dst_max_channel as f32;
231         let alpha = (0.5 + (alpha_f * dst_max_channel_f)) as u16;
232         clamp_u16(alpha, 0, dst_max_channel)
233     }
234 
import_alpha_from(&mut self, image: &image::Image) -> AvifResult<()>235     pub(crate) fn import_alpha_from(&mut self, image: &image::Image) -> AvifResult<()> {
236         if !self.has_alpha()
237             || !image.has_alpha()
238             || self.width != image.width
239             || self.height != image.height
240         {
241             return Err(AvifError::InvalidArgument);
242         }
243         let width = usize_from_u32(self.width)?;
244         if self.format == Format::Rgba1010102 {
245             // Clippy warns about the loops using x as an index for src_row. But it is also used to
246             // compute the index for dst_row. Disable the warnings.
247             #[allow(clippy::needless_range_loop)]
248             if image.depth > 8 {
249                 for y in 0..self.height {
250                     let dst_row = self.row16_mut(y)?;
251                     let src_row = image.row16(Plane::A, y)?;
252                     for x in 0..width {
253                         let alpha_pixel = (src_row[x]) >> (image.depth - 2);
254                         let index = alpha_index_in_rgba_1010102!(x);
255                         dst_row[index] = (dst_row[index] & 0x3fff) | (alpha_pixel << 14);
256                     }
257                 }
258             } else {
259                 for y in 0..self.height {
260                     let dst_row = self.row16_mut(y)?;
261                     let src_row = image.row(Plane::A, y)?;
262                     for x in 0..width {
263                         let alpha_pixel = ((src_row[x]) >> 6) as u16;
264                         let index = alpha_index_in_rgba_1010102!(x);
265                         dst_row[index] = (dst_row[index] & 0x3fff) | (alpha_pixel << 14);
266                     }
267                 }
268             }
269             return Ok(());
270         }
271         let dst_alpha_offset = self.format.alpha_offset();
272         if self.depth == image.depth {
273             if self.depth > 8 {
274                 for y in 0..self.height {
275                     let dst_row = self.row16_mut(y)?;
276                     let src_row = image.row16(Plane::A, y)?;
277                     for x in 0..width {
278                         dst_row[(x * 4) + dst_alpha_offset] = src_row[x];
279                     }
280                 }
281                 return Ok(());
282             }
283             for y in 0..self.height {
284                 let dst_row = self.row_mut(y)?;
285                 let src_row = image.row(Plane::A, y)?;
286                 for x in 0..width {
287                     dst_row[(x * 4) + dst_alpha_offset] = src_row[x];
288                 }
289             }
290             return Ok(());
291         }
292         let max_channel = self.max_channel();
293         if image.depth > 8 {
294             if self.depth > 8 {
295                 // u16 to u16 depth rescaling.
296                 for y in 0..self.height {
297                     let dst_row = self.row16_mut(y)?;
298                     let src_row = image.row16(Plane::A, y)?;
299                     for x in 0..width {
300                         dst_row[(x * 4) + dst_alpha_offset] = Self::rescale_alpha_value(
301                             src_row[x],
302                             image.max_channel_f(),
303                             max_channel,
304                         );
305                     }
306                 }
307                 return Ok(());
308             }
309             // u16 to u8 depth rescaling.
310             for y in 0..self.height {
311                 let dst_row = self.row_mut(y)?;
312                 let src_row = image.row16(Plane::A, y)?;
313                 for x in 0..width {
314                     dst_row[(x * 4) + dst_alpha_offset] =
315                         Self::rescale_alpha_value(src_row[x], image.max_channel_f(), max_channel)
316                             as u8;
317                 }
318             }
319             return Ok(());
320         }
321         // u8 to u16 depth rescaling.
322         for y in 0..self.height {
323             let dst_row = self.row16_mut(y)?;
324             let src_row = image.row(Plane::A, y)?;
325             for x in 0..width {
326                 dst_row[(x * 4) + dst_alpha_offset] = Self::rescale_alpha_value(
327                     src_row[x] as u16,
328                     image.max_channel_f(),
329                     max_channel,
330                 );
331             }
332         }
333         Ok(())
334     }
335 }
336 
337 impl image::Image {
alpha_to_full_range(&mut self) -> AvifResult<()>338     pub(crate) fn alpha_to_full_range(&mut self) -> AvifResult<()> {
339         if self.planes[3].is_none() {
340             return Ok(());
341         }
342         let width = self.width as usize;
343         let depth = self.depth;
344         if self.planes[3].unwrap_ref().is_pointer() {
345             let src = image::Image {
346                 width: self.width,
347                 height: self.height,
348                 depth: self.depth,
349                 yuv_format: self.yuv_format,
350                 planes: [
351                     None,
352                     None,
353                     None,
354                     Some(self.planes[3].unwrap_ref().try_clone()?),
355                 ],
356                 row_bytes: [0, 0, 0, self.row_bytes[3]],
357                 ..image::Image::default()
358             };
359             self.allocate_planes(Category::Alpha)?;
360             if depth > 8 {
361                 for y in 0..self.height {
362                     let src_row = src.row16(Plane::A, y)?;
363                     let dst_row = self.row16_mut(Plane::A, y)?;
364                     for x in 0..width {
365                         dst_row[x] = limited_to_full_y(depth, src_row[x]);
366                     }
367                 }
368             } else {
369                 for y in 0..self.height {
370                     let src_row = src.row(Plane::A, y)?;
371                     let dst_row = self.row_mut(Plane::A, y)?;
372                     for x in 0..width {
373                         dst_row[x] = limited_to_full_y(8, src_row[x] as u16) as u8;
374                     }
375                 }
376             }
377         } else if depth > 8 {
378             for y in 0..self.height {
379                 let row = self.row16_mut(Plane::A, y)?;
380                 for pixel in row.iter_mut().take(width) {
381                     *pixel = limited_to_full_y(depth, *pixel);
382                 }
383             }
384         } else {
385             for y in 0..self.height {
386                 let row = self.row_mut(Plane::A, y)?;
387                 for pixel in row.iter_mut().take(width) {
388                     *pixel = limited_to_full_y(8, *pixel as u16) as u8;
389                 }
390             }
391         }
392         Ok(())
393     }
394 }
395 
396 #[cfg(test)]
397 mod tests {
398     use super::*;
399 
400     use crate::internal_utils::pixels::*;
401 
402     use rand::Rng;
403     use test_case::test_matrix;
404 
405     const ALPHA_RGB_FORMATS: [rgb::Format; 4] = [
406         rgb::Format::Rgba,
407         rgb::Format::Argb,
408         rgb::Format::Bgra,
409         rgb::Format::Abgr,
410     ];
411 
rgb_image( width: u32, height: u32, depth: u8, format: rgb::Format, use_pointer: bool, buffer: &mut Vec<u8>, ) -> AvifResult<rgb::Image>412     fn rgb_image(
413         width: u32,
414         height: u32,
415         depth: u8,
416         format: rgb::Format,
417         use_pointer: bool,
418         buffer: &mut Vec<u8>,
419     ) -> AvifResult<rgb::Image> {
420         let mut rgb = rgb::Image {
421             width,
422             height,
423             depth,
424             format,
425             ..rgb::Image::default()
426         };
427         if use_pointer {
428             let pixel_size = if depth == 8 { 1 } else { 2 };
429             let buffer_size = (width * height * 4 * pixel_size) as usize;
430             buffer.reserve_exact(buffer_size);
431             buffer.resize(buffer_size, 0);
432             rgb.row_bytes = width * 4 * pixel_size;
433             // Use a pointer to mimic C API calls.
434             rgb.pixels = Some(Pixels::from_raw_pointer(
435                 buffer.as_mut_ptr(),
436                 rgb.depth as u32,
437                 height,
438                 rgb.row_bytes,
439             )?);
440         } else {
441             rgb.allocate()?;
442         }
443         Ok(rgb)
444     }
445 
446     #[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<()>447     fn fill_alpha(
448         width: u32,
449         height: u32,
450         depth: u8,
451         format_index: usize,
452         use_pointer: bool,
453     ) -> AvifResult<()> {
454         let format = ALPHA_RGB_FORMATS[format_index];
455         let mut buffer: Vec<u8> = vec![];
456         let mut rgb = rgb_image(width, height, depth, format, use_pointer, &mut buffer)?;
457 
458         rgb.set_opaque()?;
459 
460         let alpha_offset = rgb.format.alpha_offset();
461         if depth == 8 {
462             for y in 0..height {
463                 let row = rgb.row(y)?;
464                 assert_eq!(row.len(), (width * 4) as usize);
465                 for x in 0..width as usize {
466                     for idx in 0..4usize {
467                         let expected_value = if idx == alpha_offset { 255 } else { 0 };
468                         assert_eq!(row[x * 4 + idx], expected_value);
469                     }
470                 }
471             }
472         } else {
473             let max_channel = ((1 << depth) - 1) as u16;
474             for y in 0..height {
475                 let row = rgb.row16(y)?;
476                 assert_eq!(row.len(), (width * 4) as usize);
477                 for x in 0..width as usize {
478                     for idx in 0..4usize {
479                         let expected_value = if idx == alpha_offset { max_channel } else { 0 };
480                         assert_eq!(row[x * 4 + idx], expected_value);
481                     }
482                 }
483             }
484         }
485         Ok(())
486     }
487 
488     #[test]
rescale_alpha_value()489     fn rescale_alpha_value() {
490         // 8bit to 10bit.
491         assert_eq!(rgb::Image::rescale_alpha_value(0, 255.0, 1023), 0);
492         assert_eq!(rgb::Image::rescale_alpha_value(100, 255.0, 1023), 401);
493         assert_eq!(rgb::Image::rescale_alpha_value(128, 255.0, 1023), 514);
494         assert_eq!(rgb::Image::rescale_alpha_value(255, 255.0, 1023), 1023);
495         // 10bit to 8bit.
496         assert_eq!(rgb::Image::rescale_alpha_value(0, 1023.0, 255), 0);
497         assert_eq!(rgb::Image::rescale_alpha_value(401, 1023.0, 255), 100);
498         assert_eq!(rgb::Image::rescale_alpha_value(514, 1023.0, 255), 128);
499         assert_eq!(rgb::Image::rescale_alpha_value(1023, 1023.0, 255), 255);
500         // 8bit to 12bit.
501         assert_eq!(rgb::Image::rescale_alpha_value(0, 255.0, 4095), 0);
502         assert_eq!(rgb::Image::rescale_alpha_value(100, 255.0, 4095), 1606);
503         assert_eq!(rgb::Image::rescale_alpha_value(128, 255.0, 4095), 2056);
504         assert_eq!(rgb::Image::rescale_alpha_value(255, 255.0, 4095), 4095);
505         // 12bit to 8bit.
506         assert_eq!(rgb::Image::rescale_alpha_value(0, 4095.0, 255), 0);
507         assert_eq!(rgb::Image::rescale_alpha_value(1606, 4095.0, 255), 100);
508         assert_eq!(rgb::Image::rescale_alpha_value(2056, 4095.0, 255), 128);
509         assert_eq!(rgb::Image::rescale_alpha_value(4095, 4095.0, 255), 255);
510         // 10bit to 12bit.
511         assert_eq!(rgb::Image::rescale_alpha_value(0, 1023.0, 4095), 0);
512         assert_eq!(rgb::Image::rescale_alpha_value(401, 1023.0, 4095), 1605);
513         assert_eq!(rgb::Image::rescale_alpha_value(514, 1023.0, 4095), 2058);
514         assert_eq!(rgb::Image::rescale_alpha_value(1023, 1023.0, 4095), 4095);
515         // 12bit to 10bit.
516         assert_eq!(rgb::Image::rescale_alpha_value(0, 4095.0, 1023), 0);
517         assert_eq!(rgb::Image::rescale_alpha_value(1606, 4095.0, 1023), 401);
518         assert_eq!(rgb::Image::rescale_alpha_value(2056, 4095.0, 1023), 514);
519         assert_eq!(rgb::Image::rescale_alpha_value(4095, 4095.0, 1023), 1023);
520     }
521 
522     #[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<()>523     fn reformat_alpha(
524         width: u32,
525         height: u32,
526         rgb_depth: u8,
527         format_index: usize,
528         yuv_depth: u8,
529         use_pointer: bool,
530     ) -> AvifResult<()> {
531         // Note: This test simply makes sure reformat_alpha puts the alpha pixels in the right
532         // place in the rgb image (with scaling). It does not check for the actual validity of the
533         // scaled pixels.
534         let format = ALPHA_RGB_FORMATS[format_index];
535         let mut buffer: Vec<u8> = vec![];
536         let mut rgb = rgb_image(width, height, rgb_depth, format, use_pointer, &mut buffer)?;
537 
538         let mut image = image::Image::default();
539         image.width = width;
540         image.height = height;
541         image.depth = yuv_depth;
542         image.allocate_planes(Category::Alpha)?;
543 
544         let mut rng = rand::thread_rng();
545         let mut expected_values: Vec<u16> = Vec::new();
546         let image_max_channel_f = image.max_channel_f();
547         if yuv_depth == 8 {
548             for y in 0..height {
549                 let row = image.row_mut(Plane::A, y)?;
550                 for x in 0..width as usize {
551                     let value = rng.gen_range(0..256) as u8;
552                     if rgb.depth == 8 {
553                         expected_values.push(value as u16);
554                     } else {
555                         expected_values.push(rgb::Image::rescale_alpha_value(
556                             value as u16,
557                             image_max_channel_f,
558                             rgb.max_channel(),
559                         ));
560                     }
561                     row[x] = value;
562                 }
563             }
564         } else {
565             for y in 0..height {
566                 let row = image.row16_mut(Plane::A, y)?;
567                 for x in 0..width as usize {
568                     let value = rng.gen_range(0..(1i32 << yuv_depth)) as u16;
569                     if rgb.depth == yuv_depth {
570                         expected_values.push(value);
571                     } else {
572                         expected_values.push(rgb::Image::rescale_alpha_value(
573                             value as u16,
574                             image_max_channel_f,
575                             rgb.max_channel(),
576                         ));
577                     }
578                     row[x] = value;
579                 }
580             }
581         }
582 
583         rgb.import_alpha_from(&image)?;
584 
585         let alpha_offset = rgb.format.alpha_offset();
586         let mut expected_values = expected_values.into_iter();
587         if rgb_depth == 8 {
588             for y in 0..height {
589                 let rgb_row = rgb.row(y)?;
590                 assert_eq!(rgb_row.len(), (width * 4) as usize);
591                 for x in 0..width as usize {
592                     for idx in 0..4usize {
593                         let expected_value =
594                             if idx == alpha_offset { expected_values.next().unwrap() } else { 0 };
595                         assert_eq!(rgb_row[x * 4 + idx], expected_value as u8);
596                     }
597                 }
598             }
599         } else {
600             for y in 0..height {
601                 let rgb_row = rgb.row16(y)?;
602                 assert_eq!(rgb_row.len(), (width * 4) as usize);
603                 for x in 0..width as usize {
604                     for idx in 0..4usize {
605                         let expected_value =
606                             if idx == alpha_offset { expected_values.next().unwrap() } else { 0 };
607                         assert_eq!(rgb_row[x * 4 + idx], expected_value);
608                     }
609                 }
610             }
611         }
612         Ok(())
613     }
614 
615     #[test_matrix(20, 10, 10, [8, 10, 12])]
reformat_alpha_rgba1010102( width: u32, height: u32, rgb_depth: u8, yuv_depth: u8, ) -> AvifResult<()>616     fn reformat_alpha_rgba1010102(
617         width: u32,
618         height: u32,
619         rgb_depth: u8,
620         yuv_depth: u8,
621     ) -> AvifResult<()> {
622         let format = rgb::Format::Rgba1010102;
623         let mut buffer: Vec<u8> = vec![];
624         let mut rgb = rgb_image(
625             width,
626             height,
627             rgb_depth,
628             format,
629             /*use_pointer*/ false,
630             &mut buffer,
631         )?;
632 
633         let mut image = image::Image::default();
634         image.width = width;
635         image.height = height;
636         image.depth = yuv_depth;
637         image.allocate_planes(Category::Alpha)?;
638 
639         let mut rng = rand::thread_rng();
640         let mut expected_values: Vec<u16> = Vec::new();
641         if yuv_depth == 8 {
642             for y in 0..height {
643                 let row = image.row_mut(Plane::A, y)?;
644                 for x in 0..width as usize {
645                     let value = rng.gen_range(0..256) as u8;
646                     expected_values.push((value >> 6) as u16);
647                     row[x] = value;
648                 }
649             }
650         } else {
651             for y in 0..height {
652                 let row = image.row16_mut(Plane::A, y)?;
653                 for x in 0..width as usize {
654                     let value = rng.gen_range(0..(1i32 << yuv_depth)) as u16;
655                     expected_values.push(value >> (yuv_depth - 2));
656                     row[x] = value;
657                 }
658             }
659         }
660 
661         rgb.import_alpha_from(&image)?;
662 
663         let mut expected_values = expected_values.into_iter();
664         for y in 0..height {
665             let rgb_row = rgb.row16(y)?;
666             assert_eq!(rgb_row.len(), (width * 2) as usize);
667             for x in 0..width as usize {
668                 assert_eq!(
669                     rgb_row[alpha_index_in_rgba_1010102!(x)] >> 14,
670                     expected_values.next().unwrap()
671                 );
672             }
673         }
674         Ok(())
675     }
676 }
677