LibGfx/AVIF: Always reduce decoding output to a bit depth of 8

Gfx::Bitmap only supports a bit depth of 8, therefore we refused to
load AVIF images which didn't have this bit depth.

However, we can tell the libavif decoder to reduce the output depth by
setting avifRGBImage.depth to 8. This allows us to support any input
depth.

Makes images load on https://www.ikea.com/ which uses Cloudflare Images
to re-encode their images to 16-bit AVIF.
This commit is contained in:
Luke Wilde 2025-06-16 18:51:34 +01:00 committed by Jelle Raaijmakers
commit ffae0d8b2d
Notes: github-actions[bot] 2025-06-18 12:28:46 +00:00
2 changed files with 10 additions and 4 deletions

View file

@ -83,9 +83,6 @@ static ErrorOr<void> decode_avif_header(AVIFLoadingContext& context)
if (result != AVIF_RESULT_OK)
return Error::from_string_literal("Failed to decode AVIF");
if (context.decoder->image->depth != 8)
return Error::from_string_literal("Unsupported bitdepth");
// Image header now decoded, save some results for fast access in other parts of the plugin.
context.size = IntSize { context.decoder->image->width, context.decoder->image->height };
context.has_alpha = context.decoder->alphaPresent == 1;
@ -114,6 +111,7 @@ static ErrorOr<void> decode_avif_image(AVIFLoadingContext& context)
rgb.pixels = bitmap->scanline_u8(0);
rgb.rowBytes = bitmap->pitch();
rgb.format = avifRGBFormat::AVIF_RGB_FORMAT_BGRA;
rgb.depth = 8;
avifResult result = avifImageYUVToRGB(context.decoder->image, &rgb);
if (result != AVIF_RESULT_OK)

View file

@ -1130,7 +1130,15 @@ TEST_CASE(test_avif_simple_lossless)
TEST_CASE(test_avif_simple_lossy_bitdepth10)
{
auto file = TRY_OR_FAIL(Core::MappedFile::map(TEST_INPUT("avif/simple-bitdepth10.avif"sv)));
EXPECT(!Gfx::AVIFImageDecoderPlugin::sniff(file->bytes()));
EXPECT(Gfx::AVIFImageDecoderPlugin::sniff(file->bytes()));
auto plugin_decoder = TRY_OR_FAIL(Gfx::AVIFImageDecoderPlugin::create(file->bytes()));
auto frame = TRY_OR_FAIL(expect_single_frame_of_size(*plugin_decoder, { 240, 240 }));
// While AVIF YUV contents are defined bit-exact, the YUV->RGB conversion isn't.
// So pixels changing by 1 or so below is fine if you change code.
EXPECT_EQ(frame.image->get_pixel(120, 232), Gfx::Color(0xf1, 0xef, 0xf0, 255));
EXPECT_EQ(frame.image->get_pixel(198, 202), Gfx::Color(0x79, 0xab, 0xd6, 255));
}
TEST_CASE(test_avif_icc_profile)