summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNico Weber <thakis@chromium.org>2023-06-01 09:09:24 -0400
committerAndreas Kling <kling@serenityos.org>2023-06-01 17:36:20 +0200
commit661b2d394d600a7dc334691a05dce7a49699254f (patch)
treef48ed655cd2ca15b48afee7a94d3e02127be2549
parentc2ec97dd7909d633e5ba2ad69039603494900986 (diff)
downloadserenity-661b2d394d600a7dc334691a05dce7a49699254f.zip
WebP/Lossy: Clamp negative quantization indices to zero
The spec doesn't talk about this happening in the text, but `dequant_init()` in 20.4 stores `q` in an int and clamps that to 0 later.
-rw-r--r--Tests/LibGfx/TestImageDecoder.cpp21
-rw-r--r--Tests/LibGfx/test-inputs/smolkling.webpbin0 -> 27938 bytes
-rw-r--r--Userland/Libraries/LibGfx/ImageFormats/WebPLoaderLossy.cpp6
3 files changed, 24 insertions, 3 deletions
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
--- /dev/null
+++ b/Tests/LibGfx/test-inputs/smolkling.webp
Binary files 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;