Skip to content

Commit

Permalink
Fail if chroma subsampling selected when writing RGB JPEG
Browse files Browse the repository at this point in the history
The user presumably doesn't intend to subsample the green and blue
channels.
  • Loading branch information
bgilbert committed Dec 14, 2023
1 parent 1414673 commit 0579883
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 3 deletions.
12 changes: 9 additions & 3 deletions Tests/test_file_jpeg.py
Original file line number Diff line number Diff line change
Expand Up @@ -447,9 +447,15 @@ def getsampling(im):
im = self.roundtrip(hopper(), subsampling=subsampling)
assert getsampling(im) == (2, 2, 1, 1, 1, 1)

# RGB colorspace, no subsampling by default
im = self.roundtrip(hopper(), keep_rgb=True)
assert getsampling(im) == (1, 1, 1, 1, 1, 1)
# RGB colorspace
for subsampling in (-1, 0, "4:4:4"):
# "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):
self.roundtrip(hopper(), subsampling="1:1:1")
Expand Down
3 changes: 3 additions & 0 deletions docs/handbook/image-file-formats.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
instead.

When this option is enabled, attempting to chroma-subsample RGB images
with the ``subsampling`` option will result in an error.

.. versionadded:: 10.2.0

**subsampling**
Expand Down
10 changes: 10 additions & 0 deletions src/libImaging/JpegEncode.c
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,16 @@ ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8 *buf, int bytes) {
#ifdef JCS_EXTENSIONS
case JCS_EXT_RGBX:
#endif
switch (context->subsampling) {
case -1: /* Default */
case 0: /* No subsampling */
break;
default:
/* Would subsample the GB channels, which
doesn't make sense */
state->errcode = IMAGING_CODEC_CONFIG;
return -1;
}
jpeg_set_colorspace(&context->cinfo, JCS_RGB);
break;
default:
Expand Down

0 comments on commit 0579883

Please sign in to comment.