From 4d56db3a34bdea8f11b9753603d05232e08f2c87 Mon Sep 17 00:00:00 2001 From: Alexander Date: Sun, 27 Aug 2017 20:03:36 +0300 Subject: [PATCH] Fix wrong formula for subsampling=2 while JPEG saving --- PIL/JpegImagePlugin.py | 4 ++++ PIL/JpegPresets.py | 10 +++++----- Tests/test_file_jpeg.py | 4 +++- docs/handbook/image-file-formats.rst | 4 ++-- libImaging/JpegEncode.c | 2 +- 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/PIL/JpegImagePlugin.py b/PIL/JpegImagePlugin.py index 6837ba450..d28c5e506 100644 --- a/PIL/JpegImagePlugin.py +++ b/PIL/JpegImagePlugin.py @@ -635,7 +635,11 @@ def _save(im, fp, filename): subsampling = 0 elif subsampling == "4:2:2": subsampling = 1 + elif subsampling == "4:2:0": + subsampling = 2 elif subsampling == "4:1:1": + # 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": if im.format != "JPEG": diff --git a/PIL/JpegPresets.py b/PIL/JpegPresets.py index 6fda20aec..5f01f0d2d 100644 --- a/PIL/JpegPresets.py +++ b/PIL/JpegPresets.py @@ -30,7 +30,7 @@ for chroma information than for luma information. (ref.: https://en.wikipedia.org/wiki/Chroma_subsampling) Possible subsampling values are 0, 1 and 2 that correspond to 4:4:4, 4:2:2 and -4:1:1 (or 4:2:0?). +4:2:0. You can get the subsampling of a JPEG with the `JpegImagePlugin.get_subsampling(im)` function. @@ -67,7 +67,7 @@ Libjpeg ref.: https://web.archive.org/web/20120328125543/http://www.jpegcameras. """ presets = { - 'web_low': {'subsampling': 2, # "4:1:1" + 'web_low': {'subsampling': 2, # "4:2:0" 'quantization': [ [20, 16, 25, 39, 50, 46, 62, 68, 16, 18, 23, 38, 38, 53, 65, 68, @@ -86,7 +86,7 @@ presets = { 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68] ]}, - 'web_medium': {'subsampling': 2, # "4:1:1" + 'web_medium': {'subsampling': 2, # "4:2:0" 'quantization': [ [16, 11, 11, 16, 23, 27, 31, 30, 11, 12, 12, 15, 20, 23, 23, 30, @@ -162,7 +162,7 @@ presets = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3] ]}, - 'low': {'subsampling': 2, # "4:1:1" + 'low': {'subsampling': 2, # "4:2:0" 'quantization': [ [18, 14, 14, 21, 30, 35, 34, 17, 14, 16, 16, 19, 26, 23, 12, 12, @@ -181,7 +181,7 @@ presets = { 17, 12, 12, 12, 12, 12, 12, 12, 17, 12, 12, 12, 12, 12, 12, 12] ]}, - 'medium': {'subsampling': 2, # "4:1:1" + 'medium': {'subsampling': 2, # "4:2:0" 'quantization': [ [12, 8, 8, 12, 17, 21, 24, 17, 8, 9, 9, 11, 15, 19, 12, 12, diff --git a/Tests/test_file_jpeg.py b/Tests/test_file_jpeg.py index 7f701d0f6..f2e798122 100644 --- a/Tests/test_file_jpeg.py +++ b/Tests/test_file_jpeg.py @@ -299,7 +299,7 @@ class TestFileJpeg(PillowTestCase): self.assertEqual(getsampling(im), (1, 1, 1, 1, 1, 1)) im = self.roundtrip(hopper(), subsampling=1) # 4:2:2 self.assertEqual(getsampling(im), (2, 1, 1, 1, 1, 1)) - im = self.roundtrip(hopper(), subsampling=2) # 4:1:1 + im = self.roundtrip(hopper(), subsampling=2) # 4:2:0 self.assertEqual(getsampling(im), (2, 2, 1, 1, 1, 1)) im = self.roundtrip(hopper(), subsampling=3) # default (undefined) self.assertEqual(getsampling(im), (2, 2, 1, 1, 1, 1)) @@ -308,6 +308,8 @@ class TestFileJpeg(PillowTestCase): self.assertEqual(getsampling(im), (1, 1, 1, 1, 1, 1)) im = self.roundtrip(hopper(), subsampling="4:2:2") self.assertEqual(getsampling(im), (2, 1, 1, 1, 1, 1)) + im = self.roundtrip(hopper(), subsampling="4:2:0") + self.assertEqual(getsampling(im), (2, 2, 1, 1, 1, 1)) im = self.roundtrip(hopper(), subsampling="4:1:1") self.assertEqual(getsampling(im), (2, 2, 1, 1, 1, 1)) diff --git a/docs/handbook/image-file-formats.rst b/docs/handbook/image-file-formats.rst index 6682d941f..4ced9fcae 100644 --- a/docs/handbook/image-file-formats.rst +++ b/docs/handbook/image-file-formats.rst @@ -275,11 +275,11 @@ The :py:meth:`~PIL.Image.Image.save` method supports the following options: If present, sets the subsampling for the encoder. * ``keep``: Only valid for JPEG files, will retain the original image setting. - * ``4:4:4``, ``4:2:2``, ``4:1:1``: Specific sampling values + * ``4:4:4``, ``4:2:2``, ``4:2:0``: Specific sampling values * ``-1``: equivalent to ``keep`` * ``0``: equivalent to ``4:4:4`` * ``1``: equivalent to ``4:2:2`` - * ``2``: equivalent to ``4:1:1`` + * ``2``: equivalent to ``4:2:0`` **qtables** If present, sets the qtables for the encoder. This is listed as an diff --git a/libImaging/JpegEncode.c b/libImaging/JpegEncode.c index 23f8a9a13..61a90ca5c 100644 --- a/libImaging/JpegEncode.c +++ b/libImaging/JpegEncode.c @@ -194,7 +194,7 @@ ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) context->cinfo.comp_info[2].v_samp_factor = 1; break; } - case 2: /* 2x2, 1x1, 1x1 (4:1:1) : High */ + case 2: /* 2x2, 1x1, 1x1 (4:2:0) : High */ { context->cinfo.comp_info[0].h_samp_factor = 2; context->cinfo.comp_info[0].v_samp_factor = 2;