diff --git a/Tests/LibGfx/TestImageDecoder.cpp b/Tests/LibGfx/TestImageDecoder.cpp index c8e2ced9a3..4a843d37e0 100644 --- a/Tests/LibGfx/TestImageDecoder.cpp +++ b/Tests/LibGfx/TestImageDecoder.cpp @@ -420,6 +420,27 @@ TEST_CASE(test_webp_simple_lossless_color_index_transform_pixel_bundling) } } +TEST_CASE(test_webp_simple_lossless_color_index_transform_pixel_bundling_odd_width) +{ + StringView file_names[] = { + "width11-height11-colors2.webp"sv, + "width11-height11-colors3.webp"sv, + "width11-height11-colors15.webp"sv, + }; + + for (auto file_name : file_names) { + auto file = MUST(Core::MappedFile::map(MUST(String::formatted("{}{}", TEST_INPUT(""), file_name)))); + auto plugin_decoder = MUST(Gfx::WebPImageDecoderPlugin::create(file->bytes())); + EXPECT(plugin_decoder->initialize()); + + EXPECT_EQ(plugin_decoder->frame_count(), 1u); + EXPECT_EQ(plugin_decoder->size(), Gfx::IntSize(11, 11)); + + auto frame = MUST(plugin_decoder->frame(0)); + EXPECT_EQ(frame.image->size(), Gfx::IntSize(11, 11)); + } +} + TEST_CASE(test_webp_extended_lossless_animated) { auto file = MUST(Core::MappedFile::map(TEST_INPUT("extended-lossless-animated.webp"sv))); diff --git a/Tests/LibGfx/test-inputs/width11-height11-colors15.webp b/Tests/LibGfx/test-inputs/width11-height11-colors15.webp new file mode 100644 index 0000000000..cfb395d11a Binary files /dev/null and b/Tests/LibGfx/test-inputs/width11-height11-colors15.webp differ diff --git a/Tests/LibGfx/test-inputs/width11-height11-colors2.webp b/Tests/LibGfx/test-inputs/width11-height11-colors2.webp new file mode 100644 index 0000000000..8e213bda95 Binary files /dev/null and b/Tests/LibGfx/test-inputs/width11-height11-colors2.webp differ diff --git a/Tests/LibGfx/test-inputs/width11-height11-colors3.webp b/Tests/LibGfx/test-inputs/width11-height11-colors3.webp new file mode 100644 index 0000000000..c11285c401 Binary files /dev/null and b/Tests/LibGfx/test-inputs/width11-height11-colors3.webp differ diff --git a/Userland/Libraries/LibGfx/ImageFormats/WebPLoader.cpp b/Userland/Libraries/LibGfx/ImageFormats/WebPLoader.cpp index 87083ec6f1..d4c8a28748 100644 --- a/Userland/Libraries/LibGfx/ImageFormats/WebPLoader.cpp +++ b/Userland/Libraries/LibGfx/ImageFormats/WebPLoader.cpp @@ -1083,7 +1083,7 @@ ErrorOr> SubtractGreenTransform::transform(NonnullRefPtr> read(WebPLoadingContext&, LittleEndianInputBitStream&); + static ErrorOr> read(WebPLoadingContext&, LittleEndianInputBitStream&, int original_width); virtual ErrorOr> transform(NonnullRefPtr) override; // For a color indexing transform, the green channel of the source image is used as the index into a palette to produce an output color. @@ -1102,17 +1102,19 @@ public: int pixels_per_pixel() const { return m_pixels_per_pixel; } private: - ColorIndexingTransform(unsigned pixels_per_pixel, NonnullRefPtr palette_bitmap) + ColorIndexingTransform(int pixels_per_pixel, int original_width, NonnullRefPtr palette_bitmap) : m_pixels_per_pixel(pixels_per_pixel) + , m_original_width(original_width) , m_palette_bitmap(palette_bitmap) { } int m_pixels_per_pixel; + int m_original_width; NonnullRefPtr m_palette_bitmap; }; -ErrorOr> ColorIndexingTransform::read(WebPLoadingContext& context, LittleEndianInputBitStream& bit_stream) +ErrorOr> ColorIndexingTransform::read(WebPLoadingContext& context, LittleEndianInputBitStream& bit_stream, int original_width) { // color-indexing-image = 8BIT ; color count // entropy-coded-image @@ -1137,7 +1139,7 @@ ErrorOr> ColorIndexingTransform::read(WebP for (ARGB32* pixel = palette_bitmap->begin() + 1; pixel != palette_bitmap->end(); ++pixel) *pixel = add_argb32(*pixel, pixel[-1]); - return adopt_nonnull_own_or_enomem(new (nothrow) ColorIndexingTransform(pixels_per_pixel, move(palette_bitmap))); + return adopt_nonnull_own_or_enomem(new (nothrow) ColorIndexingTransform(pixels_per_pixel, original_width, move(palette_bitmap))); } ErrorOr> ColorIndexingTransform::transform(NonnullRefPtr bitmap) @@ -1156,7 +1158,8 @@ ErrorOr> ColorIndexingTransform::transform(NonnullRefPtrsize().width() * pixels_per_pixel(), bitmap->size().height() }; + VERIFY(ceil_div(m_original_width, pixels_per_pixel()) == bitmap->size().width()); + IntSize unbundled_size = { m_original_width, bitmap->size().height() }; auto new_bitmap = TRY(Bitmap::create(BitmapFormat::BGRA8888, unbundled_size)); unsigned bits_per_pixel = 8 / pixels_per_pixel(); @@ -1252,8 +1255,8 @@ static ErrorOr decode_webp_chunk_VP8L(WebPLoadingContext& context, Chunk c TRY(transforms.try_append(TRY(try_make()))); break; case COLOR_INDEXING_TRANSFORM: { - auto color_indexing_transform = TRY(ColorIndexingTransform::read(context, bit_stream)); - stored_size.set_width(stored_size.width() / color_indexing_transform->pixels_per_pixel()); + auto color_indexing_transform = TRY(ColorIndexingTransform::read(context, bit_stream, stored_size.width())); + stored_size.set_width(ceil_div(stored_size.width(), color_indexing_transform->pixels_per_pixel())); TRY(transforms.try_append(move(color_indexing_transform))); break; }