diff --git a/Tests/LibGfx/TestImageDecoder.cpp b/Tests/LibGfx/TestImageDecoder.cpp index ddbae4fd68..1ccca42af0 100644 --- a/Tests/LibGfx/TestImageDecoder.cpp +++ b/Tests/LibGfx/TestImageDecoder.cpp @@ -404,6 +404,27 @@ TEST_CASE(test_webp_extended_lossy_uncompressed_alpha) EXPECT_EQ(frame.image->get_pixel(355, 106), Gfx::Color(0, 0, 0, 0)); } +TEST_CASE(test_webp_extended_lossy_negative_quantization_offset) +{ + auto file = MUST(Core::MappedFile::map(TEST_INPUT("smolkling.webp"sv))); + EXPECT(Gfx::WebPImageDecoderPlugin::sniff(file->bytes())); + auto plugin_decoder = MUST(Gfx::WebPImageDecoderPlugin::create(file->bytes())); + MUST(plugin_decoder->initialize()); + + EXPECT_EQ(plugin_decoder->frame_count(), 1u); + EXPECT(!plugin_decoder->is_animated()); + EXPECT(!plugin_decoder->loop_count()); + + EXPECT_EQ(plugin_decoder->size(), Gfx::IntSize(264, 264)); + + auto frame = MUST(plugin_decoder->frame(0)); + EXPECT_EQ(frame.image->size(), Gfx::IntSize(264, 264)); + + // While VP8 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(16, 16), Gfx::Color(0x3c, 0x24, 0x1a, 255)); +} + TEST_CASE(test_webp_lossy_4) { // This is https://commons.wikimedia.org/wiki/File:Fr%C3%BChling_bl%C3%BChender_Kirschenbaum.jpg, diff --git a/Tests/LibGfx/test-inputs/smolkling.webp b/Tests/LibGfx/test-inputs/smolkling.webp new file mode 100644 index 0000000000..5db2eb1fd7 Binary files /dev/null and b/Tests/LibGfx/test-inputs/smolkling.webp differ diff --git a/Userland/Libraries/LibGfx/ImageFormats/WebPLoaderLossy.cpp b/Userland/Libraries/LibGfx/ImageFormats/WebPLoaderLossy.cpp index 811620fdbd..fe4c0a726f 100644 --- a/Userland/Libraries/LibGfx/ImageFormats/WebPLoaderLossy.cpp +++ b/Userland/Libraries/LibGfx/ImageFormats/WebPLoaderLossy.cpp @@ -621,7 +621,7 @@ i16 dequantize_value(i16 value, bool is_dc, QuantizationIndices const& quantizat y_ac_base = segmentation.quantizer_update_value[segment_id]; } - u8 dequantization_index; + int dequantization_index; if (index.is_y2()) dequantization_index = y_ac_base + (is_dc ? quantization_indices.y2_dc_delta : quantization_indices.y2_ac_delta); else if (index.is_u() || index.is_v()) @@ -631,9 +631,9 @@ i16 dequantize_value(i16 value, bool is_dc, QuantizationIndices const& quantizat // clamp index if ((index.is_u() || index.is_v()) && is_dc) - dequantization_index = min(dequantization_index, 117); + dequantization_index = clamp(dequantization_index, 0, 117); else - dequantization_index = min(dequantization_index, 127); + dequantization_index = clamp(dequantization_index, 0, 127); // "the multiplies are computed and stored using 16-bit signed integers." i16 dequantization_factor;