• 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 use crabby_avif::decoder::track::RepetitionCount;
16 use crabby_avif::decoder::CompressionFormat;
17 use crabby_avif::decoder::ImageContentType;
18 use crabby_avif::image::*;
19 use crabby_avif::reformat::rgb;
20 use crabby_avif::*;
21 
22 #[path = "./mod.rs"]
23 mod tests;
24 
25 use std::cell::RefCell;
26 use std::rc::Rc;
27 use tests::*;
28 
29 // From avifalphanoispetest.cc
30 #[test]
alpha_no_ispe()31 fn alpha_no_ispe() {
32     // See https://github.com/AOMediaCodec/libavif/pull/745.
33     let mut decoder = get_decoder("alpha_noispe.avif");
34     // By default, non-strict files are refused.
35     assert!(matches!(
36         decoder.settings.strictness,
37         decoder::Strictness::All
38     ));
39     let res = decoder.parse();
40     assert!(matches!(res, Err(AvifError::BmffParseFailed(_))));
41     // Allow this kind of file specifically.
42     decoder.settings.strictness =
43         decoder::Strictness::SpecificExclude(vec![decoder::StrictnessFlag::AlphaIspeRequired]);
44     let res = decoder.parse();
45     assert!(res.is_ok());
46     let image = decoder.image().expect("image was none");
47     assert!(image.alpha_present);
48     assert!(!image.image_sequence_track_present);
49     if !HAS_DECODER {
50         return;
51     }
52     let res = decoder.next_image();
53     assert!(res.is_ok());
54     let image = decoder.image().expect("image was none");
55     let alpha_plane = image.plane_data(Plane::A);
56     assert!(alpha_plane.is_some());
57     assert!(alpha_plane.unwrap().row_bytes > 0);
58 }
59 
60 #[test]
alpha_premultiplied()61 fn alpha_premultiplied() {
62     let mut decoder = get_decoder("alpha_premultiplied.avif");
63     let res = decoder.parse();
64     assert!(res.is_ok());
65     let image = decoder.image().expect("image was none");
66     assert!(image.alpha_present);
67     assert!(image.alpha_premultiplied);
68     if !HAS_DECODER {
69         return;
70     }
71     let res = decoder.next_image();
72     assert!(res.is_ok());
73     let image = decoder.image().expect("image was none");
74     assert!(image.alpha_present);
75     assert!(image.alpha_premultiplied);
76     let alpha_plane = image.plane_data(Plane::A);
77     assert!(alpha_plane.is_some());
78     assert!(alpha_plane.unwrap().row_bytes > 0);
79 }
80 
81 // From avifanimationtest.cc
82 #[test_case::test_case("colors-animated-8bpc.avif")]
83 #[test_case::test_case("colors-animated-8bpc-audio.avif")]
animated_image(filename: &str)84 fn animated_image(filename: &str) {
85     let mut decoder = get_decoder(filename);
86     let res = decoder.parse();
87     assert!(res.is_ok());
88     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
89     let image = decoder.image().expect("image was none");
90     assert!(!image.alpha_present);
91     assert!(image.image_sequence_track_present);
92     assert_eq!(decoder.image_count(), 5);
93     assert_eq!(decoder.repetition_count(), RepetitionCount::Finite(0));
94     for i in 0..5 {
95         assert_eq!(decoder.nearest_keyframe(i), 0);
96     }
97     if !HAS_DECODER {
98         return;
99     }
100     for _ in 0..5 {
101         assert!(decoder.next_image().is_ok());
102     }
103 }
104 
105 // From avifanimationtest.cc
106 #[test_case::test_case("colors-animated-8bpc.avif")]
107 #[test_case::test_case("colors-animated-8bpc-audio.avif")]
animated_image_with_source_set_to_primary_item(filename: &str)108 fn animated_image_with_source_set_to_primary_item(filename: &str) {
109     let mut decoder = get_decoder(filename);
110     decoder.settings.source = decoder::Source::PrimaryItem;
111     let res = decoder.parse();
112     assert!(res.is_ok());
113     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
114     let image = decoder.image().expect("image was none");
115     assert!(!image.alpha_present);
116     // This will be reported as true irrespective of the preferred source.
117     assert!(image.image_sequence_track_present);
118     // imageCount is expected to be 1 because we are using primary item as the
119     // preferred source.
120     assert_eq!(decoder.image_count(), 1);
121     assert_eq!(decoder.repetition_count(), RepetitionCount::Finite(0));
122     if !HAS_DECODER {
123         return;
124     }
125     // Get the first (and only) image.
126     assert!(decoder.next_image().is_ok());
127     // Subsequent calls should not return anything since there is only one
128     // image in the preferred source.
129     assert!(decoder.next_image().is_err());
130 }
131 
132 // From avifanimationtest.cc
133 #[test]
animated_image_with_alpha_and_metadata()134 fn animated_image_with_alpha_and_metadata() {
135     let mut decoder = get_decoder("colors-animated-8bpc-alpha-exif-xmp.avif");
136     let res = decoder.parse();
137     assert!(res.is_ok());
138     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
139     let image = decoder.image().expect("image was none");
140     assert!(image.alpha_present);
141     assert!(image.image_sequence_track_present);
142     assert_eq!(decoder.image_count(), 5);
143     assert_eq!(decoder.repetition_count(), RepetitionCount::Infinite);
144     assert_eq!(image.exif.len(), 1126);
145     assert_eq!(image.xmp.len(), 3898);
146     if !HAS_DECODER {
147         return;
148     }
149     for _ in 0..5 {
150         assert!(decoder.next_image().is_ok());
151     }
152 }
153 
154 #[test]
animated_image_with_depth_and_metadata()155 fn animated_image_with_depth_and_metadata() {
156     // Depth map data is not supported and should be ignored.
157     let mut decoder = get_decoder("colors-animated-8bpc-depth-exif-xmp.avif");
158     let res = decoder.parse();
159     assert!(res.is_ok());
160     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
161     let image = decoder.image().expect("image was none");
162     assert!(!image.alpha_present);
163     assert!(image.image_sequence_track_present);
164     assert_eq!(decoder.image_count(), 5);
165     assert_eq!(decoder.repetition_count(), RepetitionCount::Infinite);
166     assert_eq!(image.exif.len(), 1126);
167     assert_eq!(image.xmp.len(), 3898);
168     if !HAS_DECODER {
169         return;
170     }
171     for _ in 0..5 {
172         assert!(decoder.next_image().is_ok());
173     }
174 }
175 
176 #[test]
animated_image_with_depth_and_metadata_source_set_to_primary_item()177 fn animated_image_with_depth_and_metadata_source_set_to_primary_item() {
178     // Depth map data is not supported and should be ignored.
179     let mut decoder = get_decoder("colors-animated-8bpc-depth-exif-xmp.avif");
180     decoder.settings.source = decoder::Source::PrimaryItem;
181     let res = decoder.parse();
182     assert!(res.is_ok());
183     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
184     let image = decoder.image().expect("image was none");
185     assert!(!image.alpha_present);
186     // This will be reported as true irrespective of the preferred source.
187     assert!(image.image_sequence_track_present);
188     // imageCount is expected to be 1 because we are using primary item as the
189     // preferred source.
190     assert_eq!(decoder.image_count(), 1);
191     assert_eq!(decoder.repetition_count(), RepetitionCount::Finite(0));
192     if !HAS_DECODER {
193         return;
194     }
195     // Get the first (and only) image.
196     assert!(decoder.next_image().is_ok());
197     // Subsequent calls should not return anything since there is only one
198     // image in the preferred source.
199     assert!(decoder.next_image().is_err());
200 }
201 
202 // From avifkeyframetest.cc
203 #[test]
keyframes()204 fn keyframes() {
205     let mut decoder = get_decoder("colors-animated-12bpc-keyframes-0-2-3.avif");
206     let res = decoder.parse();
207     assert!(res.is_ok());
208     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
209     let image = decoder.image().expect("image was none");
210     assert!(image.image_sequence_track_present);
211     assert_eq!(decoder.image_count(), 5);
212 
213     // First frame is always a keyframe.
214     assert!(decoder.is_keyframe(0));
215     assert_eq!(decoder.nearest_keyframe(0), 0);
216 
217     assert!(!decoder.is_keyframe(1));
218     assert_eq!(decoder.nearest_keyframe(1), 0);
219 
220     assert!(decoder.is_keyframe(2));
221     assert_eq!(decoder.nearest_keyframe(2), 2);
222 
223     assert!(decoder.is_keyframe(3));
224     assert_eq!(decoder.nearest_keyframe(3), 3);
225 
226     assert!(!decoder.is_keyframe(4));
227     assert_eq!(decoder.nearest_keyframe(4), 3);
228 
229     // Not an existing frame.
230     assert!(!decoder.is_keyframe(15));
231     assert_eq!(decoder.nearest_keyframe(15), 3);
232 }
233 
234 // From avifdecodetest.cc
235 #[test]
color_grid_alpha_no_grid()236 fn color_grid_alpha_no_grid() {
237     // Test case from https://github.com/AOMediaCodec/libavif/issues/1203.
238     let mut decoder = get_decoder("color_grid_alpha_nogrid.avif");
239     let res = decoder.parse();
240     assert!(res.is_ok());
241     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
242     let image = decoder.image().expect("image was none");
243     assert!(image.alpha_present);
244     assert!(!image.image_sequence_track_present);
245     if !HAS_DECODER {
246         return;
247     }
248     let res = decoder.next_image();
249     assert!(res.is_ok());
250     let image = decoder.image().expect("image was none");
251     let alpha_plane = image.plane_data(Plane::A);
252     assert!(alpha_plane.is_some());
253     assert!(alpha_plane.unwrap().row_bytes > 0);
254 }
255 
256 // From avifprogressivetest.cc
257 #[test_case::test_case("progressive_dimension_change.avif", 2, 256, 256; "progressive_dimension_change")]
258 #[test_case::test_case("progressive_layered_grid.avif", 2, 512, 256; "progressive_layered_grid")]
259 #[test_case::test_case("progressive_quality_change.avif", 2, 256, 256; "progressive_quality_change")]
260 #[test_case::test_case("progressive_same_layers.avif", 4, 256, 256; "progressive_same_layers")]
261 #[test_case::test_case("tiger_3layer_1res.avif", 3, 1216, 832; "tiger_3layer_1res")]
262 #[test_case::test_case("tiger_3layer_3res.avif", 3, 1216, 832; "tiger_3layer_3res")]
progressive(filename: &str, layer_count: u32, width: u32, height: u32)263 fn progressive(filename: &str, layer_count: u32, width: u32, height: u32) {
264     let mut filename_with_prefix = String::from("progressive/");
265     filename_with_prefix.push_str(filename);
266     let mut decoder = get_decoder(&filename_with_prefix);
267 
268     decoder.settings.allow_progressive = false;
269     let res = decoder.parse();
270     assert!(res.is_ok());
271     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
272     let image = decoder.image().expect("image was none");
273     assert!(matches!(
274         image.progressive_state,
275         decoder::ProgressiveState::Available
276     ));
277 
278     decoder.settings.allow_progressive = true;
279     let res = decoder.parse();
280     assert!(res.is_ok());
281     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
282     let image = decoder.image().expect("image was none");
283     assert!(matches!(
284         image.progressive_state,
285         decoder::ProgressiveState::Active
286     ));
287     assert_eq!(image.width, width);
288     assert_eq!(image.height, height);
289     assert_eq!(decoder.image_count(), layer_count);
290     if !HAS_DECODER {
291         return;
292     }
293     for _i in 0..decoder.image_count() {
294         let res = decoder.next_image();
295         assert!(res.is_ok());
296         let image = decoder.image().expect("image was none");
297         assert_eq!(image.width, width);
298         assert_eq!(image.height, height);
299     }
300 }
301 
302 // From avifmetadatatest.cc
303 #[test]
decoder_parse_icc_exif_xmp()304 fn decoder_parse_icc_exif_xmp() {
305     // Test case from https://github.com/AOMediaCodec/libavif/issues/1086.
306     let mut decoder = get_decoder("paris_icc_exif_xmp.avif");
307 
308     decoder.settings.ignore_xmp = true;
309     decoder.settings.ignore_exif = true;
310     let res = decoder.parse();
311     assert!(res.is_ok());
312     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
313     let image = decoder.image().expect("image was none");
314 
315     assert_eq!(image.icc.len(), 596);
316     assert_eq!(image.icc[0], 0);
317     assert_eq!(image.icc[1], 0);
318     assert_eq!(image.icc[2], 2);
319     assert_eq!(image.icc[3], 84);
320 
321     assert!(image.exif.is_empty());
322     assert!(image.xmp.is_empty());
323 
324     decoder.settings.ignore_xmp = false;
325     decoder.settings.ignore_exif = false;
326     let res = decoder.parse();
327     assert!(res.is_ok());
328     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
329     let image = decoder.image().expect("image was none");
330 
331     assert_eq!(image.exif.len(), 1126);
332     assert_eq!(image.exif[0], 73);
333     assert_eq!(image.exif[1], 73);
334     assert_eq!(image.exif[2], 42);
335     assert_eq!(image.exif[3], 0);
336 
337     assert_eq!(image.xmp.len(), 3898);
338     assert_eq!(image.xmp[0], 60);
339     assert_eq!(image.xmp[1], 63);
340     assert_eq!(image.xmp[2], 120);
341     assert_eq!(image.xmp[3], 112);
342 }
343 
344 // From avifgainmaptest.cc
345 #[test]
color_grid_gainmap_different_grid()346 fn color_grid_gainmap_different_grid() {
347     let mut decoder = get_decoder("color_grid_gainmap_different_grid.avif");
348     decoder.settings.image_content_to_decode = ImageContentType::All;
349     let res = decoder.parse();
350     assert!(res.is_ok());
351     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
352     let image = decoder.image().expect("image was none");
353     // Color+alpha: 4x3 grid of 128x200 tiles.
354     assert_eq!(image.width, 128 * 4);
355     assert_eq!(image.height, 200 * 3);
356     assert_eq!(image.depth, 10);
357     // Gain map: 2x2 grid of 64x80 tiles.
358     assert!(decoder.gainmap_present());
359     assert_eq!(decoder.gainmap().image.width, 64 * 2);
360     assert_eq!(decoder.gainmap().image.height, 80 * 2);
361     assert_eq!(decoder.gainmap().image.depth, 8);
362     assert_eq!(decoder.gainmap().metadata.base_hdr_headroom.0, 6);
363     assert_eq!(decoder.gainmap().metadata.base_hdr_headroom.1, 2);
364     if !HAS_DECODER {
365         return;
366     }
367     let res = decoder.next_image();
368     assert!(res.is_ok());
369     assert!(decoder.gainmap().image.row_bytes[0] > 0);
370 }
371 
372 // From avifgainmaptest.cc
373 #[test]
color_grid_alpha_grid_gainmap_nogrid()374 fn color_grid_alpha_grid_gainmap_nogrid() {
375     let mut decoder = get_decoder("color_grid_alpha_grid_gainmap_nogrid.avif");
376     decoder.settings.image_content_to_decode = ImageContentType::All;
377     let res = decoder.parse();
378     assert!(res.is_ok());
379     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
380     let image = decoder.image().expect("image was none");
381     // Color+alpha: 4x3 grid of 128x200 tiles.
382     assert_eq!(image.width, 128 * 4);
383     assert_eq!(image.height, 200 * 3);
384     assert_eq!(image.depth, 10);
385     // Gain map: single image of size 64x80.
386     assert!(decoder.gainmap_present());
387     assert_eq!(decoder.gainmap().image.width, 64);
388     assert_eq!(decoder.gainmap().image.height, 80);
389     assert_eq!(decoder.gainmap().image.depth, 8);
390     assert_eq!(decoder.gainmap().metadata.base_hdr_headroom.0, 6);
391     assert_eq!(decoder.gainmap().metadata.base_hdr_headroom.1, 2);
392     if !HAS_DECODER {
393         return;
394     }
395     let res = decoder.next_image();
396     assert!(res.is_ok());
397     assert!(decoder.gainmap().image.row_bytes[0] > 0);
398 }
399 
400 // From avifgainmaptest.cc
401 #[test]
color_nogrid_alpha_nogrid_gainmap_grid()402 fn color_nogrid_alpha_nogrid_gainmap_grid() {
403     let mut decoder = get_decoder("color_nogrid_alpha_nogrid_gainmap_grid.avif");
404     decoder.settings.image_content_to_decode = ImageContentType::All;
405     let res = decoder.parse();
406     assert!(res.is_ok());
407     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
408     let image = decoder.image().expect("image was none");
409     // Color+alpha: single image of size 128x200.
410     assert_eq!(image.width, 128);
411     assert_eq!(image.height, 200);
412     assert_eq!(image.depth, 10);
413     // Gain map: 2x2 grid of 64x80 tiles.
414     assert!(decoder.gainmap_present());
415     assert_eq!(decoder.gainmap().image.width, 64 * 2);
416     assert_eq!(decoder.gainmap().image.height, 80 * 2);
417     assert_eq!(decoder.gainmap().image.depth, 8);
418     assert_eq!(decoder.gainmap().metadata.base_hdr_headroom.0, 6);
419     assert_eq!(decoder.gainmap().metadata.base_hdr_headroom.1, 2);
420     if !HAS_DECODER {
421         return;
422     }
423     let res = decoder.next_image();
424     assert!(res.is_ok());
425     assert!(decoder.gainmap().image.row_bytes[0] > 0);
426 }
427 
428 // From avifgainmaptest.cc
429 #[test]
gainmap_oriented()430 fn gainmap_oriented() {
431     let mut decoder = get_decoder("gainmap_oriented.avif");
432     decoder.settings.image_content_to_decode = ImageContentType::All;
433     let res = decoder.parse();
434     assert!(res.is_ok());
435     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
436     let image = decoder.image().expect("image was none");
437     assert_eq!(image.irot_angle, Some(1));
438     assert_eq!(image.imir_axis, Some(0));
439     assert!(decoder.gainmap_present());
440     assert_eq!(decoder.gainmap().image.irot_angle, None);
441     assert_eq!(decoder.gainmap().image.imir_axis, None);
442 }
443 
444 // The two test files should produce the same results:
445 // One has an unsupported 'version' field, the other an unsupported
446 // 'minimum_version' field, but the behavior of these two files is the same.
447 // From avifgainmaptest.cc
448 #[test_case::test_case("unsupported_gainmap_version.avif")]
449 #[test_case::test_case("unsupported_gainmap_minimum_version.avif")]
decode_unsupported_version(filename: &str)450 fn decode_unsupported_version(filename: &str) {
451     // Parse with various settings.
452     let mut decoder = get_decoder(filename);
453     let res = decoder.parse();
454     assert!(res.is_ok());
455     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
456     // Gain map marked as not present because the metadata is not supported.
457     assert!(!decoder.gainmap_present());
458     assert_eq!(decoder.gainmap().image.width, 0);
459     assert_eq!(decoder.gainmap().metadata.base_hdr_headroom.0, 0);
460     assert_eq!(decoder.gainmap().metadata.alternate_hdr_headroom.0, 0);
461 
462     decoder = get_decoder(filename);
463     decoder.settings.image_content_to_decode = ImageContentType::All;
464     let res = decoder.parse();
465     assert!(res.is_ok());
466     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
467     // Gainmap not found: its metadata is not supported.
468     assert!(!decoder.gainmap_present());
469     assert_eq!(decoder.gainmap().image.width, 0);
470     assert_eq!(decoder.gainmap().metadata.base_hdr_headroom.0, 0);
471     assert_eq!(decoder.gainmap().metadata.alternate_hdr_headroom.0, 0);
472 }
473 
474 // From avifgainmaptest.cc
475 #[test]
decode_unsupported_writer_version_with_extra_bytes()476 fn decode_unsupported_writer_version_with_extra_bytes() {
477     let mut decoder = get_decoder("unsupported_gainmap_writer_version_with_extra_bytes.avif");
478     let res = decoder.parse();
479     assert!(res.is_ok());
480     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
481     // Decodes successfully: there are extra bytes at the end of the gain map
482     // metadata but that's expected as the writer_version field is higher
483     // that supported.
484     assert!(decoder.gainmap_present());
485     assert_eq!(decoder.gainmap().metadata.base_hdr_headroom.0, 6);
486     assert_eq!(decoder.gainmap().metadata.base_hdr_headroom.1, 2);
487 }
488 
489 // From avifgainmaptest.cc
490 #[test]
decode_supported_writer_version_with_extra_bytes()491 fn decode_supported_writer_version_with_extra_bytes() {
492     let mut decoder = get_decoder("supported_gainmap_writer_version_with_extra_bytes.avif");
493     let res = decoder.parse();
494     // Fails to decode: there are extra bytes at the end of the gain map metadata
495     // that shouldn't be there.
496     assert!(matches!(res, Err(AvifError::InvalidToneMappedImage(_))));
497 }
498 
499 // From avifgainmaptest.cc
500 #[test]
decode_ignore_gain_map_but_read_metadata()501 fn decode_ignore_gain_map_but_read_metadata() {
502     let mut decoder = get_decoder("seine_sdr_gainmap_srgb.avif");
503 
504     let res = decoder.parse();
505     assert!(res.is_ok());
506     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
507     decoder.image().expect("image was none");
508     // Gain map not decoded.
509     assert!(decoder.gainmap_present());
510     // ... but not decoded because enableDecodingGainMap is false by default.
511     assert_eq!(decoder.gainmap().image.width, 0);
512     assert_eq!(decoder.gainmap().image.row_bytes[0], 0);
513     // Check that the gain map metadata WAS populated.
514     assert_eq!(decoder.gainmap().metadata.alternate_hdr_headroom.0, 13);
515     assert_eq!(decoder.gainmap().metadata.alternate_hdr_headroom.1, 10);
516 }
517 
518 // From avifgainmaptest.cc
519 #[test]
decode_ignore_color_and_alpha()520 fn decode_ignore_color_and_alpha() {
521     let mut decoder = get_decoder("seine_sdr_gainmap_srgb.avif");
522     decoder.settings.image_content_to_decode = ImageContentType::GainMap;
523 
524     let res = decoder.parse();
525     assert!(res.is_ok());
526     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
527 
528     let image = decoder.image().expect("image was none");
529     // Main image metadata is available.
530     assert_eq!(image.width, 400);
531     // The gain map metadata is available.
532     assert!(decoder.gainmap_present());
533     assert_eq!(decoder.gainmap().image.width, 400);
534     assert_eq!(decoder.gainmap().metadata.alternate_hdr_headroom.0, 13);
535 
536     if !HAS_DECODER {
537         return;
538     }
539     let res = decoder.next_image();
540     let image = decoder.image().expect("image was none");
541     assert!(res.is_ok());
542     // Main image pixels are not available.
543     assert_eq!(image.row_bytes[0], 0);
544     // Gain map pixels are available.
545     assert!(decoder.gainmap().image.row_bytes[0] > 0);
546 }
547 
548 // From avifgainmaptest.cc
549 #[test_case::test_case("paris_icc_exif_xmp.avif")]
550 #[test_case::test_case("sofa_grid1x5_420.avif")]
551 #[test_case::test_case("color_grid_alpha_nogrid.avif")]
552 #[test_case::test_case("seine_sdr_gainmap_srgb.avif")]
decode_ignore_all(filename: &str)553 fn decode_ignore_all(filename: &str) {
554     let mut decoder = get_decoder(filename);
555     // Ignore both the main image and the gain map.
556     decoder.settings.image_content_to_decode = ImageContentType::None;
557     // But do read the gain map metadata
558 
559     let res = decoder.parse();
560     assert!(res.is_ok());
561     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
562     let image = decoder.image().expect("image was none");
563     // Main image metadata is available.
564     assert!(image.width > 0);
565     // But trying to access the next image should give an error because both
566     // ignoreColorAndAlpha and enableDecodingGainMap are set.
567     let res = decoder.next_image();
568     assert!(res.is_err());
569 }
570 
571 // From avifcllitest.cc
572 #[test_case::test_case("clli_0_0.avif", 0, 0; "clli_0_0")]
573 #[test_case::test_case("clli_0_1.avif", 0, 1; "clli_0_1")]
574 #[test_case::test_case("clli_0_65535.avif", 0, 65535; "clli_0_65535")]
575 #[test_case::test_case("clli_1_0.avif", 1, 0; "clli_1_0")]
576 #[test_case::test_case("clli_1_1.avif", 1, 1; "clli_1_1")]
577 #[test_case::test_case("clli_1_65535.avif", 1, 65535; "clli_1_65535")]
578 #[test_case::test_case("clli_65535_0.avif", 65535, 0; "clli_65535_0")]
579 #[test_case::test_case("clli_65535_1.avif", 65535, 1; "clli_65535_1")]
580 #[test_case::test_case("clli_65535_65535.avif", 65535, 65535; "clli_65535_65535")]
clli(filename: &str, max_cll: u16, max_pall: u16)581 fn clli(filename: &str, max_cll: u16, max_pall: u16) {
582     let mut filename_with_prefix = String::from("clli/");
583     filename_with_prefix.push_str(filename);
584     let mut decoder = get_decoder(&filename_with_prefix);
585     let res = decoder.parse();
586     assert!(res.is_ok());
587     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
588     let image = decoder.image().expect("image was none");
589     if max_cll == 0 && max_pall == 0 {
590         assert!(image.clli.is_none());
591     } else {
592         assert!(image.clli.is_some());
593         let clli = image.clli.as_ref().unwrap();
594         assert_eq!(clli.max_cll, max_cll);
595         assert_eq!(clli.max_pall, max_pall);
596     }
597 }
598 
599 #[test]
raw_io()600 fn raw_io() {
601     let data =
602         std::fs::read(get_test_file("colors-animated-8bpc.avif")).expect("Unable to read file");
603     let mut decoder = decoder::Decoder::default();
604     let _ = unsafe {
605         decoder
606             .set_io_raw(data.as_ptr(), data.len())
607             .expect("Failed to set IO")
608     };
609     assert!(decoder.parse().is_ok());
610     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
611     assert_eq!(decoder.image_count(), 5);
612     if !HAS_DECODER {
613         return;
614     }
615     for _ in 0..5 {
616         assert!(decoder.next_image().is_ok());
617     }
618 }
619 
620 struct CustomIO {
621     data: Vec<u8>,
622     available_size_rc: Rc<RefCell<usize>>,
623 }
624 
625 impl decoder::IO for CustomIO {
read(&mut self, offset: u64, max_read_size: usize) -> AvifResult<&[u8]>626     fn read(&mut self, offset: u64, max_read_size: usize) -> AvifResult<&[u8]> {
627         let available_size = self.available_size_rc.borrow();
628         let start = usize::try_from(offset).unwrap();
629         let end = start + max_read_size;
630         if start > self.data.len() || end > self.data.len() {
631             return Err(AvifError::IoError);
632         }
633         let mut ssize = max_read_size;
634         if ssize > self.data.len() - start {
635             ssize = self.data.len() - start;
636         }
637         let end = start + ssize;
638         if *available_size < end {
639             return Err(AvifError::WaitingOnIo);
640         }
641         Ok(&self.data[start..end])
642     }
643 
size_hint(&self) -> u64644     fn size_hint(&self) -> u64 {
645         self.data.len() as u64
646     }
647 
persistent(&self) -> bool648     fn persistent(&self) -> bool {
649         false
650     }
651 }
652 
653 #[test]
custom_io()654 fn custom_io() {
655     let data =
656         std::fs::read(get_test_file("colors-animated-8bpc.avif")).expect("Unable to read file");
657     let mut decoder = decoder::Decoder::default();
658     let available_size_rc = Rc::new(RefCell::new(data.len()));
659     let io = Box::new(CustomIO {
660         available_size_rc: available_size_rc.clone(),
661         data,
662     });
663     decoder.set_io(io);
664     assert!(decoder.parse().is_ok());
665     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
666     assert_eq!(decoder.image_count(), 5);
667     if !HAS_DECODER {
668         return;
669     }
670     for _ in 0..5 {
671         assert!(decoder.next_image().is_ok());
672     }
673 }
674 
expected_min_decoded_row_count( height: u32, cell_height: u32, cell_columns: u32, available_size: usize, size: usize, grid_cell_offsets: &Vec<usize>, ) -> u32675 fn expected_min_decoded_row_count(
676     height: u32,
677     cell_height: u32,
678     cell_columns: u32,
679     available_size: usize,
680     size: usize,
681     grid_cell_offsets: &Vec<usize>,
682 ) -> u32 {
683     if available_size >= size {
684         return height;
685     }
686     let mut cell_index: Option<usize> = None;
687     for (index, offset) in grid_cell_offsets.iter().enumerate().rev() {
688         if available_size >= *offset {
689             cell_index = Some(index);
690             break;
691         }
692     }
693     if cell_index.is_none() {
694         return 0;
695     }
696     let cell_index = cell_index.unwrap() as u32;
697     let cell_row = cell_index / cell_columns;
698     let cell_column = cell_index % cell_columns;
699     let cell_rows_decoded = if cell_column == cell_columns - 1 { cell_row + 1 } else { cell_row };
700     cell_rows_decoded * cell_height
701 }
702 
703 #[test]
expected_min_decoded_row_count_computation()704 fn expected_min_decoded_row_count_computation() {
705     let grid_cell_offsets: Vec<usize> = vec![3258, 10643, 17846, 22151, 25409, 30000];
706     let cell_height = 154;
707     assert_eq!(
708         0,
709         expected_min_decoded_row_count(770, cell_height, 1, 1000, 30000, &grid_cell_offsets)
710     );
711     assert_eq!(
712         1 * cell_height,
713         expected_min_decoded_row_count(770, cell_height, 1, 4000, 30000, &grid_cell_offsets)
714     );
715     assert_eq!(
716         2 * cell_height,
717         expected_min_decoded_row_count(770, cell_height, 1, 12000, 30000, &grid_cell_offsets)
718     );
719     assert_eq!(
720         3 * cell_height,
721         expected_min_decoded_row_count(770, cell_height, 1, 17846, 30000, &grid_cell_offsets)
722     );
723     assert_eq!(
724         1 * cell_height,
725         expected_min_decoded_row_count(462, cell_height, 2, 17846, 30000, &grid_cell_offsets)
726     );
727     assert_eq!(
728         2 * cell_height,
729         expected_min_decoded_row_count(462, cell_height, 2, 23000, 30000, &grid_cell_offsets)
730     );
731     assert_eq!(
732         1 * cell_height,
733         expected_min_decoded_row_count(308, cell_height, 3, 23000, 30000, &grid_cell_offsets)
734     );
735     assert_eq!(
736         2 * cell_height,
737         expected_min_decoded_row_count(308, cell_height, 3, 30000, 30000, &grid_cell_offsets)
738     );
739 }
740 
741 #[test]
incremental_decode()742 fn incremental_decode() {
743     // Grid item offsets for sofa_grid1x5_420.avif:
744     // Each line is "$extent_offset + $extent_length".
745     let grid_cell_offsets: Vec<usize> = vec![
746         578 + 2680,
747         3258 + 7385,
748         10643 + 7203,
749         17846 + 4305,
750         22151 + 3258,
751     ];
752 
753     let data = std::fs::read(get_test_file("sofa_grid1x5_420.avif")).expect("Unable to read file");
754     let len = data.len();
755     let available_size_rc = Rc::new(RefCell::new(0usize));
756     let mut decoder = decoder::Decoder::default();
757     decoder.settings.allow_incremental = true;
758     let io = Box::new(CustomIO {
759         available_size_rc: available_size_rc.clone(),
760         data,
761     });
762     decoder.set_io(io);
763     let step: usize = std::cmp::max(1, len / 10000) as usize;
764 
765     // Parsing is not incremental.
766     let mut parse_result = decoder.parse();
767     while parse_result.is_err()
768         && matches!(parse_result.as_ref().err().unwrap(), AvifError::WaitingOnIo)
769     {
770         {
771             let mut available_size = available_size_rc.borrow_mut();
772             if *available_size >= len {
773                 println!("parse returned waiting on io after full file.");
774                 assert!(false);
775             }
776             *available_size = std::cmp::min(*available_size + step, len);
777         }
778         parse_result = decoder.parse();
779     }
780     assert!(parse_result.is_ok());
781     if !HAS_DECODER {
782         return;
783     }
784 
785     // Decoding is incremental.
786     let mut previous_decoded_row_count = 0;
787     let mut decode_result = decoder.next_image();
788     while decode_result.is_err()
789         && matches!(
790             decode_result.as_ref().err().unwrap(),
791             AvifError::WaitingOnIo
792         )
793     {
794         {
795             let mut available_size = available_size_rc.borrow_mut();
796             if *available_size >= len {
797                 println!("next_image returned waiting on io after full file.");
798                 assert!(false);
799             }
800             let decoded_row_count = decoder.decoded_row_count();
801             assert!(decoded_row_count >= previous_decoded_row_count);
802             let expected_min_decoded_row_count = expected_min_decoded_row_count(
803                 decoder.image().unwrap().height,
804                 154,
805                 1,
806                 *available_size,
807                 len,
808                 &grid_cell_offsets,
809             );
810             assert!(decoded_row_count >= expected_min_decoded_row_count);
811             previous_decoded_row_count = decoded_row_count;
812             *available_size = std::cmp::min(*available_size + step, len);
813         }
814         decode_result = decoder.next_image();
815     }
816     assert!(decode_result.is_ok());
817     assert_eq!(decoder.decoded_row_count(), decoder.image().unwrap().height);
818 
819     // TODO: check if incremental and non incremental produces same output.
820 }
821 
822 #[test]
nth_image()823 fn nth_image() {
824     let mut decoder = get_decoder("colors-animated-8bpc.avif");
825     let res = decoder.parse();
826     assert!(res.is_ok());
827     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
828     assert_eq!(decoder.image_count(), 5);
829     if !HAS_DECODER {
830         return;
831     }
832     assert!(decoder.nth_image(3).is_ok());
833     assert!(decoder.next_image().is_ok());
834     assert!(decoder.next_image().is_err());
835     assert!(decoder.nth_image(1).is_ok());
836     assert!(decoder.nth_image(4).is_ok());
837     assert!(decoder.nth_image(50).is_err());
838 }
839 
840 #[test]
color_and_alpha_dimensions_do_not_match()841 fn color_and_alpha_dimensions_do_not_match() {
842     let mut decoder = get_decoder("invalid_color10x10_alpha5x5.avif");
843     // Parsing should succeed.
844     let res = decoder.parse();
845     assert!(res.is_ok());
846     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
847     let image = decoder.image().expect("image was none");
848     assert_eq!(image.width, 10);
849     assert_eq!(image.height, 10);
850     if !HAS_DECODER {
851         return;
852     }
853     // Decoding should fail.
854     let res = decoder.next_image();
855     assert!(res.is_err());
856 }
857 
858 #[test]
rgb_conversion_alpha_premultiply() -> AvifResult<()>859 fn rgb_conversion_alpha_premultiply() -> AvifResult<()> {
860     let mut decoder = get_decoder("alpha.avif");
861     let res = decoder.parse();
862     assert!(res.is_ok());
863     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
864     if !HAS_DECODER {
865         return Ok(());
866     }
867     let res = decoder.next_image();
868     assert!(res.is_ok());
869     let image = decoder.image().expect("image was none");
870     let mut rgb = rgb::Image::create_from_yuv(image);
871     rgb.premultiply_alpha = true;
872     rgb.allocate()?;
873     assert!(rgb.convert_from_yuv(image).is_ok());
874     Ok(())
875 }
876 
877 #[test]
white_1x1() -> AvifResult<()>878 fn white_1x1() -> AvifResult<()> {
879     let mut decoder = get_decoder("white_1x1.avif");
880     assert_eq!(decoder.parse(), Ok(()));
881     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
882     if !HAS_DECODER {
883         return Ok(());
884     }
885     assert_eq!(decoder.next_image(), Ok(()));
886 
887     let image = decoder.image().expect("image was none");
888     let mut rgb = rgb::Image::create_from_yuv(image);
889     rgb.allocate()?;
890     assert!(rgb.convert_from_yuv(image).is_ok());
891     assert_eq!(rgb.width * rgb.height, 1);
892     let format = rgb.format;
893     for i in [format.r_offset(), format.g_offset(), format.b_offset()] {
894         assert_eq!(rgb.row(0)?[i], 253); // Compressed with loss, not pure white.
895     }
896     if rgb.has_alpha() {
897         assert_eq!(rgb.row(0)?[rgb.format.alpha_offset()], 255);
898     }
899     Ok(())
900 }
901 
902 #[test]
white_1x1_mdat_size0() -> AvifResult<()>903 fn white_1x1_mdat_size0() -> AvifResult<()> {
904     // Edit the file to simulate an 'mdat' box with size 0 (meaning it ends at EOF).
905     let mut file_bytes = std::fs::read(get_test_file("white_1x1.avif")).unwrap();
906     let mdat = [b'm', b'd', b'a', b't'];
907     let mdat_size_pos = file_bytes.windows(4).position(|w| w == mdat).unwrap() - 4;
908     file_bytes[mdat_size_pos + 3] = b'\0';
909 
910     let mut decoder = decoder::Decoder::default();
911     decoder.set_io_vec(file_bytes);
912     assert_eq!(decoder.parse(), Ok(()));
913     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
914     Ok(())
915 }
916 
917 #[test]
white_1x1_meta_size0() -> AvifResult<()>918 fn white_1x1_meta_size0() -> AvifResult<()> {
919     // Edit the file to simulate a 'meta' box with size 0 (invalid).
920     let mut file_bytes = std::fs::read(get_test_file("white_1x1.avif")).unwrap();
921     let meta = [b'm', b'e', b't', b'a'];
922     let meta_size_pos = file_bytes.windows(4).position(|w| w == meta).unwrap() - 4;
923     file_bytes[meta_size_pos + 3] = b'\0';
924 
925     let mut decoder = decoder::Decoder::default();
926     decoder.set_io_vec(file_bytes);
927 
928     // This should fail because the meta box contains the mdat box.
929     // However, the section 8.11.3.1 of ISO/IEC 14496-12 does not explicitly require the coded image
930     // item extents to be read from the MediaDataBox if the construction_method is 0.
931     // Maybe another section or specification enforces that.
932     assert_eq!(decoder.parse(), Ok(()));
933     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
934     if !HAS_DECODER {
935         return Ok(());
936     }
937     assert_eq!(decoder.next_image(), Ok(()));
938     Ok(())
939 }
940 
941 #[test]
white_1x1_ftyp_size0() -> AvifResult<()>942 fn white_1x1_ftyp_size0() -> AvifResult<()> {
943     // Edit the file to simulate a 'ftyp' box with size 0 (invalid).
944     let mut file_bytes = std::fs::read(get_test_file("white_1x1.avif")).unwrap();
945     file_bytes[3] = b'\0';
946 
947     let mut decoder = decoder::Decoder::default();
948     decoder.set_io_vec(file_bytes);
949     assert!(matches!(
950         decoder.parse(),
951         Err(AvifError::BmffParseFailed(_))
952     ));
953     Ok(())
954 }
955 
956 #[test]
dimg_repetition()957 fn dimg_repetition() {
958     let mut decoder = get_decoder("sofa_grid1x5_420_dimg_repeat.avif");
959     assert_eq!(
960         decoder.parse(),
961         Err(AvifError::BmffParseFailed(
962             "multiple dimg references for item ID 1".into()
963         ))
964     );
965 }
966 
967 #[test]
dimg_shared()968 fn dimg_shared() {
969     let mut decoder = get_decoder("color_grid_alpha_grid_tile_shared_in_dimg.avif");
970     assert_eq!(decoder.parse(), Err(AvifError::NotImplemented));
971 }
972 
973 #[test]
dimg_ordering()974 fn dimg_ordering() {
975     if !HAS_DECODER {
976         return;
977     }
978     let mut decoder1 = get_decoder("sofa_grid1x5_420.avif");
979     let res = decoder1.parse();
980     assert!(res.is_ok());
981     let res = decoder1.next_image();
982     assert!(res.is_ok());
983     let mut decoder2 = get_decoder("sofa_grid1x5_420_random_dimg_order.avif");
984     let res = decoder2.parse();
985     assert!(res.is_ok());
986     let res = decoder2.next_image();
987     assert!(res.is_ok());
988     let image1 = decoder1.image().expect("image1 was none");
989     let image2 = decoder2.image().expect("image2 was none");
990     // Ensure that the pixels in image1 and image2 are not the same.
991     let row1 = image1.row(Plane::Y, 0).expect("row1 was none");
992     let row2 = image2.row(Plane::Y, 0).expect("row2 was none");
993     assert_ne!(row1, row2);
994 }
995 
996 #[test]
heic_peek()997 fn heic_peek() {
998     let file_data = std::fs::read(get_test_file("blue.heic")).expect("could not read file");
999     assert_eq!(
1000         decoder::Decoder::peek_compatible_file_type(&file_data),
1001         cfg!(feature = "heic")
1002     );
1003 }
1004 
1005 #[test]
heic_parsing()1006 fn heic_parsing() {
1007     let mut decoder = get_decoder("blue.heic");
1008     let res = decoder.parse();
1009     if cfg!(feature = "heic") {
1010         assert!(res.is_ok());
1011         let image = decoder.image().expect("image was none");
1012         assert_eq!(image.width, 320);
1013         assert_eq!(image.height, 240);
1014         assert_eq!(decoder.compression_format(), CompressionFormat::Heic);
1015         if cfg!(feature = "android_mediacodec") {
1016             // Decoding is available only via android_mediacodec.
1017             assert!(!matches!(
1018                 decoder.next_image(),
1019                 Err(AvifError::NoCodecAvailable)
1020             ));
1021         }
1022     } else {
1023         assert!(res.is_err());
1024     }
1025 }
1026 
1027 #[test]
clap_irot_imir_non_essential()1028 fn clap_irot_imir_non_essential() {
1029     let mut decoder = get_decoder("clap_irot_imir_non_essential.avif");
1030     let res = decoder.parse();
1031     assert!(res.is_err());
1032 }
1033 
1034 #[derive(Clone)]
1035 struct ExpectedOverlayImageInfo<'a> {
1036     filename: &'a str,
1037     width: u32,
1038     height: u32,
1039     expected_pixels: &'a [(usize, u32, [u8; 4])], // (x, y, [rgba]).
1040 }
1041 
1042 const RED: [u8; 4] = [255, 0, 0, 255];
1043 const GREEN: [u8; 4] = [0, 255, 0, 255];
1044 const BLUE: [u8; 4] = [0, 0, 255, 255];
1045 const BLACK: [u8; 4] = [0, 0, 0, 255];
1046 const YELLOW: [u8; 4] = [255, 255, 0, 255];
1047 
1048 const EXPECTED_OVERLAY_IMAGE_INFOS: [ExpectedOverlayImageInfo; 4] = [
1049     ExpectedOverlayImageInfo {
1050         // Three 80x60 sub-images with the following offsets:
1051         // horizontal_offsets: [0, 40, 80]
1052         // vertical_offsets: [0, 40, 80]
1053         filename: "overlay_exact_bounds.avif",
1054         width: 160,
1055         height: 140,
1056         expected_pixels: &[
1057             // Top left should be red.
1058             (0, 0, RED),
1059             (10, 10, RED),
1060             (20, 20, RED),
1061             // Green should be overlaid on top of the red block starting at (40, 40).
1062             (40, 40, GREEN),
1063             (50, 50, GREEN),
1064             (60, 60, GREEN),
1065             // Blue should be overlaid on top of the green block starting at (80, 80).
1066             (80, 80, BLUE),
1067             (90, 90, BLUE),
1068             (100, 100, BLUE),
1069             // Top right should be background color.
1070             (159, 0, BLACK),
1071             // Bottom left should be background color.
1072             (0, 139, BLACK),
1073         ],
1074     },
1075     ExpectedOverlayImageInfo {
1076         // Three 80x60 sub-images with the following offsets:
1077         // horizontal_offsets: [20, 60, 100]
1078         // vertical_offsets: [20, 60, 100]
1079         filename: "overlay_with_border.avif",
1080         width: 200,
1081         height: 180,
1082         expected_pixels: &[
1083             // Top left should be background color.
1084             (0, 0, BLACK),
1085             // Red should be overlaid starting at (20, 20).
1086             (20, 20, RED),
1087             (30, 30, RED),
1088             (40, 40, RED),
1089             // Green should be overlaid on top of the red block starting at (60, 60).
1090             (60, 60, GREEN),
1091             (70, 70, GREEN),
1092             (80, 80, GREEN),
1093             // Blue should be overlaid on top of the green block starting at (100, 100).
1094             (100, 100, BLUE),
1095             (110, 110, BLUE),
1096             (120, 120, BLUE),
1097             // Top right should be background color.
1098             (199, 0, BLACK),
1099             // Bottom left should be background color.
1100             (0, 179, BLACK),
1101             // Bottom right should be background color.
1102             (199, 179, BLACK),
1103         ],
1104     },
1105     ExpectedOverlayImageInfo {
1106         // Two 80x60 sub-images with the following offsets:
1107         // horizontal_offsets: [-40, 120]
1108         // vertical_offsets: [-40, 100]
1109         filename: "overlay_outside_bounds.avif",
1110         width: 160,
1111         height: 140,
1112         expected_pixels: &[
1113             // Red overlay is 40x20 in the top left.
1114             (0, 0, RED),
1115             (15, 15, RED),
1116             (39, 19, RED),
1117             (40, 20, BLACK),
1118             // Blue overlay is 40x40 in the bottom right.
1119             (119, 99, BLACK),
1120             (120, 100, BLUE),
1121             (140, 120, BLUE),
1122             (159, 139, BLUE),
1123             // Center of the image should be background color.
1124             (80, 70, BLACK),
1125             // Top right should be background color.
1126             (159, 0, BLACK),
1127             // Bottom left should be background color.
1128             (0, 139, BLACK),
1129         ],
1130     },
1131     ExpectedOverlayImageInfo {
1132         // Three 80x60 sub-images with the following offsets:
1133         // horizontal_offsets: [0, 40, 80]
1134         // vertical_offsets: [0, 40, 80]
1135         // canvas background color: yellow.
1136         filename: "overlay_yellow_bg.avif",
1137         width: 160,
1138         height: 140,
1139         expected_pixels: &[
1140             // Top left should be red.
1141             (0, 0, RED),
1142             (10, 10, RED),
1143             (20, 20, RED),
1144             // Green should be overlaid on top of the red block starting at (40, 40).
1145             (40, 40, GREEN),
1146             (50, 50, GREEN),
1147             (60, 60, GREEN),
1148             // Blue should be overlaid on top of the green block starting at (80, 80).
1149             (80, 80, BLUE),
1150             (90, 90, BLUE),
1151             (100, 100, BLUE),
1152             // Top right should be background color.
1153             (159, 0, YELLOW),
1154             // Bottom left should be background color.
1155             (0, 139, YELLOW),
1156         ],
1157     },
1158 ];
1159 
1160 macro_rules! pixel_eq {
1161     ($a:expr, $b:expr) => {
1162         assert!((i32::from($a) - i32::from($b)).abs() <= 3);
1163     };
1164 }
1165 
1166 #[test_case::test_matrix(0usize..4)]
overlay(index: usize)1167 fn overlay(index: usize) {
1168     let info = &EXPECTED_OVERLAY_IMAGE_INFOS[index];
1169     let mut decoder = get_decoder(info.filename);
1170     decoder.settings.strictness = decoder::Strictness::None;
1171     let res = decoder.parse();
1172     assert!(res.is_ok());
1173     assert_eq!(decoder.compression_format(), CompressionFormat::Avif);
1174     let image = decoder.image().expect("image was none");
1175     assert_eq!(image.width, info.width);
1176     assert_eq!(image.height, info.height);
1177     if !HAS_DECODER {
1178         return;
1179     }
1180     let res = decoder.next_image();
1181     assert!(res.is_ok());
1182     let image = decoder.image().expect("image was none");
1183     assert_eq!(image.width, info.width);
1184     assert_eq!(image.height, info.height);
1185     let mut rgb = rgb::Image::create_from_yuv(image);
1186     rgb.format = rgb::Format::Rgba;
1187     assert!(rgb.allocate().is_ok());
1188     assert!(rgb.convert_from_yuv(image).is_ok());
1189     for expected_pixel in info.expected_pixels {
1190         let column = expected_pixel.0;
1191         let row = expected_pixel.1;
1192         let pixels = rgb.row(row).expect("row was none");
1193         let r = pixels[column * 4];
1194         let g = pixels[(column * 4) + 1];
1195         let b = pixels[(column * 4) + 2];
1196         let a = pixels[(column * 4) + 3];
1197         pixel_eq!(r, expected_pixel.2[0]);
1198         pixel_eq!(g, expected_pixel.2[1]);
1199         pixel_eq!(b, expected_pixel.2[2]);
1200         pixel_eq!(a, expected_pixel.2[3]);
1201     }
1202 }
1203