mirror of
				https://github.com/python-pillow/Pillow.git
				synced 2025-10-30 23:47:27 +03:00 
			
		
		
		
	Fixed issue #857.
When saving a JPEG and specifying 'keep' for quality or subsampling, if the source JPEG image is in grayscale mode, don't try to find the subsampling of the source, because grayscale images don't have any subsampling (it's only for color components). For the moment the fix also ignores subsampling of CMYK JPEG because currently Pillow doesn't support encoding JPEG in YCCK mode (and subsampling doesn't make sense in CMYK, but Pillow permits saving CMYK JPEG with subsampling, that's a bug). This fix pass those errors silently, i.e. it doesn't raise an error when 'keep' is used but it's not possible to keep the subsampling (because the image is grayscale or CMYK). I think it's the proper behavior but I'm not sure.
This commit is contained in:
		
							parent
							
								
									a65351fcdf
								
							
						
					
					
						commit
						416d8e340e
					
				|  | @ -545,6 +545,15 @@ def convert_dict_qtables(qtables): | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def get_sampling(im): | def get_sampling(im): | ||||||
|  |     # There's no subsampling when image have only 1 layer | ||||||
|  |     # (grayscale images) or when they are CMYK (4 layers), | ||||||
|  |     # so set subsampling to default value. | ||||||
|  |     # | ||||||
|  |     # NOTE: currently Pillow can't encode JPEG to YCCK format. | ||||||
|  |     # If YCCK support is added in the future, subsampling code will have | ||||||
|  |     # to be updated (here and in JpegEncode.c) to deal with 4 layers. | ||||||
|  |     if not hasattr(im, 'layers') or im.layers in (1, 4): | ||||||
|  |         return -1 | ||||||
|     sampling = im.layer[0][1:3] + im.layer[1][1:3] + im.layer[2][1:3] |     sampling = im.layer[0][1:3] + im.layer[1][1:3] + im.layer[2][1:3] | ||||||
|     return samplings.get(sampling, -1) |     return samplings.get(sampling, -1) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										
											BIN
										
									
								
								Tests/images/lena_gray.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Tests/images/lena_gray.jpg
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 22 KiB | 
|  | @ -224,9 +224,18 @@ class TestFileJpeg(PillowTestCase): | ||||||
|         self.assertIsNone(im._getmp()) |         self.assertIsNone(im._getmp()) | ||||||
| 
 | 
 | ||||||
|     def test_quality_keep(self): |     def test_quality_keep(self): | ||||||
|  |         # RGB | ||||||
|         im = Image.open("Tests/images/lena.jpg") |         im = Image.open("Tests/images/lena.jpg") | ||||||
|         f = self.tempfile('temp.jpg') |         f = self.tempfile('temp.jpg') | ||||||
|         im.save(f, quality='keep') |         im.save(f, quality='keep') | ||||||
|  |         # Grayscale | ||||||
|  |         im = Image.open("Tests/images/lena_gray.jpg") | ||||||
|  |         f = self.tempfile('temp.jpg') | ||||||
|  |         im.save(f, quality='keep') | ||||||
|  |         # CMYK | ||||||
|  |         im = Image.open("Tests/images/pil_sample_cmyk.jpg") | ||||||
|  |         f = self.tempfile('temp.jpg') | ||||||
|  |         im.save(f, quality='keep') | ||||||
| 
 | 
 | ||||||
|     def test_junk_jpeg_header(self): |     def test_junk_jpeg_header(self): | ||||||
|         # https://github.com/python-pillow/Pillow/issues/630 |         # https://github.com/python-pillow/Pillow/issues/630 | ||||||
|  |  | ||||||
							
								
								
									
										10
									
								
								encode.c
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								encode.c
									
									
									
									
									
								
							|  | @ -540,8 +540,8 @@ static unsigned int** get_qtables_arrays(PyObject* qtables) { | ||||||
| 
 | 
 | ||||||
|     tables = PySequence_Fast(qtables, "expected a sequence"); |     tables = PySequence_Fast(qtables, "expected a sequence"); | ||||||
|     num_tables = PySequence_Size(qtables); |     num_tables = PySequence_Size(qtables); | ||||||
|     if (num_tables < 2 || num_tables > NUM_QUANT_TBLS) { |     if (num_tables < 1 || num_tables > NUM_QUANT_TBLS) { | ||||||
|         PyErr_SetString(PyExc_ValueError, "Not a valid numbers of quantization tables. Should be between 2 and 4."); |         PyErr_SetString(PyExc_ValueError, "Not a valid numbers of quantization tables. Should be between 1 and 4."); | ||||||
|         return NULL; |         return NULL; | ||||||
|     } |     } | ||||||
|     qarrays = (unsigned int**) PyMem_Malloc(num_tables * sizeof(unsigned int*)); |     qarrays = (unsigned int**) PyMem_Malloc(num_tables * sizeof(unsigned int*)); | ||||||
|  | @ -760,7 +760,7 @@ PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args) | ||||||
|                                                         (ttag_t) PyInt_AsLong(key), |                                                         (ttag_t) PyInt_AsLong(key), | ||||||
|                                                         intav); |                                                         intav); | ||||||
|                         free(intav); |                         free(intav); | ||||||
|                     }        |                     } | ||||||
|                 } else { |                 } else { | ||||||
|                     TRACE((" %d elements, setting as floats \n", len)); |                     TRACE((" %d elements, setting as floats \n", len)); | ||||||
|                     floatav = malloc(sizeof(float)*len); |                     floatav = malloc(sizeof(float)*len); | ||||||
|  | @ -903,7 +903,7 @@ PyImaging_Jpeg2KEncoderNew(PyObject *self, PyObject *args) | ||||||
|     j2k_decode_coord_tuple(tile_offset, |     j2k_decode_coord_tuple(tile_offset, | ||||||
|                            &context->tile_offset_x, |                            &context->tile_offset_x, | ||||||
|                            &context->tile_offset_y); |                            &context->tile_offset_y); | ||||||
|     j2k_decode_coord_tuple(tile_size,  |     j2k_decode_coord_tuple(tile_size, | ||||||
|                            &context->tile_size_x, |                            &context->tile_size_x, | ||||||
|                            &context->tile_size_y); |                            &context->tile_size_y); | ||||||
| 
 | 
 | ||||||
|  | @ -918,7 +918,7 @@ PyImaging_Jpeg2KEncoderNew(PyObject *self, PyObject *args) | ||||||
| 
 | 
 | ||||||
|         if (context->tile_offset_x > context->offset_x |         if (context->tile_offset_x > context->offset_x | ||||||
|             || context->tile_offset_y > context->offset_y) { |             || context->tile_offset_y > context->offset_y) { | ||||||
|             PyErr_SetString(PyExc_ValueError,  |             PyErr_SetString(PyExc_ValueError, | ||||||
|                             "JPEG 2000 tile offset too large to cover image area"); |                             "JPEG 2000 tile offset too large to cover image area"); | ||||||
|             Py_DECREF(encoder); |             Py_DECREF(encoder); | ||||||
|             return NULL; |             return NULL; | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user