Merge branch 'master' into jpeg_qtables
							
								
								
									
										15
									
								
								CHANGES.rst
									
									
									
									
									
								
							
							
						
						|  | @ -4,6 +4,21 @@ Changelog (Pillow) | |||
| 2.5.0 (unreleased) | ||||
| ------------------ | ||||
| 
 | ||||
| - Add binary morphology addon | ||||
|   [dov, wiredfool] | ||||
| 
 | ||||
| - Decompression bomb protection | ||||
|   [hugovk] | ||||
| 
 | ||||
| - Put images in a single directory | ||||
|   [hugovk] | ||||
| 
 | ||||
| - Support OpenJpeg 2.1 | ||||
|   [al45tair] | ||||
| 
 | ||||
| - Remove unistd.h #include for all platforms | ||||
|   [wiredfool] | ||||
| 
 | ||||
| - Use unittest for tests | ||||
|   [hugovk] | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										29
									
								
								PIL/Image.py
									
									
									
									
									
								
							
							
						
						|  | @ -31,11 +31,18 @@ from PIL import VERSION, PILLOW_VERSION, _plugins | |||
| import warnings | ||||
| 
 | ||||
| 
 | ||||
| class DecompressionBombWarning(RuntimeWarning): | ||||
|     pass | ||||
| 
 | ||||
| class _imaging_not_installed: | ||||
|     # module placeholder | ||||
|     def __getattr__(self, id): | ||||
|         raise ImportError("The _imaging C module is not installed") | ||||
| 
 | ||||
| 
 | ||||
| # Limit to around a quarter gigabyte for a 24 bit (3 bpp) image | ||||
| MAX_IMAGE_PIXELS = int(1024 * 1024 * 1024 / 4 / 3) | ||||
| 
 | ||||
| try: | ||||
|     # give Tk a chance to set up the environment, in case we're | ||||
|     # using an _imaging module linked against libtcl/libtk (use | ||||
|  | @ -2172,6 +2179,20 @@ _fromarray_typemap[((1, 1), _ENDIAN + "i4")] = ("I", "I") | |||
| _fromarray_typemap[((1, 1), _ENDIAN + "f4")] = ("F", "F") | ||||
| 
 | ||||
| 
 | ||||
| def _decompression_bomb_check(size): | ||||
|     if MAX_IMAGE_PIXELS is None: | ||||
|         return | ||||
| 
 | ||||
|     pixels = size[0] * size[1] | ||||
| 
 | ||||
|     if pixels > MAX_IMAGE_PIXELS: | ||||
|         warnings.warn( | ||||
|             "Image size (%d pixels) exceeds limit of %d pixels, " | ||||
|             "could be decompression bomb DOS attack." % | ||||
|             (pixels, MAX_IMAGE_PIXELS), | ||||
|             DecompressionBombWarning) | ||||
| 
 | ||||
| 
 | ||||
| def open(fp, mode="r"): | ||||
|     """ | ||||
|     Opens and identifies the given image file. | ||||
|  | @ -2209,7 +2230,9 @@ def open(fp, mode="r"): | |||
|             factory, accept = OPEN[i] | ||||
|             if not accept or accept(prefix): | ||||
|                 fp.seek(0) | ||||
|                 return factory(fp, filename) | ||||
|                 im = factory(fp, filename) | ||||
|                 _decompression_bomb_check(im.size) | ||||
|                 return im | ||||
|         except (SyntaxError, IndexError, TypeError): | ||||
|             # import traceback | ||||
|             # traceback.print_exc() | ||||
|  | @ -2222,7 +2245,9 @@ def open(fp, mode="r"): | |||
|                 factory, accept = OPEN[i] | ||||
|                 if not accept or accept(prefix): | ||||
|                     fp.seek(0) | ||||
|                     return factory(fp, filename) | ||||
|                     im = factory(fp, filename) | ||||
|                     _decompression_bomb_check(im.size) | ||||
|                     return im | ||||
|             except (SyntaxError, IndexError, TypeError): | ||||
|                 # import traceback | ||||
|                 # traceback.print_exc() | ||||
|  |  | |||
|  | @ -6,7 +6,7 @@ | |||
| # | ||||
| # For a background, see "Image Processing By Interpolation and | ||||
| # Extrapolation", Paul Haeberli and Douglas Voorhies.  Available | ||||
| # at http://www.sgi.com/grafica/interp/index.html | ||||
| # at http://www.graficaobscura.com/interp/index.html | ||||
| # | ||||
| # History: | ||||
| # 1996-03-23 fl  Created | ||||
|  |  | |||
|  | @ -396,7 +396,7 @@ w7IkEbzhVQAAAABJRU5ErkJggg== | |||
| if __name__ == "__main__": | ||||
|     # create font data chunk for embedding | ||||
|     import base64, os, sys | ||||
|     font = "../Images/courB08" | ||||
|     font = "../Tests/images/courB08" | ||||
|     print("    f._load_pilfont_data(") | ||||
|     print("         # %s" % os.path.basename(font)) | ||||
|     print("         BytesIO(base64.decodestring(b'''") | ||||
|  |  | |||
							
								
								
									
										236
									
								
								PIL/ImageMorph.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,236 @@ | |||
| # A binary morphology add-on for the Python Imaging Library | ||||
| # | ||||
| # History: | ||||
| #   2014-06-04 Initial version. | ||||
| # | ||||
| # Copyright (c) 2014 Dov Grobgeld <dov.grobgeld@gmail.com> | ||||
| 
 | ||||
| from PIL import Image | ||||
| from PIL import _imagingmorph | ||||
| import re | ||||
| 
 | ||||
| LUT_SIZE = 1<<9 | ||||
| class LutBuilder: | ||||
|     """A class for building MorphLut's from a descriptive language | ||||
| 
 | ||||
|       The input patterns is a list of a strings sequences like these: | ||||
| 
 | ||||
|       4:(... | ||||
|          .1. | ||||
|          111)->1 | ||||
| 
 | ||||
|       (whitespaces including linebreaks are ignored). The option 4 | ||||
|       descibes a series of symmetry operations (in this case a | ||||
|       4-rotation), the pattern is decribed by: | ||||
| 
 | ||||
|          . or X - Ignore | ||||
|          1 - Pixel is on | ||||
|          0 - Pixel is off | ||||
| 
 | ||||
|       The result of the operation is described after "->" string. | ||||
| 
 | ||||
|       The default is to return the current pixel value, which is | ||||
|       returned if no other match is found. | ||||
| 
 | ||||
|       Operations: | ||||
|          4 - 4 way rotation | ||||
|          N - Negate | ||||
|          1 - Dummy op for no other operation (an op must always be given) | ||||
|          M - Mirroring | ||||
| 
 | ||||
|       Example: | ||||
| 
 | ||||
|       lb = LutBuilder(patterns = ["4:(... .1. 111)->1"]) | ||||
|       lut = lb.build_lut() | ||||
|           | ||||
|     """ | ||||
|     def __init__(self,patterns = None,op_name=None): | ||||
|         if patterns is not None: | ||||
|             self.patterns = patterns | ||||
|         else: | ||||
|             self.patterns = [] | ||||
|         self.lut = None | ||||
|         if op_name is not None: | ||||
|             known_patterns = { | ||||
|                 'corner' : ['1:(... ... ...)->0', | ||||
|                             '4:(00. 01. ...)->1'], | ||||
|                 'dilation4' : ['4:(... .0. .1.)->1'], | ||||
|                 'dilation8' : ['4:(... .0. .1.)->1', | ||||
|                                '4:(... .0. ..1)->1'], | ||||
|                 'erosion4' : ['4:(... .1. .0.)->0'], | ||||
|                 'erosion8' : ['4:(... .1. .0.)->0', | ||||
|                               '4:(... .1. ..0)->0'], | ||||
|                 'edge' : ['1:(... ... ...)->0', | ||||
|                           '4:(.0. .1. ...)->1', | ||||
|                           '4:(01. .1. ...)->1'] | ||||
|             } | ||||
|             if not op_name in known_patterns: | ||||
|                 raise Exception('Unknown pattern '+op_name+'!') | ||||
| 
 | ||||
|             self.patterns = known_patterns[op_name] | ||||
| 
 | ||||
|     def add_patterns(self, patterns): | ||||
|         self.patterns += patterns | ||||
| 
 | ||||
|     def build_default_lut(self): | ||||
|         symbols = [0, 1] | ||||
|         m = 1 << 4  # pos of current pixel | ||||
|         self.lut = bytearray([symbols[(i & m)>0] for i in range(LUT_SIZE)]) | ||||
| 
 | ||||
|     def get_lut(self): | ||||
|         return self.lut | ||||
| 
 | ||||
|     def _string_permute(self, pattern, permutation): | ||||
|         """string_permute takes a pattern and a permutation and returns the | ||||
|         string permuted accordinging to the permutation list. | ||||
|         """ | ||||
|         assert(len(permutation)==9) | ||||
|         return ''.join([pattern[p] for p in permutation]) | ||||
| 
 | ||||
|     def _pattern_permute(self, basic_pattern, options, basic_result): | ||||
|         """pattern_permute takes a basic pattern and its result and clones | ||||
|         the mattern according to the modifications described in the $options | ||||
|         parameter. It returns a list of all cloned patterns.""" | ||||
|         patterns = [(basic_pattern, basic_result)] | ||||
| 
 | ||||
|         # rotations | ||||
|         if '4' in options: | ||||
|             res = patterns[-1][1] | ||||
|             for i in range(4): | ||||
|                 patterns.append( | ||||
|                     (self._string_permute(patterns[-1][0], | ||||
|                                     [6,3,0, | ||||
|                                      7,4,1, | ||||
|                                      8,5,2]), res)) | ||||
|         # mirror | ||||
|         if 'M' in options: | ||||
|             n = len(patterns) | ||||
|             for pattern,res in patterns[0:n]: | ||||
|                 patterns.append( | ||||
|                     (self._string_permute(pattern, [2,1,0, | ||||
| 					      5,4,3, | ||||
| 					      8,7,6]), res)) | ||||
| 
 | ||||
|         # negate | ||||
|         if 'N' in options: | ||||
|             n = len(patterns) | ||||
|             for pattern,res in patterns[0:n]: | ||||
|                 # Swap 0 and 1 | ||||
|                 pattern = (pattern | ||||
|                            .replace('0','Z') | ||||
|                            .replace('1','0') | ||||
|                            .replace('Z','1')) | ||||
|                 res = '%d'%(1-int(res)) | ||||
|                 patterns.append((pattern, res)) | ||||
| 
 | ||||
|         return patterns | ||||
| 
 | ||||
|     def build_lut(self): | ||||
|         """Compile all patterns into a morphology lut. | ||||
| 
 | ||||
|         TBD :Build based on (file) morphlut:modify_lut | ||||
|         """ | ||||
|         self.build_default_lut() | ||||
|         patterns = [] | ||||
| 
 | ||||
|         # Parse and create symmetries of the patterns strings | ||||
|         for p in self.patterns: | ||||
|             m = re.search(r'(\w*):?\s*\((.+?)\)\s*->\s*(\d)', p.replace('\n','')) | ||||
|             if not m: | ||||
|                 raise Exception('Syntax error in pattern "'+p+'"') | ||||
|             options = m.group(1) | ||||
|             pattern = m.group(2) | ||||
|             result = int(m.group(3)) | ||||
| 
 | ||||
|             # Get rid of spaces | ||||
|             pattern= pattern.replace(' ','').replace('\n','') | ||||
| 
 | ||||
|             patterns += self._pattern_permute(pattern, options, result) | ||||
| 
 | ||||
| #        # Debugging | ||||
| #        for p,r in patterns: | ||||
| #            print p,r | ||||
| #        print '--' | ||||
| 
 | ||||
|         # compile the patterns into regular expressions for speed | ||||
|         for i in range(len(patterns)): | ||||
|             p = patterns[i][0].replace('.','X').replace('X','[01]') | ||||
|             p = re.compile(p) | ||||
|             patterns[i] = (p, patterns[i][1]) | ||||
| 
 | ||||
|         # Step through table and find patterns that match. | ||||
|         # Note that all the patterns are searched. The last one | ||||
|         # caught overrides | ||||
|         for i in range(LUT_SIZE): | ||||
|             # Build the bit pattern | ||||
|             bitpattern = bin(i)[2:] | ||||
|             bitpattern = ('0'*(9-len(bitpattern)) + bitpattern)[::-1] | ||||
| 
 | ||||
|             for p,r in patterns: | ||||
|                 if p.match(bitpattern): | ||||
|                     self.lut[i] = [0, 1][r] | ||||
| 
 | ||||
|         return self.lut | ||||
|          | ||||
| class MorphOp: | ||||
|     """A class for binary morphological operators""" | ||||
| 
 | ||||
|     def __init__(self, | ||||
|                  lut=None, | ||||
|                  op_name = None, | ||||
|                  patterns = None): | ||||
|         """Create a binary morphological operator""" | ||||
|         self.lut = lut | ||||
|         if op_name is not None: | ||||
|             self.lut = LutBuilder(op_name = op_name).build_lut() | ||||
|         elif patterns is not None: | ||||
|             self.lut = LutBuilder(patterns = patterns).build_lut() | ||||
| 
 | ||||
|     def apply(self, image): | ||||
|         """Run a single morphological operation on an image | ||||
| 
 | ||||
|         Returns a tuple of the number of changed pixels and the | ||||
|         morphed image""" | ||||
|         if self.lut is None: | ||||
|             raise Exception('No operator loaded') | ||||
|          | ||||
|         outimage = Image.new(image.mode, image.size, None) | ||||
|         count = _imagingmorph.apply(bytes(self.lut), image.im.id, outimage.im.id) | ||||
|         return count, outimage | ||||
|      | ||||
|     def match(self, image): | ||||
|         """Get a list of coordinates matching the morphological operation on an image | ||||
| 
 | ||||
|         Returns a list of tuples of (x,y) coordinates of all matching pixels.""" | ||||
|         if self.lut is None: | ||||
|             raise Exception('No operator loaded') | ||||
|          | ||||
|         return  _imagingmorph.match(bytes(self.lut), image.im.id) | ||||
| 
 | ||||
|     def get_on_pixels(self, image): | ||||
|         """Get a list of all turned on pixels in a binary image | ||||
|         Returns a list of tuples of (x,y) coordinates of all matching pixels.""" | ||||
|          | ||||
|         return  _imagingmorph.get_on_pixels(image.im.id) | ||||
| 
 | ||||
|     def load_lut(self, filename): | ||||
|         """Load an operator from an mrl file""" | ||||
|         with open(filename,'rb') as f: | ||||
|             self.lut = bytearray(f.read()) | ||||
|              | ||||
|         if len(self.lut)!= 8192: | ||||
|             self.lut = None | ||||
|             raise Exception('Wrong size operator file!') | ||||
| 
 | ||||
|     def save_lut(self, filename): | ||||
|         """Load an operator save mrl file""" | ||||
|         if self.lut is None: | ||||
|             raise Exception('No operator loaded') | ||||
|         with open(filename,'wb') as f: | ||||
|             f.write(self.lut) | ||||
| 
 | ||||
|     def set_lut(self, lut): | ||||
|         """Set the lut from an external source""" | ||||
|         self.lut = lut | ||||
| 
 | ||||
|      | ||||
|  | @ -158,15 +158,25 @@ class Jpeg2KImageFile(ImageFile.ImageFile): | |||
|         self.layers = 0 | ||||
| 
 | ||||
|         fd = -1 | ||||
|         length = -1 | ||||
| 
 | ||||
|         if hasattr(self.fp, "fileno"): | ||||
|             try: | ||||
|                 fd = self.fp.fileno() | ||||
|                 length = os.fstat(fd).st_size | ||||
|             except: | ||||
|                 fd = -1 | ||||
| 
 | ||||
|         elif hasattr(self.fp, "seek"): | ||||
|             try: | ||||
|                 pos = f.tell() | ||||
|                 f.seek(0, 2) | ||||
|                 length = f.tell() | ||||
|                 f.seek(pos, 0) | ||||
|             except: | ||||
|                 length = -1 | ||||
|          | ||||
|         self.tile = [('jpeg2k', (0, 0) + self.size, 0, | ||||
|                       (self.codec, self.reduce, self.layers, fd))] | ||||
|                       (self.codec, self.reduce, self.layers, fd, length))] | ||||
| 
 | ||||
|     def load(self): | ||||
|         if self.reduce: | ||||
|  | @ -178,7 +188,7 @@ class Jpeg2KImageFile(ImageFile.ImageFile): | |||
|         if self.tile: | ||||
|             # Update the reduce and layers settings | ||||
|             t = self.tile[0] | ||||
|             t3 = (t[3][0], self.reduce, self.layers, t[3][3]) | ||||
|             t3 = (t[3][0], self.reduce, self.layers, t[3][3], t[3][4]) | ||||
|             self.tile = [(t[0], (0, 0) + self.size, t[2], t3)] | ||||
| 
 | ||||
|         ImageFile.ImageFile.load(self) | ||||
|  |  | |||
|  | @ -14,11 +14,11 @@ | |||
| # | ||||
| 
 | ||||
| # NOTE: This format cannot be automatically recognized, so the reader | ||||
| # is not registered for use with Image.open().  To open a WEL file, use | ||||
| # is not registered for use with Image.open().  To open a WAL file, use | ||||
| # the WalImageFile.open() function instead. | ||||
| 
 | ||||
| # This reader is based on the specification available from: | ||||
| #    http://www.flipcode.com/tutorials/tut_q2levels.shtml | ||||
| #    http://www.flipcode.com/archives/Quake_2_BSP_File_Format.shtml | ||||
| # and has been tested with a few sample files found using google. | ||||
| 
 | ||||
| from __future__ import print_function | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| 
 | ||||
| Python SANE module V1.1 (30 Sep. 2004) | ||||
| ================================================================================ | ||||
| 
 | ||||
| The SANE module provides an interface to the SANE scanner and frame | ||||
| grabber interface for Linux.  This module was contributed by Andrew | ||||
|  | @ -9,11 +9,11 @@ word 'SANE' or 'sane' in the subject of your mail, otherwise it might | |||
| be classified as spam in the future. | ||||
| 
 | ||||
| 
 | ||||
| To build this module, type (in the Sane directory): | ||||
| To build this module, type (in the Sane directory):: | ||||
| 
 | ||||
| 	python setup.py build | ||||
| 
 | ||||
| In order to install the module type: | ||||
| In order to install the module type:: | ||||
| 
 | ||||
| 	python setup.py install | ||||
| 
 | ||||
|  | @ -1,6 +1,5 @@ | |||
| ------- | ||||
| Scripts | ||||
| ------- | ||||
| ======= | ||||
| 
 | ||||
| This directory contains a number of more or less trivial utilities | ||||
| and demo programs. | ||||
|  | @ -9,50 +8,50 @@ Comments and contributions are welcome. | |||
| 
 | ||||
| </F> | ||||
| 
 | ||||
| -------------------------------------------------------------------- | ||||
| pildriver.py (by Eric S. Raymond) | ||||
| -------------------------------------------------------------------- | ||||
| 
 | ||||
| A class implementing an image-processing calculator for scripts. | ||||
| Parses lists of commnds (or, called interactively, command-line | ||||
| arguments) into image loads, transformations, and saves. | ||||
| 
 | ||||
| -------------------------------------------------------------------- | ||||
| viewer.py | ||||
| -------------------------------------------------------------------- | ||||
| 
 | ||||
| A simple image viewer.  Can display all file formats handled by | ||||
| PIL.  Transparent images are properly handled. | ||||
| 
 | ||||
| -------------------------------------------------------------------- | ||||
| thresholder.py | ||||
| -------------------------------------------------------------------- | ||||
| 
 | ||||
| A simple utility that demonstrates how a transparent 1-bit overlay | ||||
| can be used to show the current thresholding of an 8-bit image. | ||||
| 
 | ||||
| -------------------------------------------------------------------- | ||||
| enhancer.py | ||||
| -------------------------------------------------------------------- | ||||
| 
 | ||||
| Illustrates the ImageEnhance module.  Drag the sliders to modify the | ||||
| images.  This might be very slow on some platforms, depending on the | ||||
| Tk version. | ||||
| 
 | ||||
| -------------------------------------------------------------------- | ||||
| painter.py | ||||
| -------------------------------------------------------------------- | ||||
| 
 | ||||
| Illustrates how a painting program could be based on PIL and Tk. | ||||
| Press the left mouse button and drag over the image to remove the | ||||
| colour.  Some clever tricks have been used to get decent performance | ||||
| when updating the screen; see the sources for details. | ||||
| 
 | ||||
| -------------------------------------------------------------------- | ||||
| player.py | ||||
| -------------------------------------------------------------------- | ||||
| 
 | ||||
| A simple image sequence player.  You can use either a sequence format | ||||
| like FLI/FLC, GIF, or ARG, or give a number of images which are | ||||
| interpreted as frames in a sequence.  All frames must have the same | ||||
| size. | ||||
| 
 | ||||
| -------------------------------------------------------------------- | ||||
| gifmaker.py | ||||
| -------------------------------------------------------------------- | ||||
| 
 | ||||
| Convert a sequence file to a GIF animation. | ||||
| 
 | ||||
|  | @ -60,20 +59,20 @@ Note that the GIF encoder provided with this release of PIL writes | |||
| uncompressed GIF files only, so the resulting animations are rather | ||||
| large compared with these created by other tools. | ||||
| 
 | ||||
| -------------------------------------------------------------------- | ||||
| explode.py | ||||
| -------------------------------------------------------------------- | ||||
| 
 | ||||
| Split a sequence file into individual frames. | ||||
| 
 | ||||
| -------------------------------------------------------------------- | ||||
| image2py.py | ||||
| -------------------------------------------------------------------- | ||||
| 
 | ||||
| Convert an image to a Python module containing an IMAGE variable. | ||||
| Note that the module using the module must include JPEG and ZIP | ||||
| decoders, unless the -u option is used. | ||||
| 
 | ||||
| -------------------------------------------------------------------- | ||||
| olesummary.py | ||||
| -------------------------------------------------------------------- | ||||
| 
 | ||||
| Uses the OleFileIO module to dump the summary information from an OLE | ||||
| structured storage file.  This works with most OLE files, including | ||||
|  | @ -233,7 +233,7 @@ def lena(mode="RGB", cache={}): | |||
|     # im = cache.get(mode) | ||||
|     if im is None: | ||||
|         if mode == "RGB": | ||||
|             im = Image.open("Images/lena.ppm") | ||||
|             im = Image.open("Tests/images/lena.ppm") | ||||
|         elif mode == "F": | ||||
|             im = lena("L").convert(mode) | ||||
|         elif mode[:4] == "I;16": | ||||
|  |  | |||
							
								
								
									
										
											BIN
										
									
								
								Tests/images/corner.lut
									
									
									
									
									
										Normal file
									
								
							
							
						
						| Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB | 
							
								
								
									
										
											BIN
										
									
								
								Tests/images/dilation4.lut
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								Tests/images/dilation8.lut
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								Tests/images/edge.lut
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								Tests/images/erosion4.lut
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								Tests/images/erosion8.lut
									
									
									
									
									
										Normal file
									
								
							
							
						
						| Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB | 
| Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB | 
| Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB | 
| Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB | 
| Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.7 KiB | 
| Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 37 KiB | 
| Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB | 
							
								
								
									
										
											BIN
										
									
								
								Tests/images/morph_a.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 83 B | 
| Before Width: | Height: | Size: 100 KiB After Width: | Height: | Size: 100 KiB | 
| Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB | 
| Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 7.9 KiB | 
							
								
								
									
										45
									
								
								Tests/test_decompression_bomb.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,45 @@ | |||
| from helper import unittest, PillowTestCase, tearDownModule | ||||
| 
 | ||||
| from PIL import Image | ||||
| 
 | ||||
| test_file = "Tests/images/lena.ppm" | ||||
| 
 | ||||
| ORIGINAL_LIMIT = Image.MAX_IMAGE_PIXELS | ||||
| 
 | ||||
| 
 | ||||
| class TestDecompressionBomb(PillowTestCase): | ||||
| 
 | ||||
|     def tearDown(self): | ||||
|         Image.MAX_IMAGE_PIXELS = ORIGINAL_LIMIT | ||||
| 
 | ||||
|     def test_no_warning_small_file(self): | ||||
|         # Implicit assert: no warning. | ||||
|         # A warning would cause a failure. | ||||
|         Image.open(test_file) | ||||
| 
 | ||||
|     def test_no_warning_no_limit(self): | ||||
|         # Arrange | ||||
|         # Turn limit off | ||||
|         Image.MAX_IMAGE_PIXELS = None | ||||
|         self.assertEqual(Image.MAX_IMAGE_PIXELS, None) | ||||
| 
 | ||||
|         # Act / Assert | ||||
|         # Implicit assert: no warning. | ||||
|         # A warning would cause a failure. | ||||
|         Image.open(test_file) | ||||
| 
 | ||||
|     def test_warning(self): | ||||
|         # Arrange | ||||
|         # Set limit to a low, easily testable value | ||||
|         Image.MAX_IMAGE_PIXELS = 10 | ||||
|         self.assertEqual(Image.MAX_IMAGE_PIXELS, 10) | ||||
| 
 | ||||
|         # Act / Assert | ||||
|         self.assert_warning( | ||||
|             Image.DecompressionBombWarning, | ||||
|             lambda: Image.open(test_file)) | ||||
| 
 | ||||
| if __name__ == '__main__': | ||||
|     unittest.main() | ||||
| 
 | ||||
| # End of file | ||||
|  | @ -3,7 +3,7 @@ from helper import unittest, PillowTestCase, tearDownModule | |||
| from PIL import Image | ||||
| 
 | ||||
| # sample ppm stream | ||||
| file = "Images/lena.fli" | ||||
| file = "Tests/images/lena.fli" | ||||
| data = open(file, "rb").read() | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -5,7 +5,7 @@ from PIL import Image | |||
| codecs = dir(Image.core) | ||||
| 
 | ||||
| # sample gif stream | ||||
| file = "Images/lena.gif" | ||||
| file = "Tests/images/lena.gif" | ||||
| with open(file, "rb") as f: | ||||
|     data = f.read() | ||||
| 
 | ||||
|  | @ -45,7 +45,7 @@ class TestFileGif(PillowTestCase): | |||
|     def test_roundtrip2(self): | ||||
|         # see https://github.com/python-pillow/Pillow/issues/403 | ||||
|         out = self.tempfile('temp.gif') | ||||
|         im = Image.open('Images/lena.gif') | ||||
|         im = Image.open('Tests/images/lena.gif') | ||||
|         im2 = im.copy() | ||||
|         im2.save(out) | ||||
|         reread = Image.open(out) | ||||
|  | @ -55,7 +55,7 @@ class TestFileGif(PillowTestCase): | |||
|     def test_palette_handling(self): | ||||
|         # see https://github.com/python-pillow/Pillow/issues/513 | ||||
| 
 | ||||
|         im = Image.open('Images/lena.gif') | ||||
|         im = Image.open('Tests/images/lena.gif') | ||||
|         im = im.convert('RGB') | ||||
| 
 | ||||
|         im = im.resize((100, 100), Image.ANTIALIAS) | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ from helper import unittest, PillowTestCase, tearDownModule | |||
| from PIL import Image | ||||
| 
 | ||||
| # sample icon file | ||||
| file = "Images/pillow.icns" | ||||
| file = "Tests/images/pillow.icns" | ||||
| data = open(file, "rb").read() | ||||
| 
 | ||||
| enable_jpeg2k = hasattr(Image.core, 'jp2klib_version') | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ from helper import unittest, PillowTestCase, tearDownModule | |||
| from PIL import Image | ||||
| 
 | ||||
| # sample ppm stream | ||||
| file = "Images/lena.ico" | ||||
| file = "Tests/images/lena.ico" | ||||
| data = open(file, "rb").read() | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -10,7 +10,7 @@ codecs = dir(Image.core) | |||
| 
 | ||||
| # sample png stream | ||||
| 
 | ||||
| file = "Images/lena.png" | ||||
| file = "Tests/images/lena.png" | ||||
| data = open(file, "rb").read() | ||||
| 
 | ||||
| # stuff to create inline PNG images | ||||
|  | @ -204,10 +204,10 @@ class TestFilePng(PillowTestCase): | |||
|     def test_load_verify(self): | ||||
|         # Check open/load/verify exception (@PIL150) | ||||
| 
 | ||||
|         im = Image.open("Images/lena.png") | ||||
|         im = Image.open("Tests/images/lena.png") | ||||
|         im.verify() | ||||
| 
 | ||||
|         im = Image.open("Images/lena.png") | ||||
|         im = Image.open("Tests/images/lena.png") | ||||
|         im.load() | ||||
|         self.assertRaises(RuntimeError, lambda: im.verify()) | ||||
| 
 | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ from helper import unittest, PillowTestCase, tearDownModule | |||
| from PIL import Image | ||||
| 
 | ||||
| # sample ppm stream | ||||
| file = "Images/lena.ppm" | ||||
| file = "Tests/images/lena.ppm" | ||||
| data = open(file, "rb").read() | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ from helper import unittest, PillowTestCase, tearDownModule | |||
| from PIL import Image | ||||
| 
 | ||||
| # sample ppm stream | ||||
| file = "Images/lena.psd" | ||||
| file = "Tests/images/lena.psd" | ||||
| data = open(file, "rb").read() | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -5,7 +5,7 @@ from PIL import Image, TarIO | |||
| codecs = dir(Image.core) | ||||
| 
 | ||||
| # sample ppm stream | ||||
| tarfile = "Images/lena.tar" | ||||
| tarfile = "Tests/images/lena.tar" | ||||
| 
 | ||||
| 
 | ||||
| class TestFileTar(PillowTestCase): | ||||
|  |  | |||
|  | @ -23,7 +23,7 @@ class TestFileWebp(PillowTestCase): | |||
| 
 | ||||
|     def test_read_rgb(self): | ||||
| 
 | ||||
|         file_path = "Images/lena.webp" | ||||
|         file_path = "Tests/images/lena.webp" | ||||
|         image = Image.open(file_path) | ||||
| 
 | ||||
|         self.assertEqual(image.mode, "RGB") | ||||
|  | @ -33,7 +33,7 @@ class TestFileWebp(PillowTestCase): | |||
|         image.getdata() | ||||
| 
 | ||||
|         # generated with: | ||||
|         # dwebp -ppm ../../Images/lena.webp -o lena_webp_bits.ppm | ||||
|         # dwebp -ppm ../../Tests/images/lena.webp -o lena_webp_bits.ppm | ||||
|         target = Image.open('Tests/images/lena_webp_bits.ppm') | ||||
|         self.assert_image_similar(image, target, 20.0) | ||||
| 
 | ||||
|  |  | |||
|  | @ -22,7 +22,7 @@ class TestFileWebpAlpha(PillowTestCase): | |||
| 
 | ||||
|     def test_read_rgba(self): | ||||
|         # Generated with `cwebp transparent.png -o transparent.webp` | ||||
|         file_path = "Images/transparent.webp" | ||||
|         file_path = "Tests/images/transparent.webp" | ||||
|         image = Image.open(file_path) | ||||
| 
 | ||||
|         self.assertEqual(image.mode, "RGBA") | ||||
|  | @ -33,7 +33,7 @@ class TestFileWebpAlpha(PillowTestCase): | |||
| 
 | ||||
|         image.tobytes() | ||||
| 
 | ||||
|         target = Image.open('Images/transparent.png') | ||||
|         target = Image.open('Tests/images/transparent.png') | ||||
|         self.assert_image_similar(image, target, 20.0) | ||||
| 
 | ||||
|     def test_write_lossless_rgb(self): | ||||
|  |  | |||
|  | @ -15,7 +15,7 @@ class TestFileWebpMetadata(PillowTestCase): | |||
| 
 | ||||
|     def test_read_exif_metadata(self): | ||||
| 
 | ||||
|         file_path = "Images/flower.webp" | ||||
|         file_path = "Tests/images/flower.webp" | ||||
|         image = Image.open(file_path) | ||||
| 
 | ||||
|         self.assertEqual(image.format, "WEBP") | ||||
|  | @ -54,7 +54,7 @@ class TestFileWebpMetadata(PillowTestCase): | |||
| 
 | ||||
|     def test_read_icc_profile(self): | ||||
| 
 | ||||
|         file_path = "Images/flower2.webp" | ||||
|         file_path = "Tests/images/flower2.webp" | ||||
|         image = Image.open(file_path) | ||||
| 
 | ||||
|         self.assertEqual(image.format, "WEBP") | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ from helper import unittest, PillowTestCase, tearDownModule | |||
| from PIL import Image | ||||
| 
 | ||||
| # sample ppm stream | ||||
| file = "Images/lena.xpm" | ||||
| file = "Tests/images/lena.xpm" | ||||
| data = open(file, "rb").read() | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ from helper import unittest, PillowTestCase, tearDownModule | |||
| 
 | ||||
| from PIL import FontFile, BdfFontFile | ||||
| 
 | ||||
| filename = "Images/courB08.bdf" | ||||
| filename = "Tests/images/courB08.bdf" | ||||
| 
 | ||||
| 
 | ||||
| class TestFontBdf(PillowTestCase): | ||||
|  |  | |||
|  | @ -36,7 +36,7 @@ class TestImageConvert(PillowTestCase): | |||
|         self.assertEqual(orig, converted) | ||||
| 
 | ||||
|     def test_8bit(self): | ||||
|         im = Image.open('Images/lena.jpg') | ||||
|         im = Image.open('Tests/images/lena.jpg') | ||||
|         self._test_float_conversion(im.convert('L')) | ||||
| 
 | ||||
|     def test_16bit(self): | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ from helper import unittest, PillowTestCase, tearDownModule, fromstring, tostrin | |||
| from PIL import Image | ||||
| 
 | ||||
| codecs = dir(Image.core) | ||||
| filename = "Images/lena.jpg" | ||||
| filename = "Tests/images/lena.jpg" | ||||
| data = tostring(Image.open(filename).resize((512, 512)), "JPEG") | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -16,14 +16,14 @@ class TestImageLoad(PillowTestCase): | |||
|         self.assertEqual(pix[0, 0], (223, 162, 133)) | ||||
| 
 | ||||
|     def test_close(self): | ||||
|         im = Image.open("Images/lena.gif") | ||||
|         im = Image.open("Tests/images/lena.gif") | ||||
|         im.close() | ||||
|         self.assertRaises(ValueError, lambda: im.load()) | ||||
|         self.assertRaises(ValueError, lambda: im.getpixel((0, 0))) | ||||
| 
 | ||||
|     def test_contextmanager(self): | ||||
|         fn = None | ||||
|         with Image.open("Images/lena.gif") as im: | ||||
|         with Image.open("Tests/images/lena.gif") as im: | ||||
|             fn = im.fp.fileno() | ||||
|             os.fstat(fn) | ||||
| 
 | ||||
|  |  | |||
|  | @ -18,6 +18,8 @@ class TestImageCms(PillowTestCase): | |||
|     def setUp(self): | ||||
|         try: | ||||
|             from PIL import ImageCms | ||||
|             # need to hit getattr to trigger the delayed import error | ||||
|             ImageCms.core.profile_open | ||||
|         except ImportError as v: | ||||
|             self.skipTest(v) | ||||
| 
 | ||||
|  |  | |||
|  | @ -7,21 +7,21 @@ from PIL import ImageDraw | |||
| import sys | ||||
| 
 | ||||
| # Image size | ||||
| w, h = 100, 100 | ||||
| W, H = 100, 100 | ||||
| 
 | ||||
| # Bounding box points | ||||
| x0 = int(w / 4) | ||||
| x1 = int(x0 * 3) | ||||
| y0 = int(h / 4) | ||||
| y1 = int(x0 * 3) | ||||
| X0 = int(W / 4) | ||||
| X1 = int(X0 * 3) | ||||
| Y0 = int(H / 4) | ||||
| Y1 = int(X0 * 3) | ||||
| 
 | ||||
| # Two kinds of bounding box | ||||
| bbox1 = [(x0, y0), (x1, y1)] | ||||
| bbox2 = [x0, y0, x1, y1] | ||||
| BBOX1 = [(X0, Y0), (X1, Y1)] | ||||
| BBOX2 = [X0, Y0, X1, Y1] | ||||
| 
 | ||||
| # Two kinds of coordinate sequences | ||||
| points1 = [(10, 10), (20, 40), (30, 30)] | ||||
| points2 = [10, 10, 20, 40, 30, 30] | ||||
| POINTS1 = [(10, 10), (20, 40), (30, 30)] | ||||
| POINTS2 = [10, 10, 20, 40, 30, 30] | ||||
| 
 | ||||
| 
 | ||||
| class TestImageDraw(PillowTestCase): | ||||
|  | @ -47,7 +47,7 @@ class TestImageDraw(PillowTestCase): | |||
| 
 | ||||
|     def helper_arc(self, bbox): | ||||
|         # Arrange | ||||
|         im = Image.new("RGB", (w, h)) | ||||
|         im = Image.new("RGB", (W, H)) | ||||
|         draw = ImageDraw.Draw(im) | ||||
| 
 | ||||
|         # Act | ||||
|  | @ -60,15 +60,15 @@ class TestImageDraw(PillowTestCase): | |||
|             im, Image.open("Tests/images/imagedraw_arc.png")) | ||||
| 
 | ||||
|     def test_arc1(self): | ||||
|         self.helper_arc(bbox1) | ||||
|         self.helper_arc(BBOX1) | ||||
| 
 | ||||
|     def test_arc2(self): | ||||
|         self.helper_arc(bbox2) | ||||
|         self.helper_arc(BBOX2) | ||||
| 
 | ||||
|     def test_bitmap(self): | ||||
|         # Arrange | ||||
|         small = Image.open("Tests/images/pil123rgba.png").resize((50, 50)) | ||||
|         im = Image.new("RGB", (w, h)) | ||||
|         im = Image.new("RGB", (W, H)) | ||||
|         draw = ImageDraw.Draw(im) | ||||
| 
 | ||||
|         # Act | ||||
|  | @ -81,7 +81,7 @@ class TestImageDraw(PillowTestCase): | |||
| 
 | ||||
|     def helper_chord(self, bbox): | ||||
|         # Arrange | ||||
|         im = Image.new("RGB", (w, h)) | ||||
|         im = Image.new("RGB", (W, H)) | ||||
|         draw = ImageDraw.Draw(im) | ||||
| 
 | ||||
|         # Act | ||||
|  | @ -93,14 +93,14 @@ class TestImageDraw(PillowTestCase): | |||
|             im, Image.open("Tests/images/imagedraw_chord.png")) | ||||
| 
 | ||||
|     def test_chord1(self): | ||||
|         self.helper_chord(bbox1) | ||||
|         self.helper_chord(BBOX1) | ||||
| 
 | ||||
|     def test_chord2(self): | ||||
|         self.helper_chord(bbox2) | ||||
|         self.helper_chord(BBOX2) | ||||
| 
 | ||||
|     def helper_ellipse(self, bbox): | ||||
|         # Arrange | ||||
|         im = Image.new("RGB", (w, h)) | ||||
|         im = Image.new("RGB", (W, H)) | ||||
|         draw = ImageDraw.Draw(im) | ||||
| 
 | ||||
|         # Act | ||||
|  | @ -112,18 +112,18 @@ class TestImageDraw(PillowTestCase): | |||
|             im, Image.open("Tests/images/imagedraw_ellipse.png")) | ||||
| 
 | ||||
|     def test_ellipse1(self): | ||||
|         self.helper_ellipse(bbox1) | ||||
|         self.helper_ellipse(BBOX1) | ||||
| 
 | ||||
|     def test_ellipse2(self): | ||||
|         self.helper_ellipse(bbox2) | ||||
|         self.helper_ellipse(BBOX2) | ||||
| 
 | ||||
|     def helper_line(self, points): | ||||
|         # Arrange | ||||
|         im = Image.new("RGB", (w, h)) | ||||
|         im = Image.new("RGB", (W, H)) | ||||
|         draw = ImageDraw.Draw(im) | ||||
| 
 | ||||
|         # Act | ||||
|         draw.line(points1, fill="yellow", width=2) | ||||
|         draw.line(points, fill="yellow", width=2) | ||||
|         del draw | ||||
| 
 | ||||
|         # Assert | ||||
|  | @ -131,14 +131,14 @@ class TestImageDraw(PillowTestCase): | |||
|             im, Image.open("Tests/images/imagedraw_line.png")) | ||||
| 
 | ||||
|     def test_line1(self): | ||||
|         self.helper_line(points1) | ||||
|         self.helper_line(POINTS1) | ||||
| 
 | ||||
|     def test_line2(self): | ||||
|         self.helper_line(points2) | ||||
|         self.helper_line(POINTS2) | ||||
| 
 | ||||
|     def helper_pieslice(self, bbox): | ||||
|         # Arrange | ||||
|         im = Image.new("RGB", (w, h)) | ||||
|         im = Image.new("RGB", (W, H)) | ||||
|         draw = ImageDraw.Draw(im) | ||||
| 
 | ||||
|         # Act | ||||
|  | @ -150,18 +150,18 @@ class TestImageDraw(PillowTestCase): | |||
|             im, Image.open("Tests/images/imagedraw_pieslice.png")) | ||||
| 
 | ||||
|     def test_pieslice1(self): | ||||
|         self.helper_pieslice(bbox1) | ||||
|         self.helper_pieslice(BBOX1) | ||||
| 
 | ||||
|     def test_pieslice2(self): | ||||
|         self.helper_pieslice(bbox2) | ||||
|         self.helper_pieslice(BBOX2) | ||||
| 
 | ||||
|     def helper_point(self, points): | ||||
|         # Arrange | ||||
|         im = Image.new("RGB", (w, h)) | ||||
|         im = Image.new("RGB", (W, H)) | ||||
|         draw = ImageDraw.Draw(im) | ||||
| 
 | ||||
|         # Act | ||||
|         draw.point(points1, fill="yellow") | ||||
|         draw.point(points, fill="yellow") | ||||
|         del draw | ||||
| 
 | ||||
|         # Assert | ||||
|  | @ -169,18 +169,18 @@ class TestImageDraw(PillowTestCase): | |||
|             im, Image.open("Tests/images/imagedraw_point.png")) | ||||
| 
 | ||||
|     def test_point1(self): | ||||
|         self.helper_point(points1) | ||||
|         self.helper_point(POINTS1) | ||||
| 
 | ||||
|     def test_point2(self): | ||||
|         self.helper_point(points2) | ||||
|         self.helper_point(POINTS2) | ||||
| 
 | ||||
|     def helper_polygon(self, points): | ||||
|         # Arrange | ||||
|         im = Image.new("RGB", (w, h)) | ||||
|         im = Image.new("RGB", (W, H)) | ||||
|         draw = ImageDraw.Draw(im) | ||||
| 
 | ||||
|         # Act | ||||
|         draw.polygon(points1, fill="red", outline="blue") | ||||
|         draw.polygon(points, fill="red", outline="blue") | ||||
|         del draw | ||||
| 
 | ||||
|         # Assert | ||||
|  | @ -188,14 +188,14 @@ class TestImageDraw(PillowTestCase): | |||
|             im, Image.open("Tests/images/imagedraw_polygon.png")) | ||||
| 
 | ||||
|     def test_polygon1(self): | ||||
|         self.helper_polygon(points1) | ||||
|         self.helper_polygon(POINTS1) | ||||
| 
 | ||||
|     def test_polygon2(self): | ||||
|         self.helper_polygon(points2) | ||||
|         self.helper_polygon(POINTS2) | ||||
| 
 | ||||
|     def helper_rectangle(self, bbox): | ||||
|         # Arrange | ||||
|         im = Image.new("RGB", (w, h)) | ||||
|         im = Image.new("RGB", (W, H)) | ||||
|         draw = ImageDraw.Draw(im) | ||||
| 
 | ||||
|         # Act | ||||
|  | @ -207,17 +207,17 @@ class TestImageDraw(PillowTestCase): | |||
|             im, Image.open("Tests/images/imagedraw_rectangle.png")) | ||||
| 
 | ||||
|     def test_rectangle1(self): | ||||
|         self.helper_rectangle(bbox1) | ||||
|         self.helper_rectangle(BBOX1) | ||||
| 
 | ||||
|     def test_rectangle2(self): | ||||
|         self.helper_rectangle(bbox2) | ||||
|         self.helper_rectangle(BBOX2) | ||||
| 
 | ||||
|     def test_floodfill(self): | ||||
|         # Arrange | ||||
|         im = Image.new("RGB", (w, h)) | ||||
|         im = Image.new("RGB", (W, H)) | ||||
|         draw = ImageDraw.Draw(im) | ||||
|         draw.rectangle(bbox2, outline="yellow", fill="green") | ||||
|         centre_point = (int(w/2), int(h/2)) | ||||
|         draw.rectangle(BBOX2, outline="yellow", fill="green") | ||||
|         centre_point = (int(W/2), int(H/2)) | ||||
| 
 | ||||
|         # Act | ||||
|         ImageDraw.floodfill(im, centre_point, ImageColor.getrgb("red")) | ||||
|  | @ -233,10 +233,10 @@ class TestImageDraw(PillowTestCase): | |||
|         # floodfill() is experimental | ||||
| 
 | ||||
|         # Arrange | ||||
|         im = Image.new("RGB", (w, h)) | ||||
|         im = Image.new("RGB", (W, H)) | ||||
|         draw = ImageDraw.Draw(im) | ||||
|         draw.rectangle(bbox2, outline="yellow", fill="green") | ||||
|         centre_point = (int(w/2), int(h/2)) | ||||
|         draw.rectangle(BBOX2, outline="yellow", fill="green") | ||||
|         centre_point = (int(W/2), int(H/2)) | ||||
| 
 | ||||
|         # Act | ||||
|         ImageDraw.floodfill( | ||||
|  |  | |||
							
								
								
									
										169
									
								
								Tests/test_imagemorph.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,169 @@ | |||
| # Test the ImageMorphology functionality | ||||
| from helper import * | ||||
| 
 | ||||
| from PIL import Image | ||||
| from PIL import ImageMorph | ||||
| 
 | ||||
| 
 | ||||
| class MorphTests(PillowTestCase): | ||||
| 
 | ||||
|     def setUp(self): | ||||
|         self.A = self.string_to_img( | ||||
|             """     | ||||
|             ....... | ||||
|             ....... | ||||
|             ..111.. | ||||
|             ..111.. | ||||
|             ..111.. | ||||
|             ....... | ||||
|             ....... | ||||
|             """ | ||||
|             )     | ||||
|      | ||||
| 
 | ||||
|     def img_to_string(self, im): | ||||
|         """Turn a (small) binary image into a string representation""" | ||||
|         chars = '.1' | ||||
|         width, height = im.size | ||||
|         return '\n'.join( | ||||
|             [''.join([chars[im.getpixel((c,r))>0] for c in range(width)]) | ||||
|              for r in range(height)]) | ||||
| 
 | ||||
|     def string_to_img(self, image_string): | ||||
|         """Turn a string image representation into a binary image""" | ||||
|         rows = [s for s in image_string.replace(' ','').split('\n') | ||||
|                 if len(s)] | ||||
|         height = len(rows) | ||||
|         width = len(rows[0]) | ||||
|         im = Image.new('L',(width,height)) | ||||
|         for i in range(width): | ||||
|             for j in range(height): | ||||
|                 c = rows[j][i] | ||||
|                 v = c in 'X1' | ||||
|                 im.putpixel((i,j),v) | ||||
| 
 | ||||
|         return im | ||||
| 
 | ||||
|     def img_string_normalize(self, im): | ||||
|         return self.img_to_string(self.string_to_img(im)) | ||||
| 
 | ||||
|     def assert_img_equal(self, A, B): | ||||
|         self.assertEqual(self.img_to_string(A), self.img_to_string(B)) | ||||
| 
 | ||||
|     def assert_img_equal_img_string(self, A, Bstring): | ||||
|         self.assertEqual(self.img_to_string(A), self.img_string_normalize(Bstring)) | ||||
| 
 | ||||
|     def test_str_to_img(self): | ||||
|         im = Image.open('Tests/images/morph_a.png') | ||||
|         self.assert_image_equal(self.A, im) | ||||
| 
 | ||||
|     def create_lut(self): | ||||
|         for op in ('corner', 'dilation4', 'dilation8', 'erosion4', 'erosion8', 'edge'): | ||||
|             lb = ImageMorph.LutBuilder(op_name=op) | ||||
|             lut = lb.build_lut(self) | ||||
|             with open('Tests/images/%s.lut' % op, 'wb') as f: | ||||
|                 f.write(lut) | ||||
| 
 | ||||
|     #create_lut() | ||||
|     def test_lut(self): | ||||
|         for op in ('corner', 'dilation4', 'dilation8', 'erosion4', 'erosion8', 'edge'): | ||||
|             lb = ImageMorph.LutBuilder(op_name=op) | ||||
|             lut = lb.build_lut() | ||||
|             with open('Tests/images/%s.lut' % op , 'rb') as f: | ||||
|                 self.assertEqual(lut, bytearray(f.read())) | ||||
| 
 | ||||
| 
 | ||||
|     # Test the named patterns | ||||
|     def test_erosion8(self): | ||||
|         # erosion8 | ||||
|         mop = ImageMorph.MorphOp(op_name='erosion8') | ||||
|         count,Aout = mop.apply(self.A) | ||||
|         self.assertEqual(count,8) | ||||
|         self.assert_img_equal_img_string(Aout, | ||||
|                                          """ | ||||
|                                          ....... | ||||
|                                          ....... | ||||
|                                          ....... | ||||
|                                          ...1... | ||||
|                                          ....... | ||||
|                                          ....... | ||||
|                                          ....... | ||||
|                                          """) | ||||
| 
 | ||||
|     def test_dialation8(self): | ||||
|         # dialation8 | ||||
|         mop = ImageMorph.MorphOp(op_name='dilation8') | ||||
|         count,Aout = mop.apply(self.A) | ||||
|         self.assertEqual(count,16) | ||||
|         self.assert_img_equal_img_string(Aout, | ||||
|                                          """ | ||||
|                                          ....... | ||||
|                                          .11111. | ||||
|                                          .11111. | ||||
|                                          .11111. | ||||
|                                          .11111. | ||||
|                                          .11111. | ||||
|                                          ....... | ||||
|                                          """) | ||||
| 
 | ||||
|     def test_erosion4(self): | ||||
|         # erosion4 | ||||
|         mop = ImageMorph.MorphOp(op_name='dilation4') | ||||
|         count,Aout = mop.apply(self.A) | ||||
|         self.assertEqual(count,12) | ||||
|         self.assert_img_equal_img_string(Aout, | ||||
|                                          """ | ||||
|                                          ....... | ||||
|                                          ..111.. | ||||
|                                          .11111. | ||||
|                                          .11111. | ||||
|                                          .11111. | ||||
|                                          ..111.. | ||||
|                                          ....... | ||||
|                                          """) | ||||
| 
 | ||||
|     def test_edge(self): | ||||
|         # edge  | ||||
|         mop = ImageMorph.MorphOp(op_name='edge') | ||||
|         count,Aout = mop.apply(self.A) | ||||
|         self.assertEqual(count,1) | ||||
|         self.assert_img_equal_img_string(Aout, | ||||
|                                          """ | ||||
|                                          ....... | ||||
|                                          ....... | ||||
|                                          ..111.. | ||||
|                                          ..1.1.. | ||||
|                                          ..111.. | ||||
|                                          ....... | ||||
|                                          ....... | ||||
|                                          """) | ||||
| 
 | ||||
| 
 | ||||
|     def test_corner(self): | ||||
|         # Create a corner detector pattern | ||||
|         mop = ImageMorph.MorphOp(patterns = ['1:(... ... ...)->0', | ||||
|                                              '4:(00. 01. ...)->1']) | ||||
|         count,Aout = mop.apply(self.A) | ||||
|         self.assertEqual(count,5) | ||||
|         self.assert_img_equal_img_string(Aout, | ||||
|                                          """ | ||||
|                                          ....... | ||||
|                                          ....... | ||||
|                                          ..1.1.. | ||||
|                                          ....... | ||||
|                                          ..1.1.. | ||||
|                                          ....... | ||||
|                                          ....... | ||||
|                                          """) | ||||
|          | ||||
| 
 | ||||
|         # Test the coordinate counting with the same operator | ||||
|         coords = mop.match(self.A) | ||||
|         self.assertEqual(len(coords), 4) | ||||
|         self.assertEqual(tuple(coords), | ||||
|                      ((2,2),(4,2),(2,4),(4,4))) | ||||
| 
 | ||||
|         coords = mop.get_on_pixels(Aout) | ||||
|         self.assertEqual(len(coords), 4) | ||||
|         self.assertEqual(tuple(coords), | ||||
|                      ((2,2),(4,2),(2,4),(4,4))) | ||||
|  | @ -4,7 +4,7 @@ from PIL import Image | |||
| from PIL import ImageOps | ||||
| from PIL import ImageFilter | ||||
| 
 | ||||
| im = Image.open("Images/lena.ppm") | ||||
| im = Image.open("Tests/images/lena.ppm") | ||||
| 
 | ||||
| 
 | ||||
| class TestImageOpsUsm(PillowTestCase): | ||||
|  |  | |||
|  | @ -19,7 +19,7 @@ import locale | |||
| 
 | ||||
| # one of string.whitespace is not freely convertable into ascii. | ||||
| 
 | ||||
| path = "Images/lena.jpg" | ||||
| path = "Tests/images/lena.jpg" | ||||
| 
 | ||||
| 
 | ||||
| class TestLocale(PillowTestCase): | ||||
|  |  | |||
|  | @ -6,7 +6,7 @@ from PIL import Image | |||
| class TestPickle(PillowTestCase): | ||||
| 
 | ||||
|     def helper_pickle_file(self, pickle, protocol=0): | ||||
|         im = Image.open('Images/lena.jpg') | ||||
|         im = Image.open('Tests/images/lena.jpg') | ||||
|         filename = self.tempfile('temp.pkl') | ||||
| 
 | ||||
|         # Act | ||||
|  | @ -19,7 +19,7 @@ class TestPickle(PillowTestCase): | |||
|         self.assertEqual(im, loaded_im) | ||||
| 
 | ||||
|     def helper_pickle_string( | ||||
|             self, pickle, protocol=0, file='Images/lena.jpg'): | ||||
|             self, pickle, protocol=0, file='Tests/images/lena.jpg'): | ||||
|         im = Image.open(file) | ||||
| 
 | ||||
|         # Act | ||||
|  |  | |||
|  | @ -215,7 +215,7 @@ def lena(mode="RGB", cache={}): | |||
|     im = cache.get(mode) | ||||
|     if im is None: | ||||
|         if mode == "RGB": | ||||
|             im = Image.open("Images/lena.ppm") | ||||
|             im = Image.open("Tests/images/lena.ppm") | ||||
|         elif mode == "F": | ||||
|             im = lena("L").convert(mode) | ||||
|         elif mode[:4] == "I;16": | ||||
|  |  | |||
|  | @ -9,7 +9,7 @@ try: | |||
| except: | ||||
|     format = "PNG" | ||||
| 
 | ||||
| im = Image.open("Images/lena.ppm") | ||||
| im = Image.open("Tests/images/lena.ppm") | ||||
| im.load() | ||||
| 
 | ||||
| queue = queue.Queue() | ||||
|  |  | |||
							
								
								
									
										292
									
								
								Tk/README.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,292 @@ | |||
| Using PIL With Tkinter | ||||
| ==================================================================== | ||||
| 
 | ||||
| Starting with 1.0 final (release candidate 2 and later, to be | ||||
| precise), PIL can attach itself to Tkinter in flight.  As a result, | ||||
| you no longer need to rebuild the Tkinter extension to be able to | ||||
| use PIL. | ||||
| 
 | ||||
| However, if you cannot get the this to work on your platform, you | ||||
| can do it in the old way: | ||||
| 
 | ||||
| Adding Tkinter support | ||||
| ---------------------- | ||||
| 
 | ||||
| 1. Compile Python's _tkinter.c with the WITH_APPINIT and WITH_PIL | ||||
|    flags set, and link it with tkImaging.c and tkappinit.c.  To | ||||
|    do this, copy the former to the Modules directory, and edit | ||||
|    the _tkinter line in Setup (or Setup.in) according to the | ||||
|    instructions in that file. | ||||
| 
 | ||||
|    NOTE: if you have an old Python version, the tkappinit.c | ||||
|    file is not included by default.  If this is the case, you | ||||
|    will have to add the following lines to tkappinit.c, after | ||||
|    the MOREBUTTONS stuff:: | ||||
| 
 | ||||
| 	{ | ||||
| 	    extern void TkImaging_Init(Tcl_Interp* interp); | ||||
| 	    TkImaging_Init(interp); | ||||
| 	} | ||||
| 
 | ||||
|    This registers a Tcl command called "PyImagingPhoto", which is | ||||
|    use to communicate between PIL and Tk's PhotoImage handler. | ||||
| 
 | ||||
|    You must also change the _tkinter line in Setup (or Setup.in) | ||||
|    to something like:: | ||||
| 
 | ||||
|     _tkinter _tkinter.c tkImaging.c tkappinit.c -DWITH_APPINIT | ||||
|     -I/usr/local/include -L/usr/local/lib -ltk8.0 -ltcl8.0 -lX11 | ||||
| 
 | ||||
| The Photoimage Booster Patch (for Windows 95/NT) | ||||
| ==================================================================== | ||||
| 
 | ||||
| This patch kit boosts performance for 16/24-bit displays.  The | ||||
| first patch is required on Tk 4.2 (where it fixes the problems for | ||||
| 16-bit displays) and later versions, with the exception for Tk 8.0b1 | ||||
| where Sun added something similar themselves, only to remove it in | ||||
| 8.0b2.  By installing both patches, Tk's PhotoImage handling becomes | ||||
| much faster on both 16-bit and 24-bit displays.  The patch has been | ||||
| tested with Tk 4.2 and 8.0. | ||||
| 
 | ||||
| Here's a benchmark, made with a sample program which loads two | ||||
| 512x512 greyscale PGM's, and two 512x512 colour PPM's, and displays | ||||
| each of them in a separate toplevel windows.  Tcl/Tk was compiled | ||||
| with Visual C 4.0, and run on a P100 under Win95.  Image load times | ||||
| are not included in the timings: | ||||
| 
 | ||||
| +----------------------+------------+-------------+----------------+ | ||||
| |                      | **8-bit**  |  **16-bit** |  **24-bit**    | | ||||
| +----------------------+------------+-------------+----------------+ | ||||
| | 1. original 4.2 code | 5.52 s     |  8.57 s     |  3.79 s        | | ||||
| +----------------------+------------+-------------+----------------+ | ||||
| | 2. booster patch     | 5.49 s     |  1.87 s     |  1.82 s        | | ||||
| +----------------------+------------+-------------+----------------+ | ||||
| |  speedup             | None       |  4.6x       |  2.1x          | | ||||
| +----------------------+------------+-------------+----------------+ | ||||
| 
 | ||||
| Here's the patches: | ||||
| 
 | ||||
| 1. For portability and speed, the best thing under Windows is to | ||||
| treat 16-bit displays as if they were 24-bit. The Windows device | ||||
| drivers take care of the rest. | ||||
| 
 | ||||
| .. Note:: | ||||
| 
 | ||||
|    If you have Tk 4.1 or Tk 8.0b1, you don't have to apply this | ||||
|    patch!  It only applies to Tk 4.2, Tk 8.0a[12] and Tk 8.0b2. | ||||
| 
 | ||||
| In ``win/tkWinImage.c``, change the following line in ``XCreateImage``:: | ||||
| 
 | ||||
|     imagePtr->bits_per_pixel = depth; | ||||
| 
 | ||||
| to:: | ||||
| 
 | ||||
|     /* ==================================================================== */ | ||||
|     /* The tk photo image booster patch -- patch section 1                  */ | ||||
|     /* ==================================================================== */ | ||||
| 
 | ||||
|         if (visual->class == TrueColor) | ||||
|         /* true colour is stored as 3 bytes: (blue, green, red) */ | ||||
|         imagePtr->bits_per_pixel = 24; | ||||
|         else | ||||
|         imagePtr->bits_per_pixel = depth; | ||||
| 
 | ||||
|     /* ==================================================================== */ | ||||
| 
 | ||||
| 
 | ||||
| 2. The DitherInstance implementation is not good.  It's especially | ||||
| bad on highend truecolour displays.  IMO, it should be rewritten from | ||||
| scratch (some other day...). | ||||
| 
 | ||||
| Anyway, the following band-aid makes the situation a little bit | ||||
| better under Windows.  This hack trades some marginal quality (no | ||||
| dithering on 16-bit displays) for a dramatic performance boost. | ||||
| Requires patch 1, unless you're using Tk 4.1 or Tk 8.0b1. | ||||
| 
 | ||||
| In generic/tkImgPhoto.c, add the #ifdef section to the DitherInstance | ||||
| function:: | ||||
| 
 | ||||
|     /* ==================================================================== */ | ||||
| 
 | ||||
|         for (; height > 0; height -= nLines) { | ||||
|         if (nLines > height) { | ||||
|             nLines = height; | ||||
|         } | ||||
|         dstLinePtr = (unsigned char *) imagePtr->data; | ||||
|         yEnd = yStart + nLines; | ||||
| 
 | ||||
|     /* ==================================================================== */ | ||||
|     /* The tk photo image booster patch -- patch section 2                  */ | ||||
|     /* ==================================================================== */ | ||||
| 
 | ||||
|     #ifdef __WIN32__ | ||||
|         if (colorPtr->visualInfo.class == TrueColor | ||||
|             && instancePtr->gamma == 1.0) { | ||||
|             /* Windows hicolor/truecolor booster */ | ||||
|             for (y = yStart; y < yEnd; ++y) { | ||||
|             destBytePtr = dstLinePtr; | ||||
|             srcPtr = srcLinePtr; | ||||
|             for (x = xStart; x < xEnd; ++x) { | ||||
|                 destBytePtr[0] = srcPtr[2]; | ||||
|                 destBytePtr[1] = srcPtr[1]; | ||||
|                 destBytePtr[2] = srcPtr[0]; | ||||
|                 destBytePtr += 3; srcPtr += 3; | ||||
|             } | ||||
|             srcLinePtr += lineLength; | ||||
|             dstLinePtr += bytesPerLine; | ||||
|             } | ||||
|         } else | ||||
|     #endif | ||||
| 
 | ||||
|     /* ==================================================================== */ | ||||
| 
 | ||||
|         for (y = yStart; y < yEnd; ++y) { | ||||
|             srcPtr = srcLinePtr; | ||||
|             errPtr = errLinePtr; | ||||
|             destBytePtr = dstLinePtr; | ||||
| 
 | ||||
| last updated: 97-07-03/fl | ||||
| 
 | ||||
| 
 | ||||
| The PIL Bitmap Booster Patch | ||||
| ==================================================================== | ||||
| 
 | ||||
| The pilbitmap booster patch greatly improves performance of the | ||||
| ImageTk.BitmapImage constructor.  Unfortunately, the design of Tk | ||||
| doesn't allow us to do this from the tkImaging interface module, so | ||||
| you have to patch the Tk sources. | ||||
| 
 | ||||
| Once installed, the ImageTk module will automatically detect this | ||||
| patch. | ||||
| 
 | ||||
| (Note: this patch has been tested with Tk 8.0 on Win32 only, but it | ||||
| should work just fine on other platforms as well). | ||||
| 
 | ||||
| 1. To the beginning of TkGetBitmapData (in generic/tkImgBmap.c), add | ||||
|    the following stuff:: | ||||
| 
 | ||||
|     /* ==================================================================== */ | ||||
| 
 | ||||
|         int width, height, numBytes, hotX, hotY; | ||||
|         char *p, *end, *expandedFileName; | ||||
|         ParseInfo pi; | ||||
|         char *data = NULL; | ||||
|         Tcl_DString buffer; | ||||
| 
 | ||||
|     /* ==================================================================== */ | ||||
|     /* The pilbitmap booster patch -- patch section                         */ | ||||
|     /* ==================================================================== */ | ||||
| 
 | ||||
|         char *PILGetBitmapData(); | ||||
| 
 | ||||
|         if (string) { | ||||
|             /* Is this a PIL bitmap reference? */ | ||||
|             data = PILGetBitmapData(string, widthPtr, heightPtr, hotXPtr, hotYPtr); | ||||
|             if (data) | ||||
|                 return data; | ||||
|         } | ||||
| 
 | ||||
|     /* ==================================================================== */ | ||||
| 
 | ||||
|         pi.string = string; | ||||
|         if (string == NULL) { | ||||
|             if (Tcl_IsSafe(interp)) { | ||||
| 
 | ||||
| 2. Append the following to the same file (you may wish to include | ||||
| Imaging.h instead of copying the struct declaration...):: | ||||
| 
 | ||||
|     /* ==================================================================== */ | ||||
|     /* The pilbitmap booster patch -- code section                          */ | ||||
|     /* ==================================================================== */ | ||||
| 
 | ||||
|     /* Imaging declaration boldly copied from Imaging.h (!) */ | ||||
| 
 | ||||
|     typedef struct ImagingInstance *Imaging; /* a.k.a. ImagingImage :-) */ | ||||
| 
 | ||||
|     typedef unsigned char UINT8; | ||||
|     typedef int INT32; | ||||
| 
 | ||||
|     struct ImagingInstance { | ||||
| 
 | ||||
|         /* Format */ | ||||
|         char mode[4+1];     /* Band names ("1", "L", "P", "RGB", "RGBA", "CMYK") */ | ||||
|         int type;           /* Always 0 in this version */ | ||||
|         int depth;          /* Always 8 in this version */ | ||||
|         int bands;          /* Number of bands (1, 3, or 4) */ | ||||
|         int xsize;          /* Image dimension. */ | ||||
|         int ysize; | ||||
| 
 | ||||
|         /* Colour palette (for "P" images only) */ | ||||
|         void* palette; | ||||
| 
 | ||||
|         /* Data pointers */ | ||||
|         UINT8 **image8;     /* Set for 8-bit image (pixelsize=1). */ | ||||
|         INT32 **image32;    /* Set for 32-bit image (pixelsize=4). */ | ||||
| 
 | ||||
|         /* Internals */ | ||||
|         char **image;       /* Actual raster data. */ | ||||
|         char *block;        /* Set if data is allocated in a single block. */ | ||||
| 
 | ||||
|         int pixelsize;      /* Size of a pixel, in bytes (1 or 4) */ | ||||
|         int linesize;       /* Size of a line, in bytes (xsize * pixelsize) */ | ||||
| 
 | ||||
|         /* Virtual methods */ | ||||
|         void (*im_delete)(Imaging *); | ||||
| 
 | ||||
|     }; | ||||
| 
 | ||||
|     /* The pilbitmap booster patch allows you to pass PIL images to the | ||||
|        Tk bitmap decoder.  Passing images this way is much more efficient | ||||
|        than using the "tobitmap" method. */ | ||||
| 
 | ||||
|     char * | ||||
|     PILGetBitmapData(string, widthPtr, heightPtr, hotXPtr, hotYPtr) | ||||
|         char *string; | ||||
|         int *widthPtr, *heightPtr; | ||||
|         int *hotXPtr, *hotYPtr; | ||||
|     { | ||||
|         char* data; | ||||
|         char* p; | ||||
|         int y; | ||||
|         Imaging im; | ||||
| 
 | ||||
|         if (strncmp(string, "PIL:", 4) != 0) | ||||
|             return NULL; | ||||
| 
 | ||||
|         im = (Imaging) atol(string + 4); | ||||
| 
 | ||||
|         if (strcmp(im->mode, "1") != 0 && strcmp(im->mode, "L") != 0) | ||||
|             return NULL; | ||||
| 
 | ||||
|         data = p = (char *) ckalloc((unsigned) ((im->xsize+7)/8) * im->ysize); | ||||
| 
 | ||||
|         for (y = 0; y < im->ysize; y++) { | ||||
|             char* in = im->image8[y]; | ||||
|             int i, m, b; | ||||
|             b = 0; m = 1; | ||||
|             for (i = 0; i < im->xsize; i++) { | ||||
|                 if (in[i] != 0) | ||||
|                     b |= m; | ||||
|                 m <<= 1; | ||||
|                 if (m == 256){ | ||||
|                     *p++ = b; | ||||
|                     b = 0; m = 1; | ||||
|                 } | ||||
|             } | ||||
|             if (m != 1) | ||||
|                 *p++ = b; | ||||
|         } | ||||
| 
 | ||||
|         *widthPtr = im->xsize; | ||||
|         *heightPtr = im->ysize; | ||||
|         *hotXPtr = -1; | ||||
|         *hotYPtr = -1; | ||||
| 
 | ||||
|         return data; | ||||
|     } | ||||
| 
 | ||||
|     /* ==================================================================== */ | ||||
| 
 | ||||
| 3. Recompile Tk and relink the _tkinter module (where necessary). | ||||
| 
 | ||||
| Last updated: 97-05-17/fl | ||||
							
								
								
									
										108
									
								
								Tk/booster.txt
									
									
									
									
									
								
							
							
						
						|  | @ -1,108 +0,0 @@ | |||
| ==================================================================== | ||||
| The Photoimage Booster Patch (for Windows 95/NT) | ||||
| ==================================================================== | ||||
| 
 | ||||
|   This patch kit boosts performance for 16/24-bit displays.  The | ||||
| first patch is required on Tk 4.2 (where it fixes the problems for | ||||
| 16-bit displays) and later versions, with the exception for Tk 8.0b1 | ||||
| where Sun added something similar themselves, only to remove it in | ||||
| 8.0b2.  By installing both patches, Tk's PhotoImage handling becomes | ||||
| much faster on both 16-bit and 24-bit displays.  The patch has been | ||||
| tested with Tk 4.2 and 8.0. | ||||
| 
 | ||||
|   Here's a benchmark, made with a sample program which loads two | ||||
| 512x512 greyscale PGM's, and two 512x512 colour PPM's, and displays | ||||
| each of them in a separate toplevel windows.  Tcl/Tk was compiled | ||||
| with Visual C 4.0, and run on a P100 under Win95.  Image load times | ||||
| are not included in the timings: | ||||
| 
 | ||||
| 			8-bit		16-bit		24-bit | ||||
| -------------------------------------------------------------------- | ||||
| 1. original 4.2 code	5.52 s		8.57 s		3.79 s | ||||
| 2. booster patch	5.49 s		1.87 s		1.82 s | ||||
| 
 | ||||
|    speedup		None		4.6x		2.1x | ||||
| 
 | ||||
| ==================================================================== | ||||
| 
 | ||||
| Here's the patches: | ||||
| 
 | ||||
| 1. For portability and speed, the best thing under Windows is to | ||||
| treat 16-bit displays as if they were 24-bit. The Windows device | ||||
| drivers take care of the rest. | ||||
| 
 | ||||
|    ---------------------------------------------------------------- | ||||
|    If you have Tk 4.1 or Tk 8.0b1, you don't have to apply this | ||||
|    patch!  It only applies to Tk 4.2, Tk 8.0a[12] and Tk 8.0b2. | ||||
|    ---------------------------------------------------------------- | ||||
| 
 | ||||
| In win/tkWinImage.c, change the following line in XCreateImage: | ||||
| 
 | ||||
|     imagePtr->bits_per_pixel = depth; | ||||
| 
 | ||||
| to | ||||
| 
 | ||||
| /* ==================================================================== */ | ||||
| /* The tk photo image booster patch -- patch section 1                  */ | ||||
| /* ==================================================================== */ | ||||
| 
 | ||||
|     if (visual->class == TrueColor) | ||||
| 	/* true colour is stored as 3 bytes: (blue, green, red) */ | ||||
| 	imagePtr->bits_per_pixel = 24; | ||||
|     else | ||||
| 	imagePtr->bits_per_pixel = depth; | ||||
| 
 | ||||
| /* ==================================================================== */ | ||||
| 
 | ||||
| 
 | ||||
| 2. The DitherInstance implementation is not good.  It's especially | ||||
| bad on highend truecolour displays.  IMO, it should be rewritten from | ||||
| scratch (some other day...). | ||||
| 
 | ||||
|   Anyway, the following band-aid makes the situation a little bit | ||||
| better under Windows.  This hack trades some marginal quality (no | ||||
| dithering on 16-bit displays) for a dramatic performance boost. | ||||
| Requires patch 1, unless you're using Tk 4.1 or Tk 8.0b1. | ||||
| 
 | ||||
| In generic/tkImgPhoto.c, add the #ifdef section to the DitherInstance | ||||
| function: | ||||
| 
 | ||||
|     for (; height > 0; height -= nLines) { | ||||
| 	if (nLines > height) { | ||||
| 	    nLines = height; | ||||
| 	} | ||||
| 	dstLinePtr = (unsigned char *) imagePtr->data; | ||||
| 	yEnd = yStart + nLines; | ||||
| 
 | ||||
| /* ==================================================================== */ | ||||
| /* The tk photo image booster patch -- patch section 2                  */ | ||||
| /* ==================================================================== */ | ||||
| 
 | ||||
| #ifdef __WIN32__ | ||||
| 	if (colorPtr->visualInfo.class == TrueColor | ||||
| 		&& instancePtr->gamma == 1.0) { | ||||
| 	    /* Windows hicolor/truecolor booster */ | ||||
| 	    for (y = yStart; y < yEnd; ++y) { | ||||
| 		destBytePtr = dstLinePtr; | ||||
| 		srcPtr = srcLinePtr; | ||||
| 		for (x = xStart; x < xEnd; ++x) { | ||||
| 		    destBytePtr[0] = srcPtr[2]; | ||||
| 		    destBytePtr[1] = srcPtr[1]; | ||||
| 		    destBytePtr[2] = srcPtr[0]; | ||||
| 		    destBytePtr += 3; srcPtr += 3; | ||||
| 		} | ||||
| 		srcLinePtr += lineLength; | ||||
| 		dstLinePtr += bytesPerLine; | ||||
| 	    } | ||||
| 	} else | ||||
| #endif | ||||
| 
 | ||||
| /* ==================================================================== */ | ||||
| 
 | ||||
| 	for (y = yStart; y < yEnd; ++y) { | ||||
| 	    srcPtr = srcLinePtr; | ||||
| 	    errPtr = errLinePtr; | ||||
| 	    destBytePtr = dstLinePtr; | ||||
| 
 | ||||
| ==================================================================== | ||||
| last updated: 97-07-03/fl | ||||
|  | @ -1,41 +0,0 @@ | |||
| ==================================================================== | ||||
| Using PIL With Tkinter | ||||
| ==================================================================== | ||||
| 
 | ||||
| Starting with 1.0 final (release candidate 2 and later, to be | ||||
| precise), PIL can attach itself to Tkinter in flight.  As a result, | ||||
| you no longer need to rebuild the Tkinter extension to be able to | ||||
| use PIL. | ||||
| 
 | ||||
| However, if you cannot get the this to work on your platform, you | ||||
| can do it in the old way: | ||||
| 
 | ||||
| * Adding Tkinter support | ||||
| 
 | ||||
| 1. Compile Python's _tkinter.c with the WITH_APPINIT and WITH_PIL | ||||
|    flags set, and link it with tkImaging.c and tkappinit.c.  To | ||||
|    do this, copy the former to the Modules directory, and edit | ||||
|    the _tkinter line in Setup (or Setup.in) according to the | ||||
|    instructions in that file. | ||||
| 
 | ||||
|    NOTE: if you have an old Python version, the tkappinit.c | ||||
|    file is not included by default.  If this is the case, you | ||||
|    will have to add the following lines to tkappinit.c, after | ||||
|    the MOREBUTTONS stuff: | ||||
| 
 | ||||
| 	{ | ||||
| 	    extern void TkImaging_Init(Tcl_Interp* interp); | ||||
| 	    TkImaging_Init(interp); | ||||
| 	} | ||||
| 
 | ||||
|    This registers a Tcl command called "PyImagingPhoto", which is | ||||
|    use to communicate between PIL and Tk's PhotoImage handler. | ||||
| 
 | ||||
|    You must also change the _tkinter line in Setup (or Setup.in) | ||||
|    to something like: | ||||
| 
 | ||||
|    _tkinter _tkinter.c tkImaging.c tkappinit.c -DWITH_APPINIT | ||||
| 	-I/usr/local/include -L/usr/local/lib -ltk8.0 -ltcl8.0 -lX11 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										149
									
								
								Tk/pilbitmap.txt
									
									
									
									
									
								
							
							
						
						|  | @ -1,149 +0,0 @@ | |||
| ==================================================================== | ||||
| The PIL Bitmap Booster Patch | ||||
| ==================================================================== | ||||
| 
 | ||||
| The pilbitmap booster patch greatly improves performance of the | ||||
| ImageTk.BitmapImage constructor.  Unfortunately, the design of Tk | ||||
| doesn't allow us to do this from the tkImaging interface module, so | ||||
| you have to patch the Tk sources. | ||||
| 
 | ||||
| Once installed, the ImageTk module will automatically detect this | ||||
| patch. | ||||
| 
 | ||||
| (Note: this patch has been tested with Tk 8.0 on Win32 only, but it | ||||
| should work just fine on other platforms as well). | ||||
| 
 | ||||
| 1. To the beginning of TkGetBitmapData (in generic/tkImgBmap.c), add | ||||
|    the following stuff: | ||||
| 
 | ||||
| ------------------------------------------------------------------------ | ||||
|     int width, height, numBytes, hotX, hotY; | ||||
|     char *p, *end, *expandedFileName; | ||||
|     ParseInfo pi; | ||||
|     char *data = NULL; | ||||
|     Tcl_DString buffer; | ||||
| 
 | ||||
| /* ==================================================================== */ | ||||
| /* The pilbitmap booster patch -- patch section                         */ | ||||
| /* ==================================================================== */ | ||||
| 
 | ||||
|     char *PILGetBitmapData(); | ||||
| 
 | ||||
|     if (string) { | ||||
|         /* Is this a PIL bitmap reference? */ | ||||
|         data = PILGetBitmapData(string, widthPtr, heightPtr, hotXPtr, hotYPtr); | ||||
|         if (data) | ||||
|             return data; | ||||
|     } | ||||
| 
 | ||||
| /* ==================================================================== */ | ||||
| 
 | ||||
|     pi.string = string; | ||||
|     if (string == NULL) { | ||||
|         if (Tcl_IsSafe(interp)) { | ||||
| ------------------------------------------------------------------------ | ||||
| 
 | ||||
| 
 | ||||
| 2. Append the following to the same file (you may wish to include | ||||
| Imaging.h instead of copying the struct declaration...) | ||||
| 
 | ||||
| ------------------------------------------------------------------------ | ||||
| 
 | ||||
| /* ==================================================================== */ | ||||
| /* The pilbitmap booster patch -- code section                          */ | ||||
| /* ==================================================================== */ | ||||
| 
 | ||||
| /* Imaging declaration boldly copied from Imaging.h (!) */ | ||||
| 
 | ||||
| typedef struct ImagingInstance *Imaging; /* a.k.a. ImagingImage :-) */ | ||||
| 
 | ||||
| typedef unsigned char UINT8; | ||||
| typedef int INT32; | ||||
| 
 | ||||
| struct ImagingInstance { | ||||
| 
 | ||||
|     /* Format */ | ||||
|     char mode[4+1];     /* Band names ("1", "L", "P", "RGB", "RGBA", "CMYK") */ | ||||
|     int type;           /* Always 0 in this version */ | ||||
|     int depth;          /* Always 8 in this version */ | ||||
|     int bands;          /* Number of bands (1, 3, or 4) */ | ||||
|     int xsize;          /* Image dimension. */ | ||||
|     int ysize; | ||||
| 
 | ||||
|     /* Colour palette (for "P" images only) */ | ||||
|     void* palette; | ||||
| 
 | ||||
|     /* Data pointers */ | ||||
|     UINT8 **image8;     /* Set for 8-bit image (pixelsize=1). */ | ||||
|     INT32 **image32;    /* Set for 32-bit image (pixelsize=4). */ | ||||
| 
 | ||||
|     /* Internals */ | ||||
|     char **image;       /* Actual raster data. */ | ||||
|     char *block;        /* Set if data is allocated in a single block. */ | ||||
| 
 | ||||
|     int pixelsize;      /* Size of a pixel, in bytes (1 or 4) */ | ||||
|     int linesize;       /* Size of a line, in bytes (xsize * pixelsize) */ | ||||
| 
 | ||||
|     /* Virtual methods */ | ||||
|     void (*im_delete)(Imaging *); | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| /* The pilbitmap booster patch allows you to pass PIL images to the | ||||
|    Tk bitmap decoder.  Passing images this way is much more efficient | ||||
|    than using the "tobitmap" method. */ | ||||
| 
 | ||||
| char * | ||||
| PILGetBitmapData(string, widthPtr, heightPtr, hotXPtr, hotYPtr) | ||||
|     char *string; | ||||
|     int *widthPtr, *heightPtr; | ||||
|     int *hotXPtr, *hotYPtr; | ||||
| { | ||||
|     char* data; | ||||
|     char* p; | ||||
|     int y; | ||||
|     Imaging im; | ||||
| 
 | ||||
|     if (strncmp(string, "PIL:", 4) != 0) | ||||
|         return NULL; | ||||
| 
 | ||||
|     im = (Imaging) atol(string + 4); | ||||
| 
 | ||||
|     if (strcmp(im->mode, "1") != 0 && strcmp(im->mode, "L") != 0) | ||||
|         return NULL; | ||||
| 
 | ||||
|     data = p = (char *) ckalloc((unsigned) ((im->xsize+7)/8) * im->ysize); | ||||
| 
 | ||||
|     for (y = 0; y < im->ysize; y++) { | ||||
|         char* in = im->image8[y]; | ||||
|         int i, m, b; | ||||
|         b = 0; m = 1; | ||||
|         for (i = 0; i < im->xsize; i++) { | ||||
|             if (in[i] != 0) | ||||
|                 b |= m; | ||||
|             m <<= 1; | ||||
|             if (m == 256){ | ||||
|                 *p++ = b; | ||||
|                 b = 0; m = 1; | ||||
|             } | ||||
|         } | ||||
|         if (m != 1) | ||||
|             *p++ = b; | ||||
|     } | ||||
| 
 | ||||
|     *widthPtr = im->xsize; | ||||
|     *heightPtr = im->ysize; | ||||
|     *hotXPtr = -1; | ||||
|     *hotYPtr = -1; | ||||
| 
 | ||||
|     return data; | ||||
| } | ||||
| 
 | ||||
| /* ==================================================================== */ | ||||
| 
 | ||||
| ------------------------------------------------------------------------ | ||||
| 
 | ||||
| 3. Recompile Tk and relink the _tkinter module (where necessary). | ||||
| 
 | ||||
| ==================================================================== | ||||
| Last updated: 97-05-17/fl | ||||
							
								
								
									
										303
									
								
								_imagingmorph.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,303 @@ | |||
| /*
 | ||||
|  * The Python Imaging Library | ||||
|  * | ||||
|  * A binary morphology add-on for the Python Imaging Library | ||||
|  * | ||||
|  * History: | ||||
|  *   2014-06-04 Initial version. | ||||
|  * | ||||
|  * Copyright (c) 2014 Dov Grobgeld <dov.grobgeld@gmail.com> | ||||
|  * | ||||
|  * See the README file for information on usage and redistribution. | ||||
|  */ | ||||
| 
 | ||||
| #include "Python.h" | ||||
| #include "Imaging.h" | ||||
| #include "py3.h" | ||||
| 
 | ||||
| #define LUT_SIZE (1<<9) | ||||
| 
 | ||||
| /* Apply a morphologic LUT to a binary image. Outputs a
 | ||||
|    a new binary image. | ||||
| 
 | ||||
|    Expected parameters: | ||||
| 
 | ||||
|       1. a LUT - a 512 byte size lookup table. | ||||
|       2. an input Imaging image id. | ||||
|       3. an output Imaging image id | ||||
| 
 | ||||
|    Returns number of changed pixels. | ||||
| */ | ||||
| static PyObject* | ||||
| apply(PyObject *self, PyObject* args) | ||||
| { | ||||
|     const char *lut; | ||||
|     PyObject *py_lut; | ||||
|     Py_ssize_t lut_len, i0, i1; | ||||
|     Imaging imgin, imgout; | ||||
|     int width, height; | ||||
|     int row_idx, col_idx; | ||||
|     UINT8 **inrows, **outrows; | ||||
|     int num_changed_pixels = 0; | ||||
| 
 | ||||
|     if (!PyArg_ParseTuple(args, "Onn", &py_lut, &i0, &i1)) { | ||||
|         PyErr_SetString(PyExc_RuntimeError, "Argument parsing problem"); | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     if (!PyBytes_Check(py_lut)) { | ||||
|         PyErr_SetString(PyExc_RuntimeError, "The morphology LUT is not a bytes object"); | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     lut_len = PyBytes_Size(py_lut); | ||||
| 
 | ||||
|     if (lut_len < LUT_SIZE) { | ||||
|         PyErr_SetString(PyExc_RuntimeError, "The morphology LUT has the wrong size"); | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     lut = PyBytes_AsString(py_lut); | ||||
| 
 | ||||
|     imgin = (Imaging) i0; | ||||
|     imgout = (Imaging) i1; | ||||
|     width = imgin->xsize; | ||||
|     height = imgin->ysize; | ||||
| 
 | ||||
|     if (imgin->type != IMAGING_TYPE_UINT8 && | ||||
|         imgin->bands != 1) { | ||||
|         PyErr_SetString(PyExc_RuntimeError, "Unsupported image type"); | ||||
|         return NULL; | ||||
|     } | ||||
|     if (imgout->type != IMAGING_TYPE_UINT8 && | ||||
|         imgout->bands != 1) { | ||||
|         PyErr_SetString(PyExc_RuntimeError, "Unsupported image type"); | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     inrows = imgin->image8; | ||||
|     outrows = imgout->image8; | ||||
| 
 | ||||
|     for (row_idx=0; row_idx < height; row_idx++) { | ||||
|         UINT8 *outrow = outrows[row_idx]; | ||||
|         UINT8 *inrow = inrows[row_idx]; | ||||
|         UINT8 *prow, *nrow; /* Previous and next row */ | ||||
| 
 | ||||
|         /* zero boundary conditions. TBD support other modes */ | ||||
|         outrow[0] = outrow[width-1] = 0; | ||||
|         if (row_idx==0 || row_idx == height-1) { | ||||
|             for(col_idx=0; col_idx<width; col_idx++) | ||||
|                 outrow[col_idx] = 0; | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
|         prow = inrows[row_idx-1]; | ||||
|         nrow = inrows[row_idx+1]; | ||||
| 
 | ||||
|         for (col_idx=1; col_idx<width-1; col_idx++) { | ||||
|             int cim = col_idx-1; | ||||
|             int cip = col_idx+1; | ||||
|             unsigned char b0 = prow[cim] &1; | ||||
|             unsigned char b1 = prow[col_idx]&1; | ||||
|             unsigned char b2 = prow[cip]&1; | ||||
| 
 | ||||
|             unsigned char b3 = inrow[cim]&1; | ||||
|             unsigned char b4 = inrow[col_idx]&1; | ||||
|             unsigned char b5 = inrow[cip]&1; | ||||
| 
 | ||||
|             unsigned char b6 = nrow[cim]&1; | ||||
|             unsigned char b7 = nrow[col_idx]&1; | ||||
|             unsigned char b8 = nrow[cip]&1; | ||||
| 
 | ||||
|             int lut_idx = (b0  | ||||
|                            |(b1 << 1) | ||||
|                            |(b2 << 2) | ||||
|                            |(b3 << 3) | ||||
|                            |(b4 << 4) | ||||
|                            |(b5 << 5) | ||||
|                            |(b6 << 6) | ||||
|                            |(b7 << 7) | ||||
|                            |(b8 << 8)); | ||||
|             outrow[col_idx] = 255*(lut[lut_idx]&1); | ||||
|             num_changed_pixels += ((b4&1)!=(outrow[col_idx]&1)); | ||||
|         } | ||||
|     } | ||||
|     return Py_BuildValue("i",num_changed_pixels); | ||||
| } | ||||
| 
 | ||||
| /* Match a morphologic LUT to a binary image and return a list
 | ||||
|    of the coordinates of all all matching pixels. | ||||
| 
 | ||||
|    Expected parameters: | ||||
| 
 | ||||
|       1. a LUT - a 512 byte size lookup table. | ||||
|       2. an input Imaging image id. | ||||
| 
 | ||||
|    Returns list of matching pixels. | ||||
| */ | ||||
| static PyObject* | ||||
| match(PyObject *self, PyObject* args) | ||||
| { | ||||
|     const char *lut; | ||||
|     PyObject *py_lut; | ||||
|     Py_ssize_t lut_len, i0; | ||||
|     Imaging imgin; | ||||
|     int width, height; | ||||
|     int row_idx, col_idx; | ||||
|     UINT8 **inrows; | ||||
|     PyObject *ret = PyList_New(0); | ||||
| 
 | ||||
|     if (!PyArg_ParseTuple(args, "On", &py_lut, &i0)) { | ||||
|         PyErr_SetString(PyExc_RuntimeError, "Argument parsing problem"); | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     if (!PyBytes_Check(py_lut)) { | ||||
|         PyErr_SetString(PyExc_RuntimeError, "The morphology LUT is not a bytes object"); | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     lut_len = PyBytes_Size(py_lut); | ||||
| 
 | ||||
|     if (lut_len < LUT_SIZE) { | ||||
|         PyErr_SetString(PyExc_RuntimeError, "The morphology LUT has the wrong size"); | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     lut = PyBytes_AsString(py_lut); | ||||
|     imgin = (Imaging) i0; | ||||
| 
 | ||||
|     if (imgin->type != IMAGING_TYPE_UINT8 && | ||||
|         imgin->bands != 1) { | ||||
|         PyErr_SetString(PyExc_RuntimeError, "Unsupported image type"); | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     inrows = imgin->image8; | ||||
|     width = imgin->xsize; | ||||
|     height = imgin->ysize; | ||||
| 
 | ||||
|     for (row_idx=1; row_idx < height-1; row_idx++) { | ||||
|         UINT8 *inrow = inrows[row_idx]; | ||||
|         UINT8 *prow, *nrow; | ||||
| 
 | ||||
|         prow = inrows[row_idx-1]; | ||||
|         nrow = inrows[row_idx+1]; | ||||
| 
 | ||||
|         for (col_idx=1; col_idx<width-1; col_idx++) { | ||||
|             int cim = col_idx-1; | ||||
|             int cip = col_idx+1; | ||||
|             unsigned char b0 = prow[cim] &1; | ||||
|             unsigned char b1 = prow[col_idx]&1; | ||||
|             unsigned char b2 = prow[cip]&1; | ||||
| 
 | ||||
|             unsigned char b3 = inrow[cim]&1; | ||||
|             unsigned char b4 = inrow[col_idx]&1; | ||||
|             unsigned char b5 = inrow[cip]&1; | ||||
| 
 | ||||
|             unsigned char b6 = nrow[cim]&1; | ||||
|             unsigned char b7 = nrow[col_idx]&1; | ||||
|             unsigned char b8 = nrow[cip]&1; | ||||
| 
 | ||||
|             int lut_idx = (b0  | ||||
|                            |(b1 << 1) | ||||
|                            |(b2 << 2) | ||||
|                            |(b3 << 3) | ||||
|                            |(b4 << 4) | ||||
|                            |(b5 << 5) | ||||
|                            |(b6 << 6) | ||||
|                            |(b7 << 7) | ||||
|                            |(b8 << 8)); | ||||
|             if (lut[lut_idx]) { | ||||
|                 PyObject *coordObj = Py_BuildValue("(nn)",col_idx,row_idx); | ||||
|                 PyList_Append(ret, coordObj); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| /* Return a list of the coordinates of all turned on pixels in an image.
 | ||||
|    May be used to extract features after a sequence of MorphOp's were applied. | ||||
|    This is faster than match as only 1x1 lookup is made. | ||||
| */ | ||||
| static PyObject* | ||||
| get_on_pixels(PyObject *self, PyObject* args) | ||||
| { | ||||
|     Py_ssize_t i0; | ||||
|     Imaging img; | ||||
|     UINT8 **rows; | ||||
|     int row_idx, col_idx; | ||||
|     int width, height; | ||||
|     PyObject *ret = PyList_New(0); | ||||
|    | ||||
|     if (!PyArg_ParseTuple(args, "n", &i0)) { | ||||
|         PyErr_SetString(PyExc_RuntimeError, "Argument parsing problem"); | ||||
| 
 | ||||
|         return NULL; | ||||
|     } | ||||
|     img = (Imaging) i0; | ||||
|     rows = img->image8; | ||||
|     width = img->xsize; | ||||
|     height = img->ysize; | ||||
|    | ||||
|     for (row_idx=0; row_idx < height; row_idx++) { | ||||
|         UINT8 *row = rows[row_idx]; | ||||
|         for (col_idx=0; col_idx<width; col_idx++) { | ||||
|             if (row[col_idx]) { | ||||
|                 PyObject *coordObj = Py_BuildValue("(nn)",col_idx,row_idx); | ||||
|                 PyList_Append(ret, coordObj); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static int | ||||
| setup_module(PyObject* m) | ||||
| { | ||||
|     PyObject* d = PyModule_GetDict(m); | ||||
| 
 | ||||
|     PyDict_SetItemString(d, "__version", PyUnicode_FromString("0.1")); | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| static PyMethodDef functions[] = { | ||||
|     /* Functions */ | ||||
|     {"apply", (PyCFunction)apply, 1}, | ||||
|     {"get_on_pixels", (PyCFunction)get_on_pixels, 1}, | ||||
|     {"match", (PyCFunction)match, 1}, | ||||
| }; | ||||
| 
 | ||||
| #if PY_VERSION_HEX >= 0x03000000 | ||||
| PyMODINIT_FUNC | ||||
| PyInit__imagingmorph(void) { | ||||
|     PyObject* m; | ||||
| 
 | ||||
|     static PyModuleDef module_def = { | ||||
|         PyModuleDef_HEAD_INIT, | ||||
|         "_imagingmorph",         /* m_name */ | ||||
|         "A module for doing image morphology",               /* m_doc */ | ||||
|         -1,                 /* m_size */ | ||||
|         functions,          /* m_methods */ | ||||
|     }; | ||||
| 
 | ||||
|     m = PyModule_Create(&module_def); | ||||
| 
 | ||||
|     if (setup_module(m) < 0) | ||||
|         return NULL; | ||||
| 
 | ||||
|     return m; | ||||
| } | ||||
| #else | ||||
| PyMODINIT_FUNC | ||||
| init_imagingmorph(void) | ||||
| { | ||||
|     PyObject* m = Py_InitModule("_imagingmorph", functions); | ||||
|     setup_module(m); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
							
								
								
									
										6
									
								
								decode.c
									
									
									
									
									
								
							
							
						
						|  | @ -797,8 +797,9 @@ PyImaging_Jpeg2KDecoderNew(PyObject* self, PyObject* args) | |||
|     int reduce = 0; | ||||
|     int layers = 0; | ||||
|     int fd = -1; | ||||
|     if (!PyArg_ParseTuple(args, "ss|iii", &mode, &format, | ||||
|                           &reduce, &layers, &fd)) | ||||
|     PY_LONG_LONG length = -1; | ||||
|     if (!PyArg_ParseTuple(args, "ss|iiiL", &mode, &format, | ||||
|                           &reduce, &layers, &fd, &length)) | ||||
|         return NULL; | ||||
| 
 | ||||
|     if (strcmp(format, "j2k") == 0) | ||||
|  | @ -821,6 +822,7 @@ PyImaging_Jpeg2KDecoderNew(PyObject* self, PyObject* args) | |||
|     context = (JPEG2KDECODESTATE *)decoder->state.context; | ||||
| 
 | ||||
|     context->fd = fd; | ||||
|     context->length = (off_t)length; | ||||
|     context->format = codec_format; | ||||
|     context->reduce = reduce; | ||||
|     context->layers = layers; | ||||
|  |  | |||
|  | @ -2,15 +2,16 @@ | |||
| # install openjpeg | ||||
| 
 | ||||
| 
 | ||||
| if [ ! -f openjpeg-2.0.0.tar.gz ]; then | ||||
|     wget 'https://openjpeg.googlecode.com/files/openjpeg-2.0.0.tar.gz'  | ||||
| if [ ! -f openjpeg-2.1.0.tar.gz ]; then | ||||
|     wget 'http://iweb.dl.sourceforge.net/project/openjpeg.mirror/2.1.0/openjpeg-2.1.0.tar.gz' | ||||
| 
 | ||||
| fi | ||||
| 
 | ||||
| rm -r openjpeg-2.0.0 | ||||
| tar -xvzf openjpeg-2.0.0.tar.gz | ||||
| rm -r openjpeg-2.1.0 | ||||
| tar -xvzf openjpeg-2.1.0.tar.gz | ||||
| 
 | ||||
| 
 | ||||
| pushd openjpeg-2.0.0  | ||||
| pushd openjpeg-2.1.0  | ||||
| 
 | ||||
| cmake -DCMAKE_INSTALL_PREFIX=/usr . && make && sudo make install | ||||
| 
 | ||||
|  |  | |||
|  | @ -73,7 +73,7 @@ Many of Pillow's features require external libraries: | |||
| 
 | ||||
| * **openjpeg** provides JPEG 2000 functionality. | ||||
| 
 | ||||
|   * Pillow has been tested with openjpeg **2.0.0**. | ||||
|   * Pillow has been tested with openjpeg **2.0.0** and **2.1.0**. | ||||
| 
 | ||||
| If the prerequisites are installed in the standard library locations for your | ||||
| machine (e.g. :file:`/usr` or :file:`/usr/local`), no additional configuration | ||||
|  |  | |||
|  | @ -8,7 +8,7 @@ | |||
|  * Copyright (c) 2014 by Alastair Houghton | ||||
|  */ | ||||
| 
 | ||||
| #include <openjpeg-2.0/openjpeg.h> | ||||
| #include <openjpeg.h> | ||||
| 
 | ||||
| /* -------------------------------------------------------------------- */ | ||||
| /* Decoder								*/ | ||||
|  | @ -20,6 +20,9 @@ typedef struct { | |||
|     /* File descriptor, if available; otherwise, -1 */ | ||||
|     int fd; | ||||
| 
 | ||||
|     /* Length of data, if available; otherwise, -1 */ | ||||
|     off_t length; | ||||
| 
 | ||||
|     /* Specify the desired format */ | ||||
|     OPJ_CODEC_FORMAT format; | ||||
| 
 | ||||
|  |  | |||
|  | @ -517,7 +517,21 @@ j2k_decode_entry(Imaging im, ImagingCodecState state, | |||
|     opj_stream_set_read_function(stream, j2k_read); | ||||
|     opj_stream_set_skip_function(stream, j2k_skip); | ||||
| 
 | ||||
|     /* OpenJPEG 2.0 doesn't have OPJ_VERSION_MAJOR */ | ||||
| #ifndef OPJ_VERSION_MAJOR | ||||
|     opj_stream_set_user_data(stream, decoder); | ||||
| #else | ||||
|     opj_stream_set_user_data(stream, decoder, NULL); | ||||
| 
 | ||||
|     /* Hack: if we don't know the length, the largest file we can
 | ||||
|        possibly support is 4GB.  We can't go larger than this, because | ||||
|        OpenJPEG truncates this value for the final box in the file, and | ||||
|        the box lengths in OpenJPEG are currently 32 bit. */ | ||||
|     if (context->length < 0) | ||||
|         opj_stream_set_user_data_length(stream, 0xffffffff); | ||||
|     else | ||||
|         opj_stream_set_user_data_length(stream, context->length); | ||||
| #endif | ||||
| 
 | ||||
|     /* Setup decompression context */ | ||||
|     context->error_msg = NULL; | ||||
|  |  | |||
|  | @ -259,7 +259,12 @@ j2k_encode_entry(Imaging im, ImagingCodecState state, | |||
|     opj_stream_set_skip_function(stream, j2k_skip); | ||||
|     opj_stream_set_seek_function(stream, j2k_seek); | ||||
| 
 | ||||
|     /* OpenJPEG 2.0 doesn't have OPJ_VERSION_MAJOR */ | ||||
| #ifndef OPJ_VERSION_MAJOR | ||||
|     opj_stream_set_user_data(stream, encoder); | ||||
| #else | ||||
|     opj_stream_set_user_data(stream, encoder, NULL); | ||||
| #endif | ||||
| 
 | ||||
|     /* Setup an opj_image */ | ||||
|     if (strcmp (im->mode, "L") == 0) { | ||||
|  |  | |||
|  | @ -13,11 +13,6 @@ | |||
| #include <tiff.h> | ||||
| #endif | ||||
| 
 | ||||
| #ifndef _UNISTD_H | ||||
| #include <unistd.h> | ||||
| #endif | ||||
| 
 | ||||
| 
 | ||||
| #ifndef min | ||||
| #define min(x,y) (( x > y ) ? y : x ) | ||||
| #define max(x,y) (( x < y ) ? y : x ) | ||||
|  | @ -43,11 +38,10 @@ extern int ImagingLibTiffEncodeInit(ImagingCodecState state, char *filename, int | |||
| extern int ImagingLibTiffSetField(ImagingCodecState state, ttag_t tag, ...); | ||||
| 
 | ||||
| 
 | ||||
| #if defined(_MSC_VER) && (_MSC_VER == 1310) | ||||
| /* VS2003/py2.4 can't use varargs. Skipping trace for now.*/ | ||||
| #define TRACE(args) | ||||
| #else | ||||
| 
 | ||||
| /* 
 | ||||
|    Trace debugging | ||||
|    legacy, don't enable for python 3.x, unicode issues.  | ||||
| */ | ||||
| 
 | ||||
| /*
 | ||||
| #define VA_ARGS(...)	__VA_ARGS__ | ||||
|  | @ -56,8 +50,5 @@ extern int ImagingLibTiffSetField(ImagingCodecState state, ttag_t tag, ...); | |||
| 
 | ||||
| #define TRACE(args) | ||||
| 
 | ||||
| #endif /* _MSC_VER */ | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
							
								
								
									
										10
									
								
								selftest.py
									
									
									
									
									
								
							
							
						
						|  | @ -49,13 +49,13 @@ def testimage(): | |||
| 
 | ||||
|     Or open existing files: | ||||
| 
 | ||||
|     >>> im = Image.open(os.path.join(ROOT, "Images/lena.gif")) | ||||
|     >>> im = Image.open(os.path.join(ROOT, "Tests/images/lena.gif")) | ||||
|     >>> _info(im) | ||||
|     ('GIF', 'P', (128, 128)) | ||||
|     >>> _info(Image.open(os.path.join(ROOT, "Images/lena.ppm"))) | ||||
|     >>> _info(Image.open(os.path.join(ROOT, "Tests/images/lena.ppm"))) | ||||
|     ('PPM', 'RGB', (128, 128)) | ||||
|     >>> try: | ||||
|     ...  _info(Image.open(os.path.join(ROOT, "Images/lena.jpg"))) | ||||
|     ...  _info(Image.open(os.path.join(ROOT, "Tests/images/lena.jpg"))) | ||||
|     ... except IOError as v: | ||||
|     ...  print(v) | ||||
|     ('JPEG', 'RGB', (128, 128)) | ||||
|  | @ -63,7 +63,7 @@ def testimage(): | |||
|     PIL doesn't actually load the image data until it's needed, | ||||
|     or you call the "load" method: | ||||
| 
 | ||||
|     >>> im = Image.open(os.path.join(ROOT, "Images/lena.ppm")) | ||||
|     >>> im = Image.open(os.path.join(ROOT, "Tests/images/lena.ppm")) | ||||
|     >>> print(im.im) # internal image attribute | ||||
|     None | ||||
|     >>> a = im.load() | ||||
|  | @ -73,7 +73,7 @@ def testimage(): | |||
|     You can apply many different operations on images.  Most | ||||
|     operations return a new image: | ||||
| 
 | ||||
|     >>> im = Image.open(os.path.join(ROOT, "Images/lena.ppm")) | ||||
|     >>> im = Image.open(os.path.join(ROOT, "Tests/images/lena.ppm")) | ||||
|     >>> _info(im.convert("L")) | ||||
|     (None, 'L', (128, 128)) | ||||
|     >>> _info(im.copy()) | ||||
|  |  | |||
							
								
								
									
										58
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						|  | @ -337,14 +337,23 @@ class pil_build_ext(build_ext): | |||
|         _add_directory(include_dirs, "/usr/include") | ||||
| 
 | ||||
|         # on Windows, look for the OpenJPEG libraries in the location that | ||||
|         # the official installed puts them | ||||
|         # the official installer puts them | ||||
|         if sys.platform == "win32": | ||||
|             _add_directory(library_dirs, | ||||
|                            os.path.join(os.environ.get("ProgramFiles", ""), | ||||
|                                         "OpenJPEG 2.0", "lib")) | ||||
|             _add_directory(include_dirs, | ||||
|                            os.path.join(os.environ.get("ProgramFiles", ""), | ||||
|                                         "OpenJPEG 2.0", "include")) | ||||
|             program_files = os.environ.get('ProgramFiles', '') | ||||
|             best_version = (0, 0) | ||||
|             best_path = None | ||||
|             for name in os.listdir(program_files): | ||||
|                 if name.startswith('OpenJPEG '): | ||||
|                     version = tuple([int(x) for x in name[9:].strip().split('.')]) | ||||
|                     if version > best_version: | ||||
|                         best_version = version | ||||
|                         best_path = os.path.join(program_files, name) | ||||
| 
 | ||||
|             if best_path: | ||||
|                 _add_directory(library_dirs, | ||||
|                                os.path.join(best_path, 'lib')) | ||||
|                 _add_directory(include_dirs, | ||||
|                                os.path.join(best_path, 'include')) | ||||
| 
 | ||||
|         # | ||||
|         # insert new dirs *before* default libs, to avoid conflicts | ||||
|  | @ -374,11 +383,30 @@ class pil_build_ext(build_ext): | |||
|                         _find_library_file(self, "libjpeg")): | ||||
|                     feature.jpeg = "libjpeg"  # alternative name | ||||
| 
 | ||||
|         feature.openjpeg_version = None | ||||
|         if feature.want('jpeg2000'): | ||||
|             if _find_include_file(self, "openjpeg-2.0/openjpeg.h"): | ||||
|                 if _find_library_file(self, "openjp2"): | ||||
|                     feature.jpeg2000 = "openjp2" | ||||
|             best_version = None | ||||
|             best_path = None | ||||
|              | ||||
|             # Find the best version | ||||
|             for directory in self.compiler.include_dirs: | ||||
|                 for name in os.listdir(directory): | ||||
|                     if name.startswith('openjpeg-') and \ | ||||
|                         os.path.isfile(os.path.join(directory, name, | ||||
|                                                     'openjpeg.h')): | ||||
|                         version = tuple([int(x) for x in name[9:].split('.')]) | ||||
|                         if best_version is None or version > best_version: | ||||
|                             best_version = version | ||||
|                             best_path = os.path.join(directory, name) | ||||
| 
 | ||||
|             if best_version and _find_library_file(self, 'openjp2'): | ||||
|                 # Add the directory to the include path so we can include | ||||
|                 # <openjpeg.h> rather than having to cope with the versioned | ||||
|                 # include path | ||||
|                 _add_directory(self.compiler.include_dirs, best_path, 0) | ||||
|                 feature.jpeg2000 = 'openjp2' | ||||
|                 feature.openjpeg_version = '.'.join([str(x) for x in best_version]) | ||||
|                  | ||||
|         if feature.want('tiff'): | ||||
|             if _find_library_file(self, "tiff"): | ||||
|                 feature.tiff = "tiff" | ||||
|  | @ -543,6 +571,9 @@ class pil_build_ext(build_ext): | |||
|         if os.path.isfile("_imagingmath.c"): | ||||
|             exts.append(Extension("PIL._imagingmath", ["_imagingmath.c"])) | ||||
| 
 | ||||
|         if os.path.isfile("_imagingmorph.c"): | ||||
|             exts.append(Extension("PIL._imagingmorph", ["_imagingmorph.c"])) | ||||
| 
 | ||||
|         self.extensions[:] = exts | ||||
| 
 | ||||
|         build_ext.build_extensions(self) | ||||
|  | @ -572,7 +603,7 @@ class pil_build_ext(build_ext): | |||
|         options = [ | ||||
|             (feature.tcl and feature.tk, "TKINTER"), | ||||
|             (feature.jpeg, "JPEG"), | ||||
|             (feature.jpeg2000, "OPENJPEG (JPEG2000)"), | ||||
|             (feature.jpeg2000, "OPENJPEG (JPEG2000)", feature.openjpeg_version), | ||||
|             (feature.zlib, "ZLIB (PNG/ZIP)"), | ||||
|             (feature.tiff, "LIBTIFF"), | ||||
|             (feature.freetype, "FREETYPE2"), | ||||
|  | @ -583,7 +614,10 @@ class pil_build_ext(build_ext): | |||
|         all = 1 | ||||
|         for option in options: | ||||
|             if option[0]: | ||||
|                 print("--- %s support available" % option[1]) | ||||
|                 version = '' | ||||
|                 if len(option) >= 3 and option[2]: | ||||
|                     version = ' (%s)' % option[2] | ||||
|                 print("--- %s support available%s" % (option[1], version)) | ||||
|             else: | ||||
|                 print("*** %s support not available" % option[1]) | ||||
|                 if option[1] == "TKINTER" and _tkinter: | ||||
|  |  | |||
							
								
								
									
										24
									
								
								test-installed.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						|  | @ -0,0 +1,24 @@ | |||
| #!/usr/bin/env python | ||||
| import nose | ||||
| import os | ||||
| import sys | ||||
| import glob | ||||
| 
 | ||||
| # monkey with the path, removing the local directory but adding the Tests/ directory | ||||
| # for helper.py and the other local imports there. | ||||
| 
 | ||||
| del(sys.path[0]) | ||||
| sys.path.insert(0, os.path.abspath('./Tests')) | ||||
| 
 | ||||
| # if there's no test selected (mostly) choose a working default. | ||||
| # Something is required, because if we import the tests from the local | ||||
| # directory, once again, we've got the non-installed PIL in the way | ||||
| if len(sys.argv) == 1: | ||||
|     sys.argv.extend(glob.glob('Tests/test*.py')) | ||||
| 
 | ||||
| # Make sure that nose doesn't muck with our paths.  | ||||
| if ('--no-path-adjustment' not in sys.argv) and ('-P' not in sys.argv): | ||||
|     sys.argv.insert(1, '--no-path-adjustment') | ||||
| 
 | ||||
| if __name__ == '__main__': | ||||
|     nose.main() | ||||