Fail if chroma subsampling selected when writing RGB JPEG

The user presumably doesn't intend to subsample the green and blue
channels.
This commit is contained in:
Benjamin Gilbert 2023-12-04 07:31:24 -06:00
parent 14146732be
commit a5fab5fc0b
3 changed files with 22 additions and 3 deletions

View File

@ -447,9 +447,15 @@ class TestFileJpeg:
im = self.roundtrip(hopper(), subsampling=subsampling) im = self.roundtrip(hopper(), subsampling=subsampling)
assert getsampling(im) == (2, 2, 1, 1, 1, 1) assert getsampling(im) == (2, 2, 1, 1, 1, 1)
# RGB colorspace, no subsampling by default # RGB colorspace
im = self.roundtrip(hopper(), keep_rgb=True) for subsampling in (-1, 0, "4:4:4"):
assert getsampling(im) == (1, 1, 1, 1, 1, 1) # "4:4:4" doesn't really make sense for RGB, but the conversion
# to an integer happens at a higher level
im = self.roundtrip(hopper(), keep_rgb=True, subsampling=subsampling)
assert getsampling(im) == (1, 1, 1, 1, 1, 1)
for subsampling in (1, "4:2:2", 2, "4:2:0", 3):
with pytest.raises(OSError):
self.roundtrip(hopper(), keep_rgb=True, subsampling=subsampling)
with pytest.raises(TypeError): with pytest.raises(TypeError):
self.roundtrip(hopper(), subsampling="1:1:1") self.roundtrip(hopper(), subsampling="1:1:1")

View File

@ -491,6 +491,9 @@ The :py:meth:`~PIL.Image.Image.save` method supports the following options:
If this option is present and true, those images will be stored as RGB If this option is present and true, those images will be stored as RGB
instead. instead.
When this option is enabled, attempting to chroma-subsample RGB images
with the ``subsampling`` option will raise an :py:exc:`OSError`.
.. versionadded:: 10.2.0 .. versionadded:: 10.2.0
**subsampling** **subsampling**

View File

@ -144,6 +144,16 @@ ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8 *buf, int bytes) {
#ifdef JCS_EXTENSIONS #ifdef JCS_EXTENSIONS
case JCS_EXT_RGBX: case JCS_EXT_RGBX:
#endif #endif
switch (context->subsampling) {
case -1: /* Default */
case 0: /* No subsampling */
break;
default:
/* Would subsample the green and blue
channels, which doesn't make sense */
state->errcode = IMAGING_CODEC_CONFIG;
return -1;
}
jpeg_set_colorspace(&context->cinfo, JCS_RGB); jpeg_set_colorspace(&context->cinfo, JCS_RGB);
break; break;
default: default: