Skip to content

Commit c2fe53c

Browse files
committed
Fail if chroma subsampling selected when writing RGB JPEG
The user presumably doesn't intend to subsample the green and blue channels.
1 parent c2b5686 commit c2fe53c

File tree

3 files changed

+22
-3
lines changed

3 files changed

+22
-3
lines changed

Tests/test_file_jpeg.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -447,9 +447,15 @@ def getsampling(im):
447447
im = self.roundtrip(hopper(), subsampling=subsampling)
448448
assert getsampling(im) == (2, 2, 1, 1, 1, 1)
449449

450-
# RGB colorspace, no subsampling by default
451-
im = self.roundtrip(hopper(), keep_rgb=True)
452-
assert getsampling(im) == (1, 1, 1, 1, 1, 1)
450+
# RGB colorspace
451+
for subsampling in (-1, 0, "4:4:4"):
452+
# "4:4:4" doesn't really make sense for RGB, but the conversion
453+
# to an integer happens at a higher level
454+
im = self.roundtrip(hopper(), keep_rgb=True, subsampling=subsampling)
455+
assert getsampling(im) == (1, 1, 1, 1, 1, 1)
456+
for subsampling in (1, "4:2:2", 2, "4:2:0", 3):
457+
with pytest.raises(OSError):
458+
self.roundtrip(hopper(), keep_rgb=True, subsampling=subsampling)
453459

454460
with pytest.raises(TypeError):
455461
self.roundtrip(hopper(), subsampling="1:1:1")

docs/handbook/image-file-formats.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,9 @@ The :py:meth:`~PIL.Image.Image.save` method supports the following options:
491491
If this option is present and true, those images will be stored as RGB
492492
instead.
493493

494+
When this option is enabled, attempting to chroma-subsample RGB images
495+
with the ``subsampling`` option will result in an error.
496+
494497
.. versionadded:: 10.2.0
495498

496499
**subsampling**

src/libImaging/JpegEncode.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,16 @@ ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8 *buf, int bytes) {
144144
#ifdef JCS_EXTENSIONS
145145
case JCS_EXT_RGBX:
146146
#endif
147+
switch (context->subsampling) {
148+
case -1: /* Default */
149+
case 0: /* No subsampling */
150+
break;
151+
default:
152+
/* Would subsample the GB channels, which
153+
doesn't make sense */
154+
state->errcode = IMAGING_CODEC_CONFIG;
155+
return -1;
156+
}
147157
jpeg_set_colorspace(&context->cinfo, JCS_RGB);
148158
break;
149159
default:

0 commit comments

Comments
 (0)