From 9bbba0612982e5647ecf781a0794fc3b1f6db8ce Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Mon, 20 Apr 2020 21:06:47 +0200 Subject: [PATCH] src: PIL: JpegImagePlugin.py: make -1 and keep subsamplings identical for save Make the -1 subsampling behave like "keep" for the save method. The doc claims that -1 is equivalent to keep. It is actually equivalent to 4:2:0 for some reason. Note that -1 was representing both the -1 subsampling and the absence of it. To persist the current behavior which is compatible with multiple input file formats other than JPEG (which is not the case of the subsampling parameter), make the absence of subsampling parameter equal to -2. get_sampling() remains unchanged since it is a public API. Note that subsampling can be -1 and -2 in some cases, both results in an image with a subsampling of 4:2:0. Also removing faulty test case since subsampling -1 cannot be used on a generated image but only JPEG file format. Signed-off-by: Quentin Schulz --- Tests/test_file_jpeg.py | 2 -- docs/handbook/image-file-formats.rst | 3 ++- src/PIL/JpegImagePlugin.py | 8 ++++---- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/Tests/test_file_jpeg.py b/Tests/test_file_jpeg.py index 9f963d80f..0793d6faf 100644 --- a/Tests/test_file_jpeg.py +++ b/Tests/test_file_jpeg.py @@ -314,8 +314,6 @@ class TestFileJpeg: return layer[0][1:3] + layer[1][1:3] + layer[2][1:3] # experimental API - im = self.roundtrip(hopper(), subsampling=-1) # default - assert getsampling(im) == (2, 2, 1, 1, 1, 1) im = self.roundtrip(hopper(), subsampling=0) # 4:4:4 assert getsampling(im) == (1, 1, 1, 1, 1, 1) im = self.roundtrip(hopper(), subsampling=1) # 4:2:2 diff --git a/docs/handbook/image-file-formats.rst b/docs/handbook/image-file-formats.rst index 40db9fe2b..677d10347 100644 --- a/docs/handbook/image-file-formats.rst +++ b/docs/handbook/image-file-formats.rst @@ -334,7 +334,8 @@ The :py:meth:`~PIL.Image.Image.save` method supports the following options: If present, the image will be stored with the provided raw EXIF data. **subsampling** - If present, sets the subsampling for the encoder. + If present, sets the subsampling for the encoder. Otherwise, ``4:2:0`` is + the default subsampling. * ``keep``: Only valid for JPEG files, will retain the original image setting. * ``4:4:4``, ``4:2:2``, ``4:2:0``: Specific sampling values diff --git a/src/PIL/JpegImagePlugin.py b/src/PIL/JpegImagePlugin.py index 2aa029efb..ae235597f 100644 --- a/src/PIL/JpegImagePlugin.py +++ b/src/PIL/JpegImagePlugin.py @@ -618,7 +618,7 @@ def _save(im, fp, filename): dpi = [round(x) for x in info.get("dpi", (0, 0))] quality = info.get("quality", -1) - subsampling = info.get("subsampling", -1) + subsampling = info.get("subsampling", -2) qtables = info.get("qtables") if quality == "keep": @@ -628,13 +628,13 @@ def _save(im, fp, filename): elif quality in presets: preset = presets[quality] quality = -1 - subsampling = preset.get("subsampling", -1) + subsampling = preset.get("subsampling", -2) qtables = preset.get("quantization") elif not isinstance(quality, int): raise ValueError("Invalid quality setting") else: if subsampling in presets: - subsampling = presets[subsampling].get("subsampling", -1) + subsampling = presets[subsampling].get("subsampling", -2) if isinstance(qtables, str) and qtables in presets: qtables = presets[qtables].get("quantization") @@ -648,7 +648,7 @@ def _save(im, fp, filename): # For compatibility. Before Pillow 4.3, 4:1:1 actually meant 4:2:0. # Set 4:2:0 if someone is still using that value. subsampling = 2 - elif subsampling == "keep": + elif subsampling == "keep" or subsampling == -1: if im.format != "JPEG": raise ValueError("Cannot use 'keep' when original image is not a JPEG") subsampling = get_sampling(im)