JPEGs can store a `restart_interval`, which controls how many
minimum coded units (MCUs) apart the stream state resets.
This can be used for error correction, decoding parts of a jpeg
in parallel, etc.
We tried to use
u32 i = vcursor * context.mblock_meta.hpadded_count + hcursor;
i % (context.dc_restart_interval *
context.sampling_factors.vertical *
context.sampling_factors.horizontal) == 0
to check if we hit a multiple of an MCU.
`hcursor` is the horizontal offset into 8x8 blocks, vcursor the
vertical offset, and hpadded_count stores how many 8x8 blocks
we have per row, padded to a multiple of the sampling factor.
This isn't quite right if hcursor isn't divisible by both
the vertical and horizontal sampling factor. Tweak things so
that they work.
Also rename `i` to `number_of_mcus_decoded_so_far` since that
what it is, at least now.
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 resized it to 102x77px in Photoshop and saved it again.
Then I turned it into a jpeg like so:
path/to/cjpeg \
-outfile Tests/LibGfx/test-inputs/jpg/odd-restart.jpg \
-sample 2x2,1x1,1x1 -quality 5 -restart 3B out.ppm
The trick here is to:
a) Pick a size that's not divisible by the data size width (8),
and that when rounded to a block size (13) still isn't divisible
by the subsample factor -- done by picking a width of 102.
b) Pick a huffman table that doesn't happen to contain the bit
pattern for a restart marker, so that reading a restart marker
from the bitstream as data causes a failure (-quality 5 happens
to do this)
c) Pick a restart interval where we fail to skip it if our calculation
is off (-restart 3B)
Together with #22987, fixes#22780.
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.
I opened Base/res/graphics/buggie.png in Photoshop, converted it
to U.S. Web Coated (SWOP) v2, flattened the image so we don't have
CMYK with alpha, and saved it as a jpeg (with color profile embedded).
Obtained by running:
convert rgb_components.jpg -colorspace cmyk \
-sampling-factor 1 ycck-1111.jpg
convert rgb_components.jpg -colorspace cmyk \
-sampling-factor 2 ycck-2111.jpg
convert rgb_components.jpg -colorspace cmyk ycck-2112.jpg
where rgb_components.jpg is the file in Tests/LibGfx/test-inputs/jpg.
(I used the web version of `convert` at
https://cancerberosgx.github.io/magic/playground/index.html)
While this does indeed produce a cmyk jpg (using the YCCK encoding
internally), it uses the mathematical rgb->cmyk conversion and does
not embed an cmyk color space in the output jpg.
Normally, cmyk images are for printing and hence converting them
from cmyk to rgb using a color profile like SWOP leads to better
results. So if a cmyk image does not contain color space information,
applications might use something like SWOP instead of the simple
math transform to convert to RGB. Programs doing that will show
these images as fairly muted (and would arguably be correct doing
so).
Hence, tests using these images shouldn't check their RGB values.
Ideally, we'd add a way to get the raw cmyk data from a cmyk jpeg,
and then tests could test color values against that.
The -1111 image uses no subsampling, meaning each channel's sampling
factor is 1.
The -2111 image uses subsampling for the non-Y channels, meaning the
sampling factors are 2 for Y and 1 each for YYK.
The -2112 image uses subsampling for the two C channels, meaning the
sampling factors are 2 for Y and K and 1 each for YY.
We correctly render the -1111 variant (using e.g.
`Build/lagom/bin/image -o out.png .../ycck-1111.jpg).
We render the -2111 variant, but it looks pretty broken.
We refuse to decode the -2112 variant. This is #21259.
Manual tests for now, but having these in tree will make it easier
to write unit tests later, once things work better.