From ab143e9b0eba981f6154a01013ba7555bf3ee1a7 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Mon, 4 Mar 2024 19:56:13 -0500 Subject: [PATCH] LibGfx/BMP: Clear alpha in palette entries The semantics of BGRx8888 aren't super clear and it means different things for different parts of the codebase. In particular, the PNG writer still writes the x channel to the alpha channel of its output. In BMPs, the 4th palette byte is usually 0, which means after #21412 we started writing all .bmp files with <= 8bpp as completely transparent to PNGs. This works around that. (See also #19464 for previous similar workarounds.) The added `bitmap.bmp` is a 1bpp file I drew in Photoshop and saved using its "Save as..." saving path. --- Tests/LibGfx/TestImageDecoder.cpp | 10 ++++++++++ Tests/LibGfx/test-inputs/bmp/bitmap.bmp | Bin 0 -> 20864 bytes .../Libraries/LibGfx/ImageFormats/BMPLoader.cpp | 4 ++-- 3 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 Tests/LibGfx/test-inputs/bmp/bitmap.bmp diff --git a/Tests/LibGfx/TestImageDecoder.cpp b/Tests/LibGfx/TestImageDecoder.cpp index 48cd495193..34ca809c03 100644 --- a/Tests/LibGfx/TestImageDecoder.cpp +++ b/Tests/LibGfx/TestImageDecoder.cpp @@ -71,6 +71,16 @@ TEST_CASE(test_bmp_top_down) TRY_OR_FAIL(expect_single_frame(*plugin_decoder)); } +TEST_CASE(test_bmp_1bpp) +{ + auto file = TRY_OR_FAIL(Core::MappedFile::map(TEST_INPUT("bmp/bitmap.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, { 399, 400 })); + EXPECT_EQ(frame.image->begin()[0], 0xff'ff'ff'ff); +} + TEST_CASE(test_ico_malformed_frame) { Array test_inputs = { diff --git a/Tests/LibGfx/test-inputs/bmp/bitmap.bmp b/Tests/LibGfx/test-inputs/bmp/bitmap.bmp new file mode 100644 index 0000000000000000000000000000000000000000..5520b349e5fed524a1bd3ce6335ec488cb6b4986 GIT binary patch literal 20864 zcmZ?rZ3tul13Lx=1`P%VhJHo{h6#)e42%qnU~#8F1_ot42nGuFpP%5Xc&O<_Gmg7O$Vdt02BhF=>QZ8qvgTiP6wbk zA{7&iQ~3iJMiSIhk2wHBNDt%x{}>h#(!>1!{|^ku5fEVi|Nnmjni@j(fb={dQ4jxr zOve$j2c+j8iT23<$KoM0GtjwUJ!l>x51NOF(t{R5#Oc9EKIq;?;e-A2 zA2kpN*#n9n^jIZM4{9I~(gR9w=!1wv>Oo1`g!C|j($0U>Kp>=t5uyhrB@oiXP!HCG z5(otKKq3ewB@omDwFo&@3G0Ex>K~-kL0AtoVbF&;Rqx>_5YD0 z0m*d`4%AI4o7kuZav_%jc^1}dcXlk zq8@O-k*EhWeStJ?!dOm37%+eX0bceX`3Gm5GBAKW1TVCS(*yPpHa$4g8)QBPkyDWD z!KVl0A$U$j(t|VqFfcHHifu%~o&X=W#FbA$Ne`4v5qdx(5R9ul0L$9{N91DU@oPj( zgO#BW^5_*8iY#^xvL0l6u&aiM@}p)Th#&!y9Z3(d_AuklT{vwcM-M21;0YV2$*2+_ zJ@7<|Dut5=(gRO$I8~uZ{70+2(WJ3*|05+HtO~FQ)|00PQTk#r6Pu7d8Hv;$De+)4 z6PuVkd3x~WFKpI;i#V(jcmzSkA|7e1QlOHD)IL6q2xXUwsL5jG)aGBO=fiQNOQ zPq7(}B*sWa&4AEDynh(r_8_$nklcZliRji59Y3H91Tl*=d!U({=x_sNAgCUQb;OYM zu+bC}!p$D0hZqZ>YDV=ifEw8($IocE4V7>szC0L>)1eZl(87xdYBWyCi&J?0Lqr(E zl++^)Z@|O|(Fi>x)u#|+NvO9G_CT}}Lz1Hh-VPz5-iEh#h;bBD4O|cL?OsH?3Tg&1 z6x<#LM*%$Q>yhLTZ9XJHOeQ1pycCgo*b(D1;2A^2@F1r7FcE&_QC3Fc+RF0CgOvz9 zjHx9sQ!!~2JxFbG1qDpCFcEv?5mQ9lpMexTu)zR)dQeg_QeTGJdf=%a4B#flq8BR9YFLnpkz6uk{5eE1y4#o;787K$jKU;J)lvH|NnoWWI5y{ zid7GIKJJe^a`r*V7g)joSUE5 z(*sI8kkEnT3`817avN&?0p}osdQkHzxFH4CgHkIX*@IFZKpI~#J)rP_r&px-VL&N& z7(fj}c<}}bcX--E)&nyXM$03LQKI$mBRZNWX#$@;XnJ7QgJ^i#0dbHqJE9XTkD5dg zaf+-S#AZemJNCrtVL+6t^~l9AKL0S-gKPt1^tGKh{R37FCO|=rD7x|516B_rKtYY1 zL~(}!NHqk5iW5@xfQmZgCb zBqm*>1p#5VF(bFhAXX8y2g~Yxf_fOBBPtLpz$9Tkn7a`O>j4{$LX7GmBA=p!7=$w# zZlmD_N(rOsU^E?!rUOt2jHUxnD2$c|qv>EY9e_e$G#!9K0X7B+ViSu;%aGBu14=8S L>0mS+z|sK#b$e7p literal 0 HcmV?d00001 diff --git a/Userland/Libraries/LibGfx/ImageFormats/BMPLoader.cpp b/Userland/Libraries/LibGfx/ImageFormats/BMPLoader.cpp index eca50ef10f..490f0e2437 100644 --- a/Userland/Libraries/LibGfx/ImageFormats/BMPLoader.cpp +++ b/Userland/Libraries/LibGfx/ImageFormats/BMPLoader.cpp @@ -979,11 +979,11 @@ static ErrorOr decode_bmp_color_table(BMPLoadingContext& context) if (bytes_per_color == 4) { if (!streamer.has_u32()) return Error::from_string_literal("Cannot read 32 bits"); - context.color_table.append(streamer.read_u32()); + context.color_table.append(streamer.read_u32() | 0xff'00'00'00); } else { if (!streamer.has_u24()) return Error::from_string_literal("Cannot read 24 bits"); - context.color_table.append(streamer.read_u24()); + context.color_table.append(streamer.read_u24() | 0xff'00'00'00); } }