LibGfx/ICO: Do not try to decode a mask if we already reached EOF
When using the BMP encoding, ICO images are expected to contain a 1-bit mask for transparency. Regardless an alpha channel is already included in the image, the mask is always required. As stated here[1], the mask is used to provide shadow around the image. Unfortunately, it seems that some encoder do not include that second transparency mask. So let's read that mask only if some data is still remaining after decoding the image. The test case has been generated by truncating the 64 last bytes (originally dedicated to the mask) from the `serenity.ico` file and changing the declared size of the image in the ICO header. The size value is stored at the offset 0x0E in the file and I changed the value from 0x0468 to 0x0428. [1]: https://devblogs.microsoft.com/oldnewthing/20101021-00/?p=12483
This commit is contained in:
parent
9c54c13744
commit
402de2985d
Notes:
sideshowbarker
2024-07-17 02:08:15 +09:00
Author: https://github.com/LucasChollet Commit: https://github.com/SerenityOS/serenity/commit/402de2985d Pull-request: https://github.com/SerenityOS/serenity/pull/22635 Issue: https://github.com/SerenityOS/serenity/issues/22617 Reviewed-by: https://github.com/trflynn89 ✅
3 changed files with 13 additions and 2 deletions
|
@ -177,6 +177,17 @@ TEST_CASE(test_bmp_embedded_in_ico)
|
|||
EXPECT_EQ(frame.image->get_pixel(7, 4), Gfx::Color(161, 0, 0));
|
||||
}
|
||||
|
||||
TEST_CASE(test_malformed_maskless_ico)
|
||||
{
|
||||
auto file = TRY_OR_FAIL(Core::MappedFile::map(TEST_INPUT("ico/malformed_maskless.ico"sv)));
|
||||
EXPECT(Gfx::ICOImageDecoderPlugin::sniff(file->bytes()));
|
||||
auto plugin_decoder = TRY_OR_FAIL(Gfx::ICOImageDecoderPlugin::create(file->bytes()));
|
||||
|
||||
auto frame = TRY_OR_FAIL(expect_single_frame_of_size(*plugin_decoder, { 16, 16 }));
|
||||
EXPECT_EQ(frame.image->get_pixel(0, 0), Gfx::Color::NamedColor::Transparent);
|
||||
EXPECT_EQ(frame.image->get_pixel(7, 4), Gfx::Color(161, 0, 0));
|
||||
}
|
||||
|
||||
TEST_CASE(test_ilbm)
|
||||
{
|
||||
auto file = MUST(Core::MappedFile::map(TEST_INPUT("ilbm/gradient.iff"sv)));
|
||||
|
|
BIN
Tests/LibGfx/test-inputs/ico/malformed_maskless.ico
Normal file
BIN
Tests/LibGfx/test-inputs/ico/malformed_maskless.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
|
@ -1429,7 +1429,7 @@ static ErrorOr<void> decode_bmp_pixel_data(BMPLoadingContext& context)
|
|||
TRY(process_row(row));
|
||||
}
|
||||
|
||||
if (context.is_included_in_ico) {
|
||||
if (context.is_included_in_ico && !streamer.at_end()) {
|
||||
for (u32 row = 0; row < height; ++row) {
|
||||
TRY(process_mask_row(row));
|
||||
}
|
||||
|
@ -1440,7 +1440,7 @@ static ErrorOr<void> decode_bmp_pixel_data(BMPLoadingContext& context)
|
|||
TRY(process_row(row));
|
||||
}
|
||||
|
||||
if (context.is_included_in_ico) {
|
||||
if (context.is_included_in_ico && !streamer.at_end()) {
|
||||
for (i32 row = height - 1; row >= 0; --row) {
|
||||
TRY(process_mask_row(row));
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue