mirror of
				https://github.com/python-pillow/Pillow.git
				synced 2025-10-31 07:57:27 +03:00 
			
		
		
		
	Merge branch 'master' of https://github.com/etienned/Pillow into etienned-master
This commit is contained in:
		
						commit
						b03abf2e58
					
				|  | @ -36,6 +36,7 @@ __version__ = "0.6" | ||||||
| 
 | 
 | ||||||
| import array, struct | import array, struct | ||||||
| from PIL import Image, ImageFile, _binary | from PIL import Image, ImageFile, _binary | ||||||
|  | from JpegPresets import presets | ||||||
| 
 | 
 | ||||||
| i8 = _binary.i8 | i8 = _binary.i8 | ||||||
| o8 = _binary.o8 | o8 = _binary.o8 | ||||||
|  | @ -416,6 +417,31 @@ RAWMODE = { | ||||||
|     "YCbCr": "YCbCr", |     "YCbCr": "YCbCr", | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | zigzag_index = ( 0,  1,  5,  6, 14, 15, 27, 28, | ||||||
|  |                  2,  4,  7, 13, 16, 26, 29, 42, | ||||||
|  |                  3,  8, 12, 17, 25, 30, 41, 43, | ||||||
|  |                  9, 11, 18, 24, 31, 40, 44, 53, | ||||||
|  |                 10, 19, 23, 32, 39, 45, 52, 54, | ||||||
|  |                 20, 22, 33, 38, 46, 51, 55, 60, | ||||||
|  |                 21, 34, 37, 47, 50, 56, 59, 61, | ||||||
|  |                 35, 36, 48, 49, 57, 58, 62, 63) | ||||||
|  | 
 | ||||||
|  | samplings = { | ||||||
|  |              (1, 1, 1, 1, 1, 1): 0, | ||||||
|  |              (2, 1, 1, 1, 1, 1): 1, | ||||||
|  |              (2, 2, 1, 1, 1, 1): 2, | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  | def convert_dict_qtables(qtables): | ||||||
|  |     qtables = [qtables[key] for key in xrange(len(qtables)) if qtables.has_key(key)] | ||||||
|  |     for idx, table in enumerate(qtables): | ||||||
|  |         qtables[idx] = [table[i] for i in zigzag_index] | ||||||
|  |     return qtables | ||||||
|  | 
 | ||||||
|  | def get_sampling(im): | ||||||
|  |     sampling = im.layer[0][1:3] + im.layer[1][1:3] + im.layer[2][1:3] | ||||||
|  |     return samplings.get(sampling, -1) | ||||||
|  | 
 | ||||||
| def _save(im, fp, filename): | def _save(im, fp, filename): | ||||||
| 
 | 
 | ||||||
|     try: |     try: | ||||||
|  | @ -427,13 +453,72 @@ def _save(im, fp, filename): | ||||||
| 
 | 
 | ||||||
|     dpi = info.get("dpi", (0, 0)) |     dpi = info.get("dpi", (0, 0)) | ||||||
| 
 | 
 | ||||||
|  |     quality = info.get("quality", 0) | ||||||
|     subsampling = info.get("subsampling", -1) |     subsampling = info.get("subsampling", -1) | ||||||
|  |     qtables = info.get("qtables") | ||||||
|  | 
 | ||||||
|  |     if quality == "keep": | ||||||
|  |         quality = 0 | ||||||
|  |         subsampling = "keep" | ||||||
|  |         qtables = "keep" | ||||||
|  |     elif quality in presets: | ||||||
|  |         preset = presets[quality] | ||||||
|  |         quality = 0 | ||||||
|  |         subsampling = preset.get('subsampling', -1) | ||||||
|  |         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) | ||||||
|  |         if qtables in presets: | ||||||
|  |             qtables = presets[qtables].get('quantization') | ||||||
|  | 
 | ||||||
|     if subsampling == "4:4:4": |     if subsampling == "4:4:4": | ||||||
|         subsampling = 0 |         subsampling = 0 | ||||||
|     elif subsampling == "4:2:2": |     elif subsampling == "4:2:2": | ||||||
|         subsampling = 1 |         subsampling = 1 | ||||||
|     elif subsampling == "4:1:1": |     elif subsampling == "4:1:1": | ||||||
|         subsampling = 2 |         subsampling = 2 | ||||||
|  |     elif subsampling == "keep": | ||||||
|  |         if im.format != "JPEG": | ||||||
|  |             raise ValueError("Cannot use 'keep' when original image is not a JPEG") | ||||||
|  |         subsampling = get_sampling(im)     | ||||||
|  | 
 | ||||||
|  |     def validate_qtables(qtables): | ||||||
|  |         if qtables is None: | ||||||
|  |             return qtables | ||||||
|  |         if isinstance(qtables, basestring): | ||||||
|  |             try: | ||||||
|  |                 lines = [int(num) for line in qtables.splitlines() | ||||||
|  |                          for num in line.split('#', 1)[0].split()] | ||||||
|  |             except ValueError: | ||||||
|  |                 raise ValueError("Invalid quantization table") | ||||||
|  |             else: | ||||||
|  |                 qtables = [lines[s:s+64] for s in xrange(0, len(lines), 64)] | ||||||
|  |         if isinstance(qtables, (tuple, list, dict)): | ||||||
|  |             if isinstance(qtables, dict): | ||||||
|  |                 qtables = convert_dict_qtables(qtables) | ||||||
|  |             elif isinstance(qtables, tuple): | ||||||
|  |                 qtables = list(qtables) | ||||||
|  |             if not (0 < len(qtables) < 5): | ||||||
|  |                 raise ValueError("None or too many quantization tables") | ||||||
|  |             for idx, table in enumerate(qtables): | ||||||
|  |                 try: | ||||||
|  |                     if len(table) != 64: | ||||||
|  |                         raise | ||||||
|  |                     table = array.array('b', table) | ||||||
|  |                 except TypeError: | ||||||
|  |                     raise ValueError("Invalid quantization table") | ||||||
|  |                 else: | ||||||
|  |                     qtables[idx] = list(table) | ||||||
|  |             return qtables | ||||||
|  |                  | ||||||
|  |     if qtables == "keep": | ||||||
|  |         if im.format != "JPEG": | ||||||
|  |             raise ValueError("Cannot use 'keep' when original image is not a JPEG") | ||||||
|  |         qtables = getattr(im, "quantization", None) | ||||||
|  |     qtables = validate_qtables(qtables) | ||||||
| 
 | 
 | ||||||
|     extra = b"" |     extra = b"" | ||||||
| 
 | 
 | ||||||
|  | @ -454,7 +539,7 @@ def _save(im, fp, filename): | ||||||
| 
 | 
 | ||||||
|     # get keyword arguments |     # get keyword arguments | ||||||
|     im.encoderconfig = ( |     im.encoderconfig = ( | ||||||
|         info.get("quality", 0), |         quality, | ||||||
|         # "progressive" is the official name, but older documentation |         # "progressive" is the official name, but older documentation | ||||||
|         # says "progression" |         # says "progression" | ||||||
|         # FIXME: issue a warning if the wrong form is used (post-1.1.7) |         # FIXME: issue a warning if the wrong form is used (post-1.1.7) | ||||||
|  | @ -464,6 +549,7 @@ def _save(im, fp, filename): | ||||||
|         info.get("streamtype", 0), |         info.get("streamtype", 0), | ||||||
|         dpi[0], dpi[1], |         dpi[0], dpi[1], | ||||||
|         subsampling, |         subsampling, | ||||||
|  |         qtables, | ||||||
|         extra, |         extra, | ||||||
|         info.get("exif", b"") |         info.get("exif", b"") | ||||||
|         ) |         ) | ||||||
|  |  | ||||||
							
								
								
									
										250
									
								
								PIL/JpegPresets.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										250
									
								
								PIL/JpegPresets.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,250 @@ | ||||||
|  | """ | ||||||
|  | JPEG quality settings equivalent to the Photoshop settings. | ||||||
|  | 
 | ||||||
|  | More presets can be added to the presets dict if needed. | ||||||
|  | 
 | ||||||
|  | Can be use when saving JPEG file. | ||||||
|  | 
 | ||||||
|  | To apply the preset, specify: | ||||||
|  | 
 | ||||||
|  |  - quality=preset name | ||||||
|  |   | ||||||
|  | To apply only the quantization table: | ||||||
|  | 
 | ||||||
|  | - qtables=preset name | ||||||
|  | 
 | ||||||
|  | To apply only the subsampling setting: | ||||||
|  | 
 | ||||||
|  | - subsampling=preset name | ||||||
|  | 
 | ||||||
|  | Example: | ||||||
|  | 
 | ||||||
|  |     im.save("image_name.jpg", quality="web_high") | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | Subsampling | ||||||
|  | ----------- | ||||||
|  | 
 | ||||||
|  | Subsampling is the practice of encoding images by implementing less resolution | ||||||
|  | for chroma information than for luma information. | ||||||
|  | (ref.: http://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?). | ||||||
|  | 
 | ||||||
|  | You can get the subsampling of a JPEG with the | ||||||
|  | `JpegImagePlugin.get_subsampling(im)` function. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | Quantization tables | ||||||
|  | ------------------- | ||||||
|  | 
 | ||||||
|  | They are values use by the DCT (Discrete cosine transform) to remove | ||||||
|  | *unnecessary* information from the image (the lossy part of the compression). | ||||||
|  | (ref.: http://en.wikipedia.org/wiki/Quantization_matrix#Quantization_matrices, | ||||||
|  |        http://en.wikipedia.org/wiki/JPEG#Quantization) | ||||||
|  | 
 | ||||||
|  | You can get the quantization tables of a JPEG with: | ||||||
|  | 
 | ||||||
|  |     im.quantization | ||||||
|  |      | ||||||
|  | This will return a dict with a number of arrays. You can pass this dict directly | ||||||
|  | as the qtables argument when saving a JPEG. | ||||||
|  | 
 | ||||||
|  | The tables format between im.quantization and quantization in presets differ in | ||||||
|  | 3 ways: | ||||||
|  | 
 | ||||||
|  |  1. The base container of the preset is a list with sublists instead of dict. | ||||||
|  |     dict[0] -> list[0], dict[1] -> list[1], ... | ||||||
|  |      | ||||||
|  |  2. Each table in a preset is a list instead of an array. | ||||||
|  |   | ||||||
|  |  3. The zigzag order is remove in the preset (needed by libjpeg >= 6a). | ||||||
|  |   | ||||||
|  | You can convert the dict format to the preset format with the | ||||||
|  | `JpegImagePlugin.convert_dict_qtables(dict_qtables)` function. | ||||||
|  | 
 | ||||||
|  | Libjpeg ref.: http://www.jpegcameras.com/libjpeg/libjpeg-3.html | ||||||
|  | 
 | ||||||
|  | """ | ||||||
|  | 
 | ||||||
|  | presets = {  | ||||||
|  |             'web_low':      {'subsampling':  2, # "4:1:1" | ||||||
|  |                             'quantization': [ | ||||||
|  |                                [20, 16, 25, 39, 50, 46, 62, 68, | ||||||
|  |                                 16, 18, 23, 38, 38, 53, 65, 68, | ||||||
|  |                                 25, 23, 31, 38, 53, 65, 68, 68, | ||||||
|  |                                 39, 38, 38, 53, 65, 68, 68, 68, | ||||||
|  |                                 50, 38, 53, 65, 68, 68, 68, 68, | ||||||
|  |                                 46, 53, 65, 68, 68, 68, 68, 68, | ||||||
|  |                                 62, 65, 68, 68, 68, 68, 68, 68, | ||||||
|  |                                 68, 68, 68, 68, 68, 68, 68, 68], | ||||||
|  |                                [21, 25, 32, 38, 54, 68, 68, 68, | ||||||
|  |                                 25, 28, 24, 38, 54, 68, 68, 68, | ||||||
|  |                                 32, 24, 32, 43, 66, 68, 68, 68, | ||||||
|  |                                 38, 38, 43, 53, 68, 68, 68, 68, | ||||||
|  |                                 54, 54, 66, 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" | ||||||
|  |                             'quantization': [ | ||||||
|  |                                [16, 11, 11, 16, 23, 27, 31, 30, | ||||||
|  |                                 11, 12, 12, 15, 20, 23, 23, 30, | ||||||
|  |                                 11, 12, 13, 16, 23, 26, 35, 47, | ||||||
|  |                                 16, 15, 16, 23, 26, 37, 47, 64, | ||||||
|  |                                 23, 20, 23, 26, 39, 51, 64, 64, | ||||||
|  |                                 27, 23, 26, 37, 51, 64, 64, 64, | ||||||
|  |                                 31, 23, 35, 47, 64, 64, 64, 64, | ||||||
|  |                                 30, 30, 47, 64, 64, 64, 64, 64], | ||||||
|  |                                [17, 15, 17, 21, 20, 26, 38, 48, | ||||||
|  |                                 15, 19, 18, 17, 20, 26, 35, 43, | ||||||
|  |                                 17, 18, 20, 22, 26, 30, 46, 53, | ||||||
|  |                                 21, 17, 22, 28, 30, 39, 53, 64, | ||||||
|  |                                 20, 20, 26, 30, 39, 48, 64, 64, | ||||||
|  |                                 26, 26, 30, 39, 48, 63, 64, 64, | ||||||
|  |                                 38, 35, 46, 53, 64, 64, 64, 64, | ||||||
|  |                                 48, 43, 53, 64, 64, 64, 64, 64] | ||||||
|  |                             ]}, | ||||||
|  |                              | ||||||
|  |             'web_high':     {'subsampling':  0, # "4:4:4" | ||||||
|  |                             'quantization': [ | ||||||
|  |                                [ 6,  4,  4,  6,  9, 11, 12, 16, | ||||||
|  |                                  4,  5,  5,  6,  8, 10, 12, 12, | ||||||
|  |                                  4,  5,  5,  6, 10, 12, 14, 19, | ||||||
|  |                                  6,  6,  6, 11, 12, 15, 19, 28, | ||||||
|  |                                  9,  8, 10, 12, 16, 20, 27, 31, | ||||||
|  |                                 11, 10, 12, 15, 20, 27, 31, 31, | ||||||
|  |                                 12, 12, 14, 19, 27, 31, 31, 31, | ||||||
|  |                                 16, 12, 19, 28, 31, 31, 31, 31], | ||||||
|  |                                [ 7,  7, 13, 24, 26, 31, 31, 31, | ||||||
|  |                                  7, 12, 16, 21, 31, 31, 31, 31, | ||||||
|  |                                 13, 16, 17, 31, 31, 31, 31, 31, | ||||||
|  |                                 24, 21, 31, 31, 31, 31, 31, 31, | ||||||
|  |                                 26, 31, 31, 31, 31, 31, 31, 31, | ||||||
|  |                                 31, 31, 31, 31, 31, 31, 31, 31, | ||||||
|  |                                 31, 31, 31, 31, 31, 31, 31, 31, | ||||||
|  |                                 31, 31, 31, 31, 31, 31, 31, 31] | ||||||
|  |                             ]}, | ||||||
|  |                              | ||||||
|  |             'web_very_high': {'subsampling':  0, # "4:4:4" | ||||||
|  |                             'quantization': [ | ||||||
|  |                                [ 2,  2,  2,  2,  3,  4,  5,  6, | ||||||
|  |                                  2,  2,  2,  2,  3,  4,  5,  6, | ||||||
|  |                                  2,  2,  2,  2,  4,  5,  7,  9, | ||||||
|  |                                  2,  2,  2,  4,  5,  7,  9, 12, | ||||||
|  |                                  3,  3,  4,  5,  8, 10, 12, 12, | ||||||
|  |                                  4,  4,  5,  7, 10, 12, 12, 12, | ||||||
|  |                                  5,  5,  7,  9, 12, 12, 12, 12, | ||||||
|  |                                  6,  6,  9, 12, 12, 12, 12, 12], | ||||||
|  |                                [ 3,  3,  5,  9, 13, 15, 15, 15, | ||||||
|  |                                  3,  4,  6, 11, 14, 12, 12, 12, | ||||||
|  |                                  5,  6,  9, 14, 12, 12, 12, 12, | ||||||
|  |                                  9, 11, 14, 12, 12, 12, 12, 12, | ||||||
|  |                                 13, 14, 12, 12, 12, 12, 12, 12, | ||||||
|  |                                 15, 12, 12, 12, 12, 12, 12, 12, | ||||||
|  |                                 15, 12, 12, 12, 12, 12, 12, 12, | ||||||
|  |                                 15, 12, 12, 12, 12, 12, 12, 12] | ||||||
|  |                             ]}, | ||||||
|  |                              | ||||||
|  |             'web_maximum':  {'subsampling':  0, # "4:4:4" | ||||||
|  |                             'quantization': [ | ||||||
|  |                                [ 1,  1,  1,  1,  1,  1,  1,  1,  | ||||||
|  |                                  1,  1,  1,  1,  1,  1,  1,  1,  | ||||||
|  |                                  1,  1,  1,  1,  1,  1,  1,  2,  | ||||||
|  |                                  1,  1,  1,  1,  1,  1,  2,  2,  | ||||||
|  |                                  1,  1,  1,  1,  1,  2,  2,  3,  | ||||||
|  |                                  1,  1,  1,  1,  2,  2,  3,  3,  | ||||||
|  |                                  1,  1,  1,  2,  2,  3,  3,  3,  | ||||||
|  |                                  1,  1,  2,  2,  3,  3,  3,  3], | ||||||
|  |                                [ 1,  1,  1,  2,  2,  3,  3,  3, | ||||||
|  |                                  1,  1,  1,  2,  3,  3,  3,  3, | ||||||
|  |                                  1,  1,  1,  3,  3,  3,  3,  3, | ||||||
|  |                                  2,  2,  3,  3,  3,  3,  3,  3, | ||||||
|  |                                  2,  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" | ||||||
|  |                             'quantization': [ | ||||||
|  |                                [18, 14, 14, 21, 30, 35, 34, 17, | ||||||
|  |                                 14, 16, 16, 19, 26, 23, 12, 12, | ||||||
|  |                                 14, 16, 17, 21, 23, 12, 12, 12, | ||||||
|  |                                 21, 19, 21, 23, 12, 12, 12, 12, | ||||||
|  |                                 30, 26, 23, 12, 12, 12, 12, 12, | ||||||
|  |                                 35, 23, 12, 12, 12, 12, 12, 12, | ||||||
|  |                                 34, 12, 12, 12, 12, 12, 12, 12, | ||||||
|  |                                 17, 12, 12, 12, 12, 12, 12, 12], | ||||||
|  |                                [20, 19, 22, 27, 20, 20, 17, 17, | ||||||
|  |                                 19, 25, 23, 14, 14, 12, 12, 12, | ||||||
|  |                                 22, 23, 14, 14, 12, 12, 12, 12, | ||||||
|  |                                 27, 14, 14, 12, 12, 12, 12, 12, | ||||||
|  |                                 20, 14, 12, 12, 12, 12, 12, 12, | ||||||
|  |                                 20, 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" | ||||||
|  |                             'quantization': [ | ||||||
|  |                                [12,  8,  8, 12, 17, 21, 24, 17, | ||||||
|  |                                  8,  9,  9, 11, 15, 19, 12, 12, | ||||||
|  |                                  8,  9, 10, 12, 19, 12, 12, 12, | ||||||
|  |                                 12, 11, 12, 21, 12, 12, 12, 12, | ||||||
|  |                                 17, 15, 19, 12, 12, 12, 12, 12, | ||||||
|  |                                 21, 19, 12, 12, 12, 12, 12, 12, | ||||||
|  |                                 24, 12, 12, 12, 12, 12, 12, 12, | ||||||
|  |                                 17, 12, 12, 12, 12, 12, 12, 12], | ||||||
|  |                                [13, 11, 13, 16, 20, 20, 17, 17, | ||||||
|  |                                 11, 14, 14, 14, 14, 12, 12, 12, | ||||||
|  |                                 13, 14, 14, 14, 12, 12, 12, 12, | ||||||
|  |                                 16, 14, 14, 12, 12, 12, 12, 12, | ||||||
|  |                                 20, 14, 12, 12, 12, 12, 12, 12, | ||||||
|  |                                 20, 12, 12, 12, 12, 12, 12, 12, | ||||||
|  |                                 17, 12, 12, 12, 12, 12, 12, 12, | ||||||
|  |                                 17, 12, 12, 12, 12, 12, 12, 12] | ||||||
|  |                             ]}, | ||||||
|  |                              | ||||||
|  |             'high':         {'subsampling':  0, # "4:4:4" | ||||||
|  |                             'quantization': [ | ||||||
|  |                                [ 6,  4,  4,  6,  9, 11, 12, 16, | ||||||
|  |                                  4,  5,  5,  6,  8, 10, 12, 12,  | ||||||
|  |                                  4,  5,  5,  6, 10, 12, 12, 12, | ||||||
|  |                                  6,  6,  6, 11, 12, 12, 12, 12, | ||||||
|  |                                  9,  8, 10, 12, 12, 12, 12, 12, | ||||||
|  |                                 11, 10, 12, 12, 12, 12, 12, 12, | ||||||
|  |                                 12, 12, 12, 12, 12, 12, 12, 12, | ||||||
|  |                                 16, 12, 12, 12, 12, 12, 12, 12], | ||||||
|  |                                [ 7,  7, 13, 24, 20, 20, 17, 17, | ||||||
|  |                                  7, 12, 16, 14, 14, 12, 12, 12, | ||||||
|  |                                 13, 16, 14, 14, 12, 12, 12, 12, | ||||||
|  |                                 24, 14, 14, 12, 12, 12, 12, 12, | ||||||
|  |                                 20, 14, 12, 12, 12, 12, 12, 12, | ||||||
|  |                                 20, 12, 12, 12, 12, 12, 12, 12, | ||||||
|  |                                 17, 12, 12, 12, 12, 12, 12, 12, | ||||||
|  |                                 17, 12, 12, 12, 12, 12, 12, 12] | ||||||
|  |                             ]}, | ||||||
|  |                              | ||||||
|  |             'maximum':      {'subsampling':  0, # "4:4:4" | ||||||
|  |                             'quantization': [ | ||||||
|  |                                [ 2,  2,  2,  2,  3,  4,  5,  6, | ||||||
|  |                                  2,  2,  2,  2,  3,  4,  5,  6, | ||||||
|  |                                  2,  2,  2,  2,  4,  5,  7,  9, | ||||||
|  |                                  2,  2,  2,  4,  5,  7,  9, 12, | ||||||
|  |                                  3,  3,  4,  5,  8, 10, 12, 12, | ||||||
|  |                                  4,  4,  5,  7, 10, 12, 12, 12, | ||||||
|  |                                  5,  5,  7,  9, 12, 12, 12, 12, | ||||||
|  |                                  6,  6,  9, 12, 12, 12, 12, 12], | ||||||
|  |                                [ 3,  3,  5,  9, 13, 15, 15, 15, | ||||||
|  |                                  3,  4,  6, 10, 14, 12, 12, 12, | ||||||
|  |                                  5,  6,  9, 14, 12, 12, 12, 12, | ||||||
|  |                                  9, 10, 14, 12, 12, 12, 12, 12, | ||||||
|  |                                 13, 14, 12, 12, 12, 12, 12, 12, | ||||||
|  |                                 15, 12, 12, 12, 12, 12, 12, 12, | ||||||
|  |                                 15, 12, 12, 12, 12, 12, 12, 12, | ||||||
|  |                                 15, 12, 12, 12, 12, 12, 12, 12] | ||||||
|  |                             ]}, | ||||||
|  |             } | ||||||
							
								
								
									
										72
									
								
								encode.c
									
									
									
									
									
								
							
							
						
						
									
										72
									
								
								encode.c
									
									
									
									
									
								
							|  | @ -506,6 +506,69 @@ PyImaging_ZipEncoderNew(PyObject* self, PyObject* args) | ||||||
| 
 | 
 | ||||||
| #include "Jpeg.h" | #include "Jpeg.h" | ||||||
| 
 | 
 | ||||||
|  | static unsigned int** get_qtables_arrays(PyObject* qtables) { | ||||||
|  |     PyObject* tables; | ||||||
|  |     PyObject* table; | ||||||
|  |     PyObject* table_data; | ||||||
|  |     int i, j, num_tables; | ||||||
|  |     unsigned int **qarrays; | ||||||
|  |      | ||||||
|  |     if (qtables == Py_None) { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     if (!PySequence_Check(qtables)) { | ||||||
|  |         PyErr_SetString(PyExc_ValueError, "Invalid quantization tables"); | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     tables = PySequence_Fast(qtables, "expected a sequence"); | ||||||
|  |     num_tables = PySequence_Size(qtables); | ||||||
|  |     if (num_tables < 2 || num_tables > NUM_QUANT_TBLS) { | ||||||
|  |         PyErr_SetString(PyExc_ValueError, "Not a valid numbers of quantization tables. Should be between 2 and 4."); | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |     qarrays = (unsigned int**) PyMem_Malloc(num_tables * sizeof(unsigned int)); | ||||||
|  |     if (!qarrays) { | ||||||
|  |         Py_DECREF(tables); | ||||||
|  |         PyErr_NoMemory(); | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |     for (i = 0; i < num_tables; i++) { | ||||||
|  |         table = PySequence_Fast_GET_ITEM(tables, i); | ||||||
|  |         if (!PySequence_Check(table)) { | ||||||
|  |             Py_DECREF(tables); | ||||||
|  |             PyErr_SetString(PyExc_ValueError, "Invalid quantization tables"); | ||||||
|  |             return NULL; | ||||||
|  |         } | ||||||
|  |         if (PySequence_Size(table) != DCTSIZE2) { | ||||||
|  |             Py_DECREF(tables); | ||||||
|  |             PyErr_SetString(PyExc_ValueError, "Invalid quantization tables"); | ||||||
|  |             return NULL; | ||||||
|  |         } | ||||||
|  |         table_data = PySequence_Fast(table, "expected a sequence"); | ||||||
|  |         qarrays[i] = (unsigned int*) PyMem_Malloc(DCTSIZE2 * sizeof(unsigned int)); | ||||||
|  |         if (!qarrays[i]) { | ||||||
|  |             Py_DECREF(tables); | ||||||
|  |             PyErr_NoMemory(); | ||||||
|  |             return NULL; | ||||||
|  |         } | ||||||
|  |         for (j = 0; j < DCTSIZE2; j++) { | ||||||
|  |             qarrays[i][j] = PyInt_AS_LONG(PySequence_Fast_GET_ITEM(table_data, j)); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     Py_DECREF(tables); | ||||||
|  | 
 | ||||||
|  |     if (PyErr_Occurred()) { | ||||||
|  |         PyMem_Free(qarrays); | ||||||
|  |         qarrays = NULL; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return qarrays; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| PyObject* | PyObject* | ||||||
| PyImaging_JpegEncoderNew(PyObject* self, PyObject* args) | PyImaging_JpegEncoderNew(PyObject* self, PyObject* args) | ||||||
| { | { | ||||||
|  | @ -520,15 +583,17 @@ PyImaging_JpegEncoderNew(PyObject* self, PyObject* args) | ||||||
|     int streamtype = 0; /* 0=interchange, 1=tables only, 2=image only */ |     int streamtype = 0; /* 0=interchange, 1=tables only, 2=image only */ | ||||||
|     int xdpi = 0, ydpi = 0; |     int xdpi = 0, ydpi = 0; | ||||||
|     int subsampling = -1; /* -1=default, 0=none, 1=medium, 2=high */ |     int subsampling = -1; /* -1=default, 0=none, 1=medium, 2=high */ | ||||||
|  |     PyObject* qtables; | ||||||
|  |     unsigned int **qarrays = NULL; | ||||||
|     char* extra = NULL; |     char* extra = NULL; | ||||||
|     int extra_size; |     int extra_size; | ||||||
|     char* rawExif = NULL; |     char* rawExif = NULL; | ||||||
|     int rawExifLen = 0; |     int rawExifLen = 0; | ||||||
| 
 | 
 | ||||||
|     if (!PyArg_ParseTuple(args, "ss|iiiiiiii"PY_ARG_BYTES_LENGTH""PY_ARG_BYTES_LENGTH, |     if (!PyArg_ParseTuple(args, "ss|iiiiiiiiO"PY_ARG_BYTES_LENGTH""PY_ARG_BYTES_LENGTH, | ||||||
|                           &mode, &rawmode, &quality, |                           &mode, &rawmode, &quality, | ||||||
|                           &progressive, &smooth, &optimize, &streamtype, |                           &progressive, &smooth, &optimize, &streamtype, | ||||||
|                           &xdpi, &ydpi, &subsampling, &extra, &extra_size, |                           &xdpi, &ydpi, &subsampling, &qtables, &extra, &extra_size, | ||||||
|                           &rawExif, &rawExifLen)) |                           &rawExif, &rawExifLen)) | ||||||
| 	return NULL; | 	return NULL; | ||||||
| 
 | 
 | ||||||
|  | @ -539,6 +604,8 @@ PyImaging_JpegEncoderNew(PyObject* self, PyObject* args) | ||||||
|     if (get_packer(encoder, mode, rawmode) < 0) |     if (get_packer(encoder, mode, rawmode) < 0) | ||||||
| 	return NULL; | 	return NULL; | ||||||
| 
 | 
 | ||||||
|  |     qarrays = get_qtables_arrays(qtables); | ||||||
|  | 
 | ||||||
|     if (extra && extra_size > 0) { |     if (extra && extra_size > 0) { | ||||||
|         char* p = malloc(extra_size); |         char* p = malloc(extra_size); | ||||||
|         if (!p) |         if (!p) | ||||||
|  | @ -560,6 +627,7 @@ PyImaging_JpegEncoderNew(PyObject* self, PyObject* args) | ||||||
|     encoder->encode = ImagingJpegEncode; |     encoder->encode = ImagingJpegEncode; | ||||||
| 
 | 
 | ||||||
|     ((JPEGENCODERSTATE*)encoder->state.context)->quality = quality; |     ((JPEGENCODERSTATE*)encoder->state.context)->quality = quality; | ||||||
|  |     ((JPEGENCODERSTATE*)encoder->state.context)->qtables = qarrays; | ||||||
|     ((JPEGENCODERSTATE*)encoder->state.context)->subsampling = subsampling; |     ((JPEGENCODERSTATE*)encoder->state.context)->subsampling = subsampling; | ||||||
|     ((JPEGENCODERSTATE*)encoder->state.context)->progressive = progressive; |     ((JPEGENCODERSTATE*)encoder->state.context)->progressive = progressive; | ||||||
|     ((JPEGENCODERSTATE*)encoder->state.context)->smooth = smooth; |     ((JPEGENCODERSTATE*)encoder->state.context)->smooth = smooth; | ||||||
|  |  | ||||||
|  | @ -88,6 +88,9 @@ typedef struct { | ||||||
|     /* Chroma Subsampling (-1=default, 0=none, 1=medium, 2=high) */ |     /* Chroma Subsampling (-1=default, 0=none, 1=medium, 2=high) */ | ||||||
|     int subsampling; |     int subsampling; | ||||||
| 
 | 
 | ||||||
|  |     /* Custom quantization tables () */ | ||||||
|  |     unsigned int **qtables; | ||||||
|  | 
 | ||||||
|     /* Extra data (to be injected after header) */ |     /* Extra data (to be injected after header) */ | ||||||
|     char* extra; int extra_size; |     char* extra; int extra_size; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -143,8 +143,22 @@ ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) | ||||||
| 
 | 
 | ||||||
| 	/* Compressor configuration */ | 	/* Compressor configuration */ | ||||||
| 	jpeg_set_defaults(&context->cinfo); | 	jpeg_set_defaults(&context->cinfo); | ||||||
| 	if (context->quality > 0) | 
 | ||||||
|  | 	/* Use custom quantization tables */ | ||||||
|  | 	if (context->qtables) { | ||||||
|  |         int i; | ||||||
|  |         int quality = 100; | ||||||
|  |         if (context->quality > 0) { | ||||||
|  |             quality = context->quality; | ||||||
|  |         } | ||||||
|  |         for (i = 0; i < sizeof(context->qtables)/sizeof(unsigned int); i++) { | ||||||
|  |              // TODO: Should add support for none baseline
 | ||||||
|  |             jpeg_add_quant_table(&context->cinfo, i, context->qtables[i], | ||||||
|  |                 quality, TRUE); | ||||||
|  |         } | ||||||
|  | 	} else if (context->quality > 0) { | ||||||
| 	    jpeg_set_quality(&context->cinfo, context->quality, 1); | 	    jpeg_set_quality(&context->cinfo, context->quality, 1); | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	/* Set subsampling options */ | 	/* Set subsampling options */ | ||||||
| 	switch (context->subsampling) | 	switch (context->subsampling) | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user