diff --git a/Libraries/LibGfx/ImageFormats/BMPLoader.cpp b/Libraries/LibGfx/ImageFormats/BMPLoader.cpp index ca4545d1f97..a3c08be99de 100644 --- a/Libraries/LibGfx/ImageFormats/BMPLoader.cpp +++ b/Libraries/LibGfx/ImageFormats/BMPLoader.cpp @@ -958,7 +958,26 @@ static ErrorOr decode_bmp_color_table(BMPLoadingContext& context) return {}; } - auto bytes_per_color = context.dib_type == DIBType::Core ? 3 : 4; + // OS/2 1.x (Core) uses 3 bytes per color + // OS/2 2.x (OSV2) can use 3 or 4 bytes per color + u8 bytes_per_color; + if (context.dib_type == DIBType::Core) { + bytes_per_color = 3; + } else if (context.dib_type == DIBType::OSV2 || context.dib_type == DIBType::OSV2Short) { + // For OS/2 2.x we need to determine the number of bytes per color based on the size of the color table + u8 header_size = context.is_included_in_ico ? 0 : bmp_header_size; + u32 available_size = context.data_offset - header_size - context.dib_size(); + u32 max_colors = 1 << context.dib.core.bpp; + + if (available_size == 3 * max_colors) { + bytes_per_color = 3; + } else { + bytes_per_color = 4; + } + } else { + bytes_per_color = 4; + } + u32 max_colors = 1 << context.dib.core.bpp; u8 header_size = !context.is_included_in_ico ? bmp_header_size : 0; @@ -974,9 +993,9 @@ static ErrorOr decode_bmp_color_table(BMPLoadingContext& context) if (context.dib_type <= DIBType::OSV2) { // Partial color tables are not supported, so the space of the color // table must be at least enough for the maximum amount of colors - if (size_of_color_table < 3 * max_colors) { + if (size_of_color_table < bytes_per_color * max_colors) { // This is against the spec, but most viewers process it anyways - dbgln("BMP with CORE header does not have enough colors. Has: {}, expected: {}", size_of_color_table, (3 * max_colors)); + dbgln("BMP with CORE header does not have enough colors. Has: {}, expected: {}", size_of_color_table, (bytes_per_color * max_colors)); } } diff --git a/Tests/LibGfx/TestImageDecoder.cpp b/Tests/LibGfx/TestImageDecoder.cpp index 79be2640922..cacf10a841e 100644 --- a/Tests/LibGfx/TestImageDecoder.cpp +++ b/Tests/LibGfx/TestImageDecoder.cpp @@ -94,6 +94,17 @@ TEST_CASE(test_bmp_v4) EXPECT_EQ(frame.image->get_pixel(0, 0), Gfx::Color::NamedColor::Red); } +TEST_CASE(test_bmp_os2_3bit) +{ + auto file = TRY_OR_FAIL(Core::MappedFile::map(TEST_INPUT("bmp/os2_3bpc.bmp"sv))); + EXPECT(Gfx::BMPImageDecoderPlugin::sniff(file->bytes())); + auto plugin_decoder = TRY_OR_FAIL(Gfx::BMPImageDecoderPlugin::create(file->bytes())); + + auto frame = TRY_OR_FAIL(expect_single_frame_of_size(*plugin_decoder, { 300, 200 })); + EXPECT_EQ(frame.image->get_pixel(150, 100), Gfx::Color::NamedColor::Black); + EXPECT_EQ(frame.image->get_pixel(152, 100), Gfx::Color::NamedColor::White); +} + TEST_CASE(test_ico_malformed_frame) { Array test_inputs = { diff --git a/Tests/LibGfx/test-inputs/bmp/os2_3bpc.bmp b/Tests/LibGfx/test-inputs/bmp/os2_3bpc.bmp new file mode 100644 index 00000000000..c40b0c1476d Binary files /dev/null and b/Tests/LibGfx/test-inputs/bmp/os2_3bpc.bmp differ