LibGfx+Tests: Support grayscale jpegs with 2x2 sampling and MCU reset

Non-interleaved files always have an MCU of one data unit.

(A "data unit" is an 8x8 tile of pixels, and an "MCU" is a
"minium coded unit", e.g. 2x2 data units for luminance and
1 data unit each for Cr and Cb for a YCrCb image with
4:2:0 subsampling.)

For the test case, I converted an existing image to a ppm:

    Build/lagom/bin/image -o out.ppm \
        Tests/LibGfx/test-inputs/jpg/12-bit.jpg

Then I converted it to grayscale and saved it as a pgm in Photoshop.
Then I turned it into a weird jpeg like so:

    path/to/cjpeg \
        -outfile Tests/LibGfx/test-inputs/jpg/grayscale_mcu.jpg \
        -sample 2x2 -restart 3 out.pgm

Makes 3 of the 5 jpegs failing to decode at #22780 go.
This commit is contained in:
Nico Weber 2024-01-29 10:56:22 -05:00 committed by Andreas Kling
parent 90490d9fb8
commit 6971ba35d5
3 changed files with 14 additions and 0 deletions

View file

@ -417,6 +417,15 @@ TEST_CASE(test_jpeg_grayscale_with_app14)
TRY_OR_FAIL(expect_single_frame_of_size(*plugin_decoder, { 80, 80 }));
}
TEST_CASE(test_jpeg_grayscale_with_weird_mcu_and_reset_marker)
{
auto file = TRY_OR_FAIL(Core::MappedFile::map(TEST_INPUT("jpg/grayscale_mcu.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, { 320, 240 }));
}
TEST_CASE(test_jpeg_malformed_header)
{
Array test_inputs = {

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

View file

@ -1301,6 +1301,11 @@ static ErrorOr<void> read_start_of_frame(JPEGStream& stream, JPEGLoadingContext&
component.sampling_factors.horizontal = subsample_factors >> 4;
component.sampling_factors.vertical = subsample_factors & 0x0F;
if (component_count == 1) {
// 4.8.2 Minimum coded unit: "If the compressed image data is non-interleaved, the MCU is defined to be one data unit."
component.sampling_factors = { 1, 1 };
}
dbgln_if(JPEG_DEBUG, "Component subsampling: {}, {}", component.sampling_factors.horizontal, component.sampling_factors.vertical);
if (i == 0) {