Open jfolz opened 4 years ago
The TurboJPEG API handles common chroma subsampling configurations, but it cannot handle every possible combination of horizontal and vertical sampling factors.
The second image appears to use "4:1:0" (AKA "4:2") subsampling, which is a known (albeit rare) form of 8x chroma subsampling. That image could be accommodated by introducing a new subsampling option (TJSAMP_410
) into the TurboJPEG API. That would be straightforward but labor-intensive, since it would require extending all of the API functions (including the YUV functions) that deal with subsampling, as well as extending TJUnitTest and TJBench to test the new subsampling configuration.
The first image doesn't appear to use any known subsampling configuration. Thus, the first image could not be accommodated without extensive modifications to the TurboJPEG API-- extending it to handle arbitrary subsampling configurations.
In both cases, the modifications would represent an enhancement rather than a bug fix, and I have no funding available for such a project right now. If your organization wishes to sponsor this feature, then I would be happy to provide you with a cost estimate offline. Otherwise, it's not likely to happen anytime soon.
Thank you for the detailed analysis. I will ponder my options for a bit, but as you said these are very rare. I found less than 20 of the 4:1:0 kind and just a couple of the really weird one in over a million images. Supporting these kinds of images is probably not worth it if that requires massive changes to the library.
Supporting 4:1:0 would be a non-disruptive and backward-compatible change-- probably a day's work or in that neighborhood. Thus, supporting that subsampling configuration would make a lot more sense than supporting arbitrary subsampling configurations. The latter would require a wholesale rewrite of almost the entire TurboJPEG API.
Note that the wholesale rewrite I propose here would subsume this enhancement, but per above, it would be much easier to just add a TJSAMP_410
constant to the existing TurboJPEG API.
Subsumed by #517
This is implemented in the TurboJPEG 3 API overhaul, using several new mechanisms:
tj3DecompressHeader()
function sets the new TJPARAM_SUBSAMP
parameter to TJSAMP_UNKNOWN
if it can't identify the subsampling configuration of a JPEG image, but this is no longer treated as an error.tj3JPEGBufSize()
function treats TJSAMP_UNKNOWN
as if it were TJSAMP_444
, the logic being that a JPEG buffer that can hold a 4:4:4 JPEG image should also be able to hold a JPEG image with an arbitrary subsampling configuration. This may not, however, be the case if the JPEG image has more than three components (e.g. YCCK.)tj3Decompress*()
functions can now fully decompress JPEG images with arbitrary subsampling configurations into packed-pixel images without complaint. However, the subsampling configuration must be known in order to:
jpeg_crop_scanline()
will modify the left boundary and width of the cropping region if the left boundary doesn't fall on an MCU boundary, but jpeg_crop_scanline()
can't be called until after jpeg_start_decompress()
, which is well within the body of tj3Decompress*()
. The calling program needs to know what the final cropping region will be so it can allocate a packed-pixel buffer of an appropriate size, but there is no way to know that at the time tj3Decompress*()
is called unless the API understands the subsampling configuration. Future API overhauls may be able to work around this issue by implementing stateful management of packed-pixel buffers, but that's a hard problem (https://github.com/libjpeg-turbo/libjpeg-turbo/issues/517#issuecomment-1374612779).tj3SetCroppingRegion()
also affects the decompress-to-YUV functions.https://github.com/libjpeg-turbo/libjpeg-turbo/commit/fc881ebb211b2ba6292d35691a946e1f9c1374b4 adds explicit support for 4:4:1 (transposed 4:1:1) subsampling, in order to fully support lossless transformation chains that begin by rotating or transposing a 4:1:1 JPEG image. (Refer to #659.) That gives the TurboJPEG 3 API full coverage of all 1X, 2X, and 4X chrominance subsampling levels.
Explicitly supporting the two named 8X subsampling levels (4:1:0 and 4:2:1) would be a trivial enhancement, if anyone cares enough about those types of images to want to partially decompress them, losslessly crop them, or decompress them to planar YUV images. Personally, I don't, but I would happily accept funding to implement those subsampling types.
Reopening this feature request, since arbitrary subsampling factors didn't land in the TurboJPEG v3 API and I have no idea when or if the TurboJPEG v4 API (#646) will land. For now, I'm focusing on incrementally extending the TurboJPEG v3 API to cover as much of the libjpeg API functionality as possible without completely overhauling it. Supporting 4:1:0 and 2:4 subsampling in the existing API would be very straightforward and would extend coverage to almost all JPEG images "in the wild." TurboJPEG v3 can already handle JPEG images with unknown/arbitrary subsampling levels. It just can't perform lossless cropping, partial decompression, or decompression-to-YUV with such images, since those operations require knowing the iMCU size.
Have you searched the existing issues (both open and closed) in the libjpeg-turbo issue tracker to ensure that this bug report is not a duplicate? There is a similar issue #323 (also by me), but the subsampling types it fails on are different.
Does this bug report describe one of the two known and unsolvable issues with the JPEG format? No
Clear and concise description of the bug: I found some more unusual images that decompress correctly with djpeg, but
tjDecompressHeader3
reports "Could not determine subsampling type for JPEG image".Steps to reproduce the bug (using only libjpeg-turbo): Run
tjDecompressHeader3
with one of the example images.Image(s) needed in order to reproduce the bug (if applicable): Example 1 with djpeg -verbose output of:
Example 2 with djpeg -verbose output of:
Expected behavior:
tjDecompressHeader3
identifies subsampling type correctly.Observed behavior:
tjDecompressHeader3
is not able to determine subsampling type and decoding has to be stopped.Platform(s) (compiler version, operating system version, CPU) on which the bug was observed: Probably irrelevant, but: GCC 7.5.0, OpenSuse Leap 15.1 (kernel 4.12.14), Intel(R) Core(TM) i7-5930K.
libjpeg-turbo release(s), commit(s), or branch(es) in which the bug was observed (always test the tip of the master branch or the latest stable pre-release to verify that the bug hasn't already been fixed): v 2.0.4.
If the bug is a regression, the specific commit that introduced the regression (use
git bisect
to determine this): AFAIK this has never worked.Additional information: None