mirror of
				https://github.com/python-pillow/Pillow.git
				synced 2025-11-04 01:47:47 +03:00 
			
		
		
		
	Merge pull request #2698 from uploadcare/jpeg-subsampling
Fix sampling factor for subsampling=2 while JPEG saving
This commit is contained in:
		
						commit
						32d14e382a
					
				| 
						 | 
					@ -635,7 +635,11 @@ def _save(im, fp, filename):
 | 
				
			||||||
        subsampling = 0
 | 
					        subsampling = 0
 | 
				
			||||||
    elif subsampling == "4:2:2":
 | 
					    elif subsampling == "4:2:2":
 | 
				
			||||||
        subsampling = 1
 | 
					        subsampling = 1
 | 
				
			||||||
 | 
					    elif subsampling == "4:2:0":
 | 
				
			||||||
 | 
					        subsampling = 2
 | 
				
			||||||
    elif subsampling == "4:1:1":
 | 
					    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
 | 
					        subsampling = 2
 | 
				
			||||||
    elif subsampling == "keep":
 | 
					    elif subsampling == "keep":
 | 
				
			||||||
        if im.format != "JPEG":
 | 
					        if im.format != "JPEG":
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -30,7 +30,7 @@ for chroma information than for luma information.
 | 
				
			||||||
(ref.: https://en.wikipedia.org/wiki/Chroma_subsampling)
 | 
					(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
 | 
					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
 | 
					You can get the subsampling of a JPEG with the
 | 
				
			||||||
`JpegImagePlugin.get_subsampling(im)` function.
 | 
					`JpegImagePlugin.get_subsampling(im)` function.
 | 
				
			||||||
| 
						 | 
					@ -67,7 +67,7 @@ Libjpeg ref.: https://web.archive.org/web/20120328125543/http://www.jpegcameras.
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
presets = {
 | 
					presets = {
 | 
				
			||||||
            'web_low':      {'subsampling':  2,  # "4:1:1"
 | 
					            'web_low':      {'subsampling':  2,  # "4:2:0"
 | 
				
			||||||
                             'quantization': [
 | 
					                             'quantization': [
 | 
				
			||||||
                               [20, 16, 25, 39, 50, 46, 62, 68,
 | 
					                               [20, 16, 25, 39, 50, 46, 62, 68,
 | 
				
			||||||
                                16, 18, 23, 38, 38, 53, 65, 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,
 | 
				
			||||||
                                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': [
 | 
					                             'quantization': [
 | 
				
			||||||
                               [16, 11, 11, 16, 23, 27, 31, 30,
 | 
					                               [16, 11, 11, 16, 23, 27, 31, 30,
 | 
				
			||||||
                                11, 12, 12, 15, 20, 23, 23, 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,
 | 
				
			||||||
                                 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': [
 | 
					                             'quantization': [
 | 
				
			||||||
                               [18, 14, 14, 21, 30, 35, 34, 17,
 | 
					                               [18, 14, 14, 21, 30, 35, 34, 17,
 | 
				
			||||||
                                14, 16, 16, 19, 26, 23, 12, 12,
 | 
					                                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,
 | 
				
			||||||
                                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': [
 | 
					                             'quantization': [
 | 
				
			||||||
                               [12,  8,  8, 12, 17, 21, 24, 17,
 | 
					                               [12,  8,  8, 12, 17, 21, 24, 17,
 | 
				
			||||||
                                 8,  9,  9, 11, 15, 19, 12, 12,
 | 
					                                 8,  9,  9, 11, 15, 19, 12, 12,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -299,7 +299,7 @@ class TestFileJpeg(PillowTestCase):
 | 
				
			||||||
        self.assertEqual(getsampling(im), (1, 1, 1, 1, 1, 1))
 | 
					        self.assertEqual(getsampling(im), (1, 1, 1, 1, 1, 1))
 | 
				
			||||||
        im = self.roundtrip(hopper(), subsampling=1)  # 4:2:2
 | 
					        im = self.roundtrip(hopper(), subsampling=1)  # 4:2:2
 | 
				
			||||||
        self.assertEqual(getsampling(im), (2, 1, 1, 1, 1, 1))
 | 
					        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))
 | 
					        self.assertEqual(getsampling(im), (2, 2, 1, 1, 1, 1))
 | 
				
			||||||
        im = self.roundtrip(hopper(), subsampling=3)  # default (undefined)
 | 
					        im = self.roundtrip(hopper(), subsampling=3)  # default (undefined)
 | 
				
			||||||
        self.assertEqual(getsampling(im), (2, 2, 1, 1, 1, 1))
 | 
					        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))
 | 
					        self.assertEqual(getsampling(im), (1, 1, 1, 1, 1, 1))
 | 
				
			||||||
        im = self.roundtrip(hopper(), subsampling="4:2:2")
 | 
					        im = self.roundtrip(hopper(), subsampling="4:2:2")
 | 
				
			||||||
        self.assertEqual(getsampling(im), (2, 1, 1, 1, 1, 1))
 | 
					        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")
 | 
					        im = self.roundtrip(hopper(), subsampling="4:1:1")
 | 
				
			||||||
        self.assertEqual(getsampling(im), (2, 2, 1, 1, 1, 1))
 | 
					        self.assertEqual(getsampling(im), (2, 2, 1, 1, 1, 1))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -275,11 +275,11 @@ The :py:meth:`~PIL.Image.Image.save` method supports the following options:
 | 
				
			||||||
    If present, sets the subsampling for the encoder.
 | 
					    If present, sets the subsampling for the encoder.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    * ``keep``: Only valid for JPEG files, will retain the original image setting.
 | 
					    * ``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``
 | 
					    * ``-1``: equivalent to ``keep``
 | 
				
			||||||
    * ``0``: equivalent to ``4:4:4``
 | 
					    * ``0``: equivalent to ``4:4:4``
 | 
				
			||||||
    * ``1``: equivalent to ``4:2:2``
 | 
					    * ``1``: equivalent to ``4:2:2``
 | 
				
			||||||
    * ``2``: equivalent to ``4:1:1``
 | 
					    * ``2``: equivalent to ``4:2:0``
 | 
				
			||||||
 | 
					
 | 
				
			||||||
**qtables**
 | 
					**qtables**
 | 
				
			||||||
    If present, sets the qtables for the encoder. This is listed as an
 | 
					    If present, sets the qtables for the encoder. This is listed as an
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -194,7 +194,7 @@ ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
 | 
				
			||||||
		    context->cinfo.comp_info[2].v_samp_factor = 1;
 | 
							    context->cinfo.comp_info[2].v_samp_factor = 1;
 | 
				
			||||||
		    break;
 | 
							    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].h_samp_factor = 2;
 | 
				
			||||||
		    context->cinfo.comp_info[0].v_samp_factor = 2;
 | 
							    context->cinfo.comp_info[0].v_samp_factor = 2;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user