LibGfx: Correctly determine when to invert CMYK

We should invert CMYK data only if color space is JCS_CMYK and either
there is no Adobe marker, or the Adobe transform is 0. Transform 2
indicates YCCK data, which we should not invert.
This commit is contained in:
aplefull 2025-10-15 20:04:42 +02:00 committed by Jelle Raaijmakers
parent e55060ef6e
commit 5df216218b
Notes: github-actions[bot] 2025-10-15 19:51:27 +00:00
5 changed files with 40 additions and 1 deletions

View file

@ -148,7 +148,10 @@ ErrorOr<void> JPEGLoadingContext::decode()
// Photoshop writes inverted CMYK data (i.e. Photoshop's 0 should be 255). We convert this
// to expected values.
if (cinfo.saw_Adobe_marker) {
bool should_invert_cmyk = cinfo.jpeg_color_space == JCS_CMYK
&& (!cinfo.saw_Adobe_marker || cinfo.Adobe_transform == 0);
if (should_invert_cmyk) {
for (int i = 0; i < cmyk_bitmap->size().height(); ++i) {
auto* line = cmyk_bitmap->scanline(i);

View file

@ -323,6 +323,42 @@ TEST_CASE(test_jpeg_ycck)
}
}
TEST_CASE(test_jpeg_cmyk_no_adobe_marker)
{
auto file = TRY_OR_FAIL(Core::MappedFile::map(TEST_INPUT("jpg/cmyk-no-adobe-marker.jpg"sv)));
EXPECT(Gfx::JPEGImageDecoderPlugin::sniff(file->bytes()));
auto plugin_decoder = TRY_OR_FAIL(Gfx::JPEGImageDecoderPlugin::create(file->bytes()));
TRY_OR_FAIL(expect_single_frame_of_size(*plugin_decoder, { 10, 10 }));
EXPECT_EQ(plugin_decoder->frame(0).value().image->get_pixel(8, 1), Gfx::Color(44, 184, 97));
EXPECT_EQ(plugin_decoder->frame(0).value().image->get_pixel(1, 8), Gfx::Color(184, 44, 97));
EXPECT_EQ(plugin_decoder->frame(0).value().image->get_pixel(9, 9), Gfx::Color(24, 24, 194));
}
TEST_CASE(test_jpeg_cmyk_adobe_transform_0)
{
auto file = TRY_OR_FAIL(Core::MappedFile::map(TEST_INPUT("jpg/cmyk-adobe-transform-0.jpg"sv)));
EXPECT(Gfx::JPEGImageDecoderPlugin::sniff(file->bytes()));
auto plugin_decoder = TRY_OR_FAIL(Gfx::JPEGImageDecoderPlugin::create(file->bytes()));
TRY_OR_FAIL(expect_single_frame_of_size(*plugin_decoder, { 10, 10 }));
EXPECT_EQ(plugin_decoder->frame(0).value().image->get_pixel(8, 1), Gfx::Color(44, 184, 97));
EXPECT_EQ(plugin_decoder->frame(0).value().image->get_pixel(1, 8), Gfx::Color(184, 44, 97));
EXPECT_EQ(plugin_decoder->frame(0).value().image->get_pixel(9, 9), Gfx::Color(24, 24, 194));
}
TEST_CASE(test_jpeg_ycck_adobe_transform_2)
{
auto file = TRY_OR_FAIL(Core::MappedFile::map(TEST_INPUT("jpg/ycck-adobe-transform-2.jpg"sv)));
EXPECT(Gfx::JPEGImageDecoderPlugin::sniff(file->bytes()));
auto plugin_decoder = TRY_OR_FAIL(Gfx::JPEGImageDecoderPlugin::create(file->bytes()));
TRY_OR_FAIL(expect_single_frame_of_size(*plugin_decoder, { 10, 10 }));
EXPECT_EQ(plugin_decoder->frame(0).value().image->get_pixel(8, 1), Gfx::Color(197, 27, 134));
EXPECT_EQ(plugin_decoder->frame(0).value().image->get_pixel(1, 8), Gfx::Color(24, 199, 134));
EXPECT_EQ(plugin_decoder->frame(0).value().image->get_pixel(9, 9), Gfx::Color(227, 224, 19));
}
TEST_CASE(test_jpeg_sof2_spectral_selection)
{
auto file = TRY_OR_FAIL(Core::MappedFile::map(TEST_INPUT("jpg/spectral_selection.jpg"sv)));

Binary file not shown.

After

Width:  |  Height:  |  Size: 593 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 577 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 597 B