diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 000000000..bd93c4749 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,11 @@ +# .coveragerc to control coverage.py + +[report] +# Regexes for lines to exclude from consideration +exclude_lines = + # Have to re-enable the standard pragma: + pragma: no cover + + # Don't complain if non-runnable code isn't run: + if 0: + if __name__ == .__main__.: diff --git a/.travis.yml b/.travis.yml index 36dae5b7a..389051358 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,8 @@ python: install: - "sudo apt-get -qq install libfreetype6-dev liblcms2-dev python-qt4 ghostscript libffi-dev cmake" - "pip install cffi" - - "pip install coveralls" + - "pip install coveralls nose" + - if [ "$TRAVIS_PYTHON_VERSION" == "2.6" ]; then pip install unittest2; fi # webp - pushd depends && ./install_webp.sh && popd @@ -28,18 +29,18 @@ script: - python setup.py build_ext --inplace # Don't cover PyPy: it fails intermittently and is x5.8 slower (#640) - - if [ "$TRAVIS_PYTHON_VERSION" == "pypy" ]; then python selftest.py; fi - - if [ "$TRAVIS_PYTHON_VERSION" == "pypy" ]; then python Tests/run.py; fi + - if [ "$TRAVIS_PYTHON_VERSION" == "pypy" ]; then time python selftest.py; fi + - if [ "$TRAVIS_PYTHON_VERSION" == "pypy" ]; then time nosetests Tests/test_*.py; fi # Cover the others - - if [ "$TRAVIS_PYTHON_VERSION" != "pypy" ]; then coverage run --append --include=PIL/* selftest.py; fi - - if [ "$TRAVIS_PYTHON_VERSION" != "pypy" ]; then python Tests/run.py --coverage; fi + - if [ "$TRAVIS_PYTHON_VERSION" != "pypy" ]; then time coverage run --append --include=PIL/* selftest.py; fi + - if [ "$TRAVIS_PYTHON_VERSION" != "pypy" ]; then time coverage run --append --include=PIL/* -m nose Tests/test_*.py; fi after_success: - coverage report - coveralls - pip install pep8 pyflakes - - pep8 PIL/*.py - - pyflakes PIL/*.py - - pep8 Tests/*.py - - pyflakes Tests/*.py + - pep8 --statistics --count PIL/*.py + - pep8 --statistics --count Tests/*.py + - pyflakes PIL/*.py | tee >(wc -l) + - pyflakes Tests/*.py | tee >(wc -l) diff --git a/CHANGES.rst b/CHANGES.rst index b19ef359d..40d8ed5cd 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -3,33 +3,46 @@ Changelog (Pillow) 2.5.0 (unreleased) ------------------ + +- Use unittest for tests + [hugovk] + +- ImageCms fixes + [hugovk] + +- Added more ImageDraw tests + [hugovk] + +- Added tests for Spider files + [hugovk] + - Use libtiff to write any compressed tiff files [wiredfool] - + - Support for pickling Image objects [hugovk] - Fixed resolution handling for EPS thumbnails [eliempje] - + - Fixed rendering of some binary EPS files (Issue #302) - [eliempje] - + [eliempje] + - Rename variables not to use built-in function names [hugovk] - -- Ignore junk JPEG markers + +- Ignore junk JPEG markers [hugovk] - + - Change default interpolation for Image.thumbnail to Image.ANTIALIAS [hugovk] - + - Add tests and fixes for saving PDFs [hugovk] - + - Remove transparency resource after P->RGBA conversion [hugovk] - + - Clean up preprocessor cruft for Windows [CounterPillow] @@ -39,13 +52,13 @@ Changelog (Pillow) - Added Image.close, context manager support. [wiredfool] -- Added support for 16 bit PGM files. +- Added support for 16 bit PGM files. [wiredfool] - Updated OleFileIO to version 0.30 from upstream [hugovk] -- Added support for additional TIFF floating point format +- Added support for additional TIFF floating point format [Hijackal] - Have the tempfile use a suffix with a dot @@ -75,7 +88,7 @@ Changelog (Pillow) - Added support for JPEG 2000 [al45tair] -- Add more detailed error messages to Image.py +- Add more detailed error messages to Image.py [larsmans] - Avoid conflicting _expand functions in PIL & MINGW, fixes #538 @@ -103,7 +116,7 @@ Changelog (Pillow) [wiredfool] - Fixed palette handling when converting from mode P->RGB->P - [d_schmidt] + [d_schmidt] - Fixed saving mode P image as a PNG with transparency = palette color 0 [d-schmidt] @@ -113,7 +126,7 @@ Changelog (Pillow) - Fixed DOS with invalid palette size or invalid image size in BMP file [wiredfool] - + - Added support for BMP version 4 and 5 [eddwardo, wiredfool] @@ -146,7 +159,7 @@ Changelog (Pillow) - Prefer homebrew freetype over X11 freetype (but still allow both) [dmckeone] - + 2.3.1 (2014-03-14) ------------------ @@ -271,7 +284,7 @@ Changelog (Pillow) [nikmolnar] - Fix for encoding of b_whitespace, similar to closed issue #272 - [mhogg] + [mhogg] - Fix #273: Add numpy array interface support for 16 and 32 bit integer modes [cgohlke] @@ -431,7 +444,7 @@ Changelog (Pillow) - Add Python 3 support. (Pillow >= 2.0.0 supports Python 2.6, 2.7, 3.2, 3.3. Pillow < 2.0.0 supports Python 2.4, 2.5, 2.6, 2.7.) [fluggo] -- Add PyPy support (experimental, please see: https://github.com/python-imaging/Pillow/issues/67) +- Add PyPy support (experimental, please see: https://github.com/python-pillow/Pillow/issues/67) - Add WebP support. [lqs] diff --git a/PIL/Image.py b/PIL/Image.py index 887ceabc1..e064ed9ef 100644 --- a/PIL/Image.py +++ b/PIL/Image.py @@ -1529,7 +1529,7 @@ class Image: clockwise around its centre. :param angle: In degrees counter clockwise. - :param filter: An optional resampling filter. This can be + :param resample: An optional resampling filter. This can be one of :py:attr:`PIL.Image.NEAREST` (use nearest neighbour), :py:attr:`PIL.Image.BILINEAR` (linear interpolation in a 2x2 environment), or :py:attr:`PIL.Image.BICUBIC` @@ -1550,7 +1550,6 @@ class Image: math.cos(angle), math.sin(angle), 0.0, -math.sin(angle), math.cos(angle), 0.0 ] - def transform(x, y, matrix=matrix): (a, b, c, d, e, f) = matrix diff --git a/PIL/ImageCms.py b/PIL/ImageCms.py index 363650250..fc176952e 100644 --- a/PIL/ImageCms.py +++ b/PIL/ImageCms.py @@ -1,19 +1,19 @@ -# -# The Python Imaging Library. -# $Id$ -# -# optional color managment support, based on Kevin Cazabon's PyCMS -# library. -# -# History: -# 2009-03-08 fl Added to PIL. -# -# Copyright (C) 2002-2003 Kevin Cazabon -# Copyright (c) 2009 by Fredrik Lundh -# -# See the README file for information on usage and redistribution. See -# below for the original description. -# +""" +The Python Imaging Library. +$Id$ + +Optional color managment support, based on Kevin Cazabon's PyCMS +library. + +History: +2009-03-08 fl Added to PIL. + +Copyright (C) 2002-2003 Kevin Cazabon +Copyright (c) 2009 by Fredrik Lundh + +See the README file for information on usage and redistribution. See +below for the original description. +""" from __future__ import print_function @@ -66,7 +66,8 @@ pyCMS Added try/except statements arount type() checks of potential CObjects... Python won't let you use type() - on them, and raises a TypeError (stupid, if you ask me!) + on them, and raises a TypeError (stupid, if you ask + me!) Added buildProofTransformFromOpenProfiles() function. Additional fixes in DLL, see DLL code for details. @@ -88,9 +89,9 @@ try: from PIL import _imagingcms except ImportError as ex: # Allow error import for doc purposes, but error out when accessing - # anything in core. - from _util import deferred_error - _imagingcms = deferred_error(ex) + # anything in core. + from _util import import_err + _imagingcms = import_err(ex) from PIL._util import isStringType core = _imagingcms @@ -113,22 +114,24 @@ DIRECTION_PROOF = 2 FLAGS = { "MATRIXINPUT": 1, "MATRIXOUTPUT": 2, - "MATRIXONLY": (1|2), - "NOWHITEONWHITEFIXUP": 4, # Don't hot fix scum dot - "NOPRELINEARIZATION": 16, # Don't create prelinearization tables on precalculated transforms (internal use) - "GUESSDEVICECLASS": 32, # Guess device class (for transform2devicelink) - "NOTCACHE": 64, # Inhibit 1-pixel cache + "MATRIXONLY": (1 | 2), + "NOWHITEONWHITEFIXUP": 4, # Don't hot fix scum dot + # Don't create prelinearization tables on precalculated transforms + # (internal use): + "NOPRELINEARIZATION": 16, + "GUESSDEVICECLASS": 32, # Guess device class (for transform2devicelink) + "NOTCACHE": 64, # Inhibit 1-pixel cache "NOTPRECALC": 256, - "NULLTRANSFORM": 512, # Don't transform anyway - "HIGHRESPRECALC": 1024, # Use more memory to give better accurancy - "LOWRESPRECALC": 2048, # Use less memory to minimize resouces + "NULLTRANSFORM": 512, # Don't transform anyway + "HIGHRESPRECALC": 1024, # Use more memory to give better accurancy + "LOWRESPRECALC": 2048, # Use less memory to minimize resouces "WHITEBLACKCOMPENSATION": 8192, "BLACKPOINTCOMPENSATION": 8192, - "GAMUTCHECK": 4096, # Out of Gamut alarm - "SOFTPROOFING": 16384, # Do softproofing - "PRESERVEBLACK": 32768, # Black preservation - "NODEFAULTRESOURCEDEF": 16777216, # CRD special - "GRIDPOINTS": lambda n: ((n) & 0xFF) << 16 # Gridpoints + "GAMUTCHECK": 4096, # Out of Gamut alarm + "SOFTPROOFING": 16384, # Do softproofing + "PRESERVEBLACK": 32768, # Black preservation + "NODEFAULTRESOURCEDEF": 16777216, # CRD special + "GRIDPOINTS": lambda n: ((n) & 0xFF) << 16 # Gridpoints } _MAX_FLAG = 0 @@ -136,6 +139,7 @@ for flag in FLAGS.values(): if isinstance(flag, int): _MAX_FLAG = _MAX_FLAG | flag + # --------------------------------------------------------------------. # Experimental PIL-level API # --------------------------------------------------------------------. @@ -153,40 +157,42 @@ class ImageCmsProfile: elif hasattr(profile, "read"): self._set(core.profile_frombytes(profile.read())) else: - self._set(profile) # assume it's already a profile + self._set(profile) # assume it's already a profile def _set(self, profile, filename=None): self.profile = profile self.filename = filename if profile: - self.product_name = None #profile.product_name - self.product_info = None #profile.product_info + self.product_name = None # profile.product_name + self.product_info = None # profile.product_info else: self.product_name = None self.product_info = None + class ImageCmsTransform(Image.ImagePointHandler): + """Transform. This can be used with the procedural API, or with the standard Image.point() method. """ def __init__(self, input, output, input_mode, output_mode, - intent=INTENT_PERCEPTUAL, - proof=None, proof_intent=INTENT_ABSOLUTE_COLORIMETRIC, flags=0): + intent=INTENT_PERCEPTUAL, proof=None, + proof_intent=INTENT_ABSOLUTE_COLORIMETRIC, flags=0): if proof is None: self.transform = core.buildTransform( input.profile, output.profile, input_mode, output_mode, intent, flags - ) + ) else: self.transform = core.buildProofTransform( input.profile, output.profile, proof.profile, input_mode, output_mode, intent, proof_intent, flags - ) + ) # Note: inputMode and outputMode are for pyCMS compatibility only self.input_mode = self.inputMode = input_mode self.output_mode = self.outputMode = output_mode @@ -198,21 +204,22 @@ class ImageCmsTransform(Image.ImagePointHandler): im.load() if imOut is None: imOut = Image.new(self.output_mode, im.size, None) - result = self.transform.apply(im.im.id, imOut.im.id) + self.transform.apply(im.im.id, imOut.im.id) return imOut def apply_in_place(self, im): im.load() if im.mode != self.output_mode: - raise ValueError("mode mismatch") # wrong output mode - result = self.transform.apply(im.im.id, im.im.id) + raise ValueError("mode mismatch") # wrong output mode + self.transform.apply(im.im.id, im.im.id) return im + def get_display_profile(handle=None): """ (experimental) Fetches the profile for the current display device. :returns: None if the profile is not known. """ - + import sys if sys.platform == "win32": from PIL import ImageWin @@ -229,15 +236,21 @@ def get_display_profile(handle=None): profile = get() return ImageCmsProfile(profile) + # --------------------------------------------------------------------. # pyCMS compatible layer # --------------------------------------------------------------------. class PyCMSError(Exception): - """ (pyCMS) Exception class. This is used for all errors in the pyCMS API. """ + + """ (pyCMS) Exception class. + This is used for all errors in the pyCMS API. """ pass -def profileToProfile(im, inputProfile, outputProfile, renderingIntent=INTENT_PERCEPTUAL, outputMode=None, inPlace=0, flags=0): + +def profileToProfile( + im, inputProfile, outputProfile, renderingIntent=INTENT_PERCEPTUAL, + outputMode=None, inPlace=0, flags=0): """ (pyCMS) Applies an ICC transformation to a given image, mapping from inputProfile to outputProfile. @@ -259,40 +272,45 @@ def profileToProfile(im, inputProfile, outputProfile, renderingIntent=INTENT_PER profiles, the input profile must handle RGB data, and the output profile must handle CMYK data. - :param im: An open PIL image object (i.e. Image.new(...) or Image.open(...), etc.) - :param inputProfile: String, as a valid filename path to the ICC input profile - you wish to use for this image, or a profile object + :param im: An open PIL image object (i.e. Image.new(...) or + Image.open(...), etc.) + :param inputProfile: String, as a valid filename path to the ICC input + profile you wish to use for this image, or a profile object :param outputProfile: String, as a valid filename path to the ICC output profile you wish to use for this image, or a profile object - :param renderingIntent: Integer (0-3) specifying the rendering intent you wish - to use for the transform + :param renderingIntent: Integer (0-3) specifying the rendering intent you + wish to use for the transform INTENT_PERCEPTUAL = 0 (DEFAULT) (ImageCms.INTENT_PERCEPTUAL) INTENT_RELATIVE_COLORIMETRIC = 1 (ImageCms.INTENT_RELATIVE_COLORIMETRIC) INTENT_SATURATION = 2 (ImageCms.INTENT_SATURATION) INTENT_ABSOLUTE_COLORIMETRIC = 3 (ImageCms.INTENT_ABSOLUTE_COLORIMETRIC) - see the pyCMS documentation for details on rendering intents and what they do. - :param outputMode: A valid PIL mode for the output image (i.e. "RGB", "CMYK", - etc.). Note: if rendering the image "inPlace", outputMode MUST be the - same mode as the input, or omitted completely. If omitted, the outputMode - will be the same as the mode of the input image (im.mode) - :param inPlace: Boolean (1 = True, None or 0 = False). If True, the original - image is modified in-place, and None is returned. If False (default), a - new Image object is returned with the transform applied. + see the pyCMS documentation for details on rendering intents and what + they do. + :param outputMode: A valid PIL mode for the output image (i.e. "RGB", + "CMYK", etc.). Note: if rendering the image "inPlace", outputMode + MUST be the same mode as the input, or omitted completely. If + omitted, the outputMode will be the same as the mode of the input + image (im.mode) + :param inPlace: Boolean (1 = True, None or 0 = False). If True, the + original image is modified in-place, and None is returned. If False + (default), a new Image object is returned with the transform applied. :param flags: Integer (0-...) specifying additional flags - :returns: Either None or a new PIL image object, depending on value of inPlace + :returns: Either None or a new PIL image object, depending on value of + inPlace :exception PyCMSError: """ if outputMode is None: outputMode = im.mode - if not isinstance(renderingIntent, int) or not (0 <= renderingIntent <=3): + if not isinstance(renderingIntent, int) or not (0 <= renderingIntent <= 3): raise PyCMSError("renderingIntent must be an integer between 0 and 3") if not isinstance(flags, int) or not (0 <= flags <= _MAX_FLAG): - raise PyCMSError("flags must be an integer between 0 and %s" + _MAX_FLAG) + raise PyCMSError( + "flags must be an integer between 0 and %s" + _MAX_FLAG) try: if not isinstance(inputProfile, ImageCmsProfile): @@ -300,8 +318,9 @@ def profileToProfile(im, inputProfile, outputProfile, renderingIntent=INTENT_PER if not isinstance(outputProfile, ImageCmsProfile): outputProfile = ImageCmsProfile(outputProfile) transform = ImageCmsTransform( - inputProfile, outputProfile, im.mode, outputMode, renderingIntent, flags=flags - ) + inputProfile, outputProfile, im.mode, outputMode, + renderingIntent, flags=flags + ) if inPlace: transform.apply_in_place(im) imOut = None @@ -323,8 +342,8 @@ def getOpenProfile(profileFilename): If profileFilename is not a vaild filename for an ICC profile, a PyCMSError will be raised. - :param profileFilename: String, as a valid filename path to the ICC profile you - wish to open, or a file-like object. + :param profileFilename: String, as a valid filename path to the ICC profile + you wish to open, or a file-like object. :returns: A CmsProfile class object. :exception PyCMSError: """ @@ -334,7 +353,10 @@ def getOpenProfile(profileFilename): except (IOError, TypeError, ValueError) as v: raise PyCMSError(v) -def buildTransform(inputProfile, outputProfile, inMode, outMode, renderingIntent=INTENT_PERCEPTUAL, flags=0): + +def buildTransform( + inputProfile, outputProfile, inMode, outMode, + renderingIntent=INTENT_PERCEPTUAL, flags=0): """ (pyCMS) Builds an ICC transform mapping from the inputProfile to the outputProfile. Use applyTransform to apply the transform to a given @@ -367,14 +389,14 @@ def buildTransform(inputProfile, outputProfile, inMode, outMode, renderingIntent manually overridden if you really want to, but I don't know of any time that would be of use, or would even work). - :param inputProfile: String, as a valid filename path to the ICC input profile - you wish to use for this transform, or a profile object + :param inputProfile: String, as a valid filename path to the ICC input + profile you wish to use for this transform, or a profile object :param outputProfile: String, as a valid filename path to the ICC output profile you wish to use for this transform, or a profile object - :param inMode: String, as a valid PIL mode that the appropriate profile also - supports (i.e. "RGB", "RGBA", "CMYK", etc.) - :param outMode: String, as a valid PIL mode that the appropriate profile also - supports (i.e. "RGB", "RGBA", "CMYK", etc.) + :param inMode: String, as a valid PIL mode that the appropriate profile + also supports (i.e. "RGB", "RGBA", "CMYK", etc.) + :param outMode: String, as a valid PIL mode that the appropriate profile + also supports (i.e. "RGB", "RGBA", "CMYK", etc.) :param renderingIntent: Integer (0-3) specifying the rendering intent you wish to use for the transform @@ -383,28 +405,37 @@ def buildTransform(inputProfile, outputProfile, inMode, outMode, renderingIntent INTENT_SATURATION = 2 (ImageCms.INTENT_SATURATION) INTENT_ABSOLUTE_COLORIMETRIC = 3 (ImageCms.INTENT_ABSOLUTE_COLORIMETRIC) - see the pyCMS documentation for details on rendering intents and what they do. + see the pyCMS documentation for details on rendering intents and what + they do. :param flags: Integer (0-...) specifying additional flags :returns: A CmsTransform class object. :exception PyCMSError: """ - if not isinstance(renderingIntent, int) or not (0 <= renderingIntent <=3): + if not isinstance(renderingIntent, int) or not (0 <= renderingIntent <= 3): raise PyCMSError("renderingIntent must be an integer between 0 and 3") if not isinstance(flags, int) or not (0 <= flags <= _MAX_FLAG): - raise PyCMSError("flags must be an integer between 0 and %s" + _MAX_FLAG) + raise PyCMSError( + "flags must be an integer between 0 and %s" + _MAX_FLAG) try: if not isinstance(inputProfile, ImageCmsProfile): inputProfile = ImageCmsProfile(inputProfile) if not isinstance(outputProfile, ImageCmsProfile): outputProfile = ImageCmsProfile(outputProfile) - return ImageCmsTransform(inputProfile, outputProfile, inMode, outMode, renderingIntent, flags=flags) + return ImageCmsTransform( + inputProfile, outputProfile, inMode, outMode, + renderingIntent, flags=flags) except (IOError, TypeError, ValueError) as v: raise PyCMSError(v) -def buildProofTransform(inputProfile, outputProfile, proofProfile, inMode, outMode, renderingIntent=INTENT_PERCEPTUAL, proofRenderingIntent=INTENT_ABSOLUTE_COLORIMETRIC, flags=FLAGS["SOFTPROOFING"]): + +def buildProofTransform( + inputProfile, outputProfile, proofProfile, inMode, outMode, + renderingIntent=INTENT_PERCEPTUAL, + proofRenderingIntent=INTENT_ABSOLUTE_COLORIMETRIC, + flags=FLAGS["SOFTPROOFING"]): """ (pyCMS) Builds an ICC transform mapping from the inputProfile to the outputProfile, but tries to simulate the result that would be @@ -443,17 +474,17 @@ def buildProofTransform(inputProfile, outputProfile, proofProfile, inMode, outMo when the simulated device has a much wider gamut than the output device, you may obtain marginal results. - :param inputProfile: String, as a valid filename path to the ICC input profile - you wish to use for this transform, or a profile object + :param inputProfile: String, as a valid filename path to the ICC input + profile you wish to use for this transform, or a profile object :param outputProfile: String, as a valid filename path to the ICC output (monitor, usually) profile you wish to use for this transform, or a profile object - :param proofProfile: String, as a valid filename path to the ICC proof profile - you wish to use for this transform, or a profile object - :param inMode: String, as a valid PIL mode that the appropriate profile also - supports (i.e. "RGB", "RGBA", "CMYK", etc.) - :param outMode: String, as a valid PIL mode that the appropriate profile also - supports (i.e. "RGB", "RGBA", "CMYK", etc.) + :param proofProfile: String, as a valid filename path to the ICC proof + profile you wish to use for this transform, or a profile object + :param inMode: String, as a valid PIL mode that the appropriate profile + also supports (i.e. "RGB", "RGBA", "CMYK", etc.) + :param outMode: String, as a valid PIL mode that the appropriate profile + also supports (i.e. "RGB", "RGBA", "CMYK", etc.) :param renderingIntent: Integer (0-3) specifying the rendering intent you wish to use for the input->proof (simulated) transform @@ -462,7 +493,8 @@ def buildProofTransform(inputProfile, outputProfile, proofProfile, inMode, outMo INTENT_SATURATION = 2 (ImageCms.INTENT_SATURATION) INTENT_ABSOLUTE_COLORIMETRIC = 3 (ImageCms.INTENT_ABSOLUTE_COLORIMETRIC) - see the pyCMS documentation for details on rendering intents and what they do. + see the pyCMS documentation for details on rendering intents and what + they do. :param proofRenderingIntent: Integer (0-3) specifying the rendering intent you wish to use for proof->output transform @@ -471,17 +503,19 @@ def buildProofTransform(inputProfile, outputProfile, proofProfile, inMode, outMo INTENT_SATURATION = 2 (ImageCms.INTENT_SATURATION) INTENT_ABSOLUTE_COLORIMETRIC = 3 (ImageCms.INTENT_ABSOLUTE_COLORIMETRIC) - see the pyCMS documentation for details on rendering intents and what they do. + see the pyCMS documentation for details on rendering intents and what + they do. :param flags: Integer (0-...) specifying additional flags :returns: A CmsTransform class object. :exception PyCMSError: """ - - if not isinstance(renderingIntent, int) or not (0 <= renderingIntent <=3): + + if not isinstance(renderingIntent, int) or not (0 <= renderingIntent <= 3): raise PyCMSError("renderingIntent must be an integer between 0 and 3") if not isinstance(flags, int) or not (0 <= flags <= _MAX_FLAG): - raise PyCMSError("flags must be an integer between 0 and %s" + _MAX_FLAG) + raise PyCMSError( + "flags must be an integer between 0 and %s" + _MAX_FLAG) try: if not isinstance(inputProfile, ImageCmsProfile): @@ -490,13 +524,16 @@ def buildProofTransform(inputProfile, outputProfile, proofProfile, inMode, outMo outputProfile = ImageCmsProfile(outputProfile) if not isinstance(proofProfile, ImageCmsProfile): proofProfile = ImageCmsProfile(proofProfile) - return ImageCmsTransform(inputProfile, outputProfile, inMode, outMode, renderingIntent, proofProfile, proofRenderingIntent, flags) + return ImageCmsTransform( + inputProfile, outputProfile, inMode, outMode, renderingIntent, + proofProfile, proofRenderingIntent, flags) except (IOError, TypeError, ValueError) as v: raise PyCMSError(v) buildTransformFromOpenProfiles = buildTransform buildProofTransformFromOpenProfiles = buildProofTransform + def applyTransform(im, transform, inPlace=0): """ (pyCMS) Applies a transform to a given image. @@ -514,8 +551,8 @@ def applyTransform(im, transform, inPlace=0): is raised. This function applies a pre-calculated transform (from - ImageCms.buildTransform() or ImageCms.buildTransformFromOpenProfiles()) to an - image. The transform can be used for multiple images, saving + ImageCms.buildTransform() or ImageCms.buildTransformFromOpenProfiles()) + to an image. The transform can be used for multiple images, saving considerable calcuation time if doing the same conversion multiple times. If you want to modify im in-place instead of receiving a new image as @@ -528,10 +565,12 @@ def applyTransform(im, transform, inPlace=0): :param im: A PIL Image object, and im.mode must be the same as the inMode supported by the transform. :param transform: A valid CmsTransform class object - :param inPlace: Bool (1 == True, 0 or None == False). If True, im is modified - in place and None is returned, if False, a new Image object with the - transform applied is returned (and im is not changed). The default is False. - :returns: Either None, or a new PIL Image object, depending on the value of inPlace + :param inPlace: Bool (1 == True, 0 or None == False). If True, im is + modified in place and None is returned, if False, a new Image object + with the transform applied is returned (and im is not changed). The + default is False. + :returns: Either None, or a new PIL Image object, depending on the value of + inPlace :exception PyCMSError: """ @@ -546,6 +585,7 @@ def applyTransform(im, transform, inPlace=0): return imOut + def createProfile(colorSpace, colorTemp=-1): """ (pyCMS) Creates a profile. @@ -562,30 +602,36 @@ def createProfile(colorSpace, colorTemp=-1): ImageCms.buildTransformFromOpenProfiles() to create a transform to apply to images. - :param colorSpace: String, the color space of the profile you wish to create. + :param colorSpace: String, the color space of the profile you wish to + create. Currently only "LAB", "XYZ", and "sRGB" are supported. :param colorTemp: Positive integer for the white point for the profile, in degrees Kelvin (i.e. 5000, 6500, 9600, etc.). The default is for D50 - illuminant if omitted (5000k). colorTemp is ONLY applied to LAB profiles, - and is ignored for XYZ and sRGB. + illuminant if omitted (5000k). colorTemp is ONLY applied to LAB + profiles, and is ignored for XYZ and sRGB. :returns: A CmsProfile class object :exception PyCMSError: """ if colorSpace not in ["LAB", "XYZ", "sRGB"]: - raise PyCMSError("Color space not supported for on-the-fly profile creation (%s)" % colorSpace) + raise PyCMSError( + "Color space not supported for on-the-fly profile creation (%s)" + % colorSpace) if colorSpace == "LAB": try: colorTemp = float(colorTemp) except: - raise PyCMSError("Color temperature must be numeric, \"%s\" not valid" % colorTemp) + raise PyCMSError( + "Color temperature must be numeric, \"%s\" not valid" + % colorTemp) try: return core.createProfile(colorSpace, colorTemp) except (TypeError, ValueError) as v: raise PyCMSError(v) + def getProfileName(profile): """ @@ -600,10 +646,10 @@ def getProfileName(profile): profile was originally created. Sometimes this tag also contains additional information supplied by the creator. - :param profile: EITHER a valid CmsProfile object, OR a string of the filename - of an ICC profile. - :returns: A string containing the internal name of the profile as stored in an - ICC tag. + :param profile: EITHER a valid CmsProfile object, OR a string of the + filename of an ICC profile. + :returns: A string containing the internal name of the profile as stored + in an ICC tag. :exception PyCMSError: """ @@ -612,14 +658,14 @@ def getProfileName(profile): if not isinstance(profile, ImageCmsProfile): profile = ImageCmsProfile(profile) # do it in python, not c. - # // name was "%s - %s" (model, manufacturer) || Description , - # // but if the Model and Manufacturer were the same or the model + # // name was "%s - %s" (model, manufacturer) || Description , + # // but if the Model and Manufacturer were the same or the model # // was long, Just the model, in 1.x model = profile.profile.product_model manufacturer = profile.profile.product_manufacturer if not (model or manufacturer): - return profile.profile.product_description+"\n" + return profile.profile.product_description + "\n" if not manufacturer or len(model) > 30: return model + "\n" return "%s - %s\n" % (model, manufacturer) @@ -627,6 +673,7 @@ def getProfileName(profile): except (AttributeError, IOError, TypeError, ValueError) as v: raise PyCMSError(v) + def getProfileInfo(profile): """ (pyCMS) Gets the internal product information for the given profile. @@ -641,18 +688,19 @@ def getProfileInfo(profile): info tag. This often contains details about the profile, and how it was created, as supplied by the creator. - :param profile: EITHER a valid CmsProfile object, OR a string of the filename - of an ICC profile. - :returns: A string containing the internal profile information stored in an ICC - tag. + :param profile: EITHER a valid CmsProfile object, OR a string of the + filename of an ICC profile. + :returns: A string containing the internal profile information stored in + an ICC tag. :exception PyCMSError: """ - + try: if not isinstance(profile, ImageCmsProfile): profile = ImageCmsProfile(profile) # add an extra newline to preserve pyCMS compatibility - # Python, not C. the white point bits weren't working well, so skipping. + # Python, not C. the white point bits weren't working well, + # so skipping. # // info was description \r\n\r\n copyright \r\n\r\n K007 tag \r\n\r\n whitepoint description = profile.profile.product_description cpright = profile.profile.product_copyright @@ -660,7 +708,7 @@ def getProfileInfo(profile): for elt in (description, cpright): if elt: arr.append(elt) - return "\r\n\r\n".join(arr)+"\r\n\r\n" + return "\r\n\r\n".join(arr) + "\r\n\r\n" except (AttributeError, IOError, TypeError, ValueError) as v: raise PyCMSError(v) @@ -677,12 +725,12 @@ def getProfileCopyright(profile): is raised Use this function to obtain the information stored in the profile's - copyright tag. + copyright tag. - :param profile: EITHER a valid CmsProfile object, OR a string of the filename - of an ICC profile. - :returns: A string containing the internal profile information stored in an ICC - tag. + :param profile: EITHER a valid CmsProfile object, OR a string of the + filename of an ICC profile. + :returns: A string containing the internal profile information stored in + an ICC tag. :exception PyCMSError: """ try: @@ -693,6 +741,7 @@ def getProfileCopyright(profile): except (AttributeError, IOError, TypeError, ValueError) as v: raise PyCMSError(v) + def getProfileManufacturer(profile): """ (pyCMS) Gets the manufacturer for the given profile. @@ -700,16 +749,16 @@ def getProfileManufacturer(profile): If profile isn't a valid CmsProfile object or filename to a profile, a PyCMSError is raised. - If an error occurs while trying to obtain the manufacturer tag, a PyCMSError - is raised + If an error occurs while trying to obtain the manufacturer tag, a + PyCMSError is raised Use this function to obtain the information stored in the profile's - manufacturer tag. + manufacturer tag. - :param profile: EITHER a valid CmsProfile object, OR a string of the filename - of an ICC profile. - :returns: A string containing the internal profile information stored in an ICC - tag. + :param profile: EITHER a valid CmsProfile object, OR a string of the + filename of an ICC profile. + :returns: A string containing the internal profile information stored in + an ICC tag. :exception PyCMSError: """ try: @@ -720,23 +769,24 @@ def getProfileManufacturer(profile): except (AttributeError, IOError, TypeError, ValueError) as v: raise PyCMSError(v) + def getProfileModel(profile): """ (pyCMS) Gets the model for the given profile. - + If profile isn't a valid CmsProfile object or filename to a profile, a PyCMSError is raised. - + If an error occurs while trying to obtain the model tag, a PyCMSError is raised - + Use this function to obtain the information stored in the profile's - model tag. - - :param profile: EITHER a valid CmsProfile object, OR a string of the filename - of an ICC profile. - :returns: A string containing the internal profile information stored in an ICC - tag. + model tag. + + :param profile: EITHER a valid CmsProfile object, OR a string of the + filename of an ICC profile. + :returns: A string containing the internal profile information stored in + an ICC tag. :exception PyCMSError: """ @@ -748,6 +798,7 @@ def getProfileModel(profile): except (AttributeError, IOError, TypeError, ValueError) as v: raise PyCMSError(v) + def getProfileDescription(profile): """ (pyCMS) Gets the description for the given profile. @@ -759,12 +810,12 @@ def getProfileDescription(profile): is raised Use this function to obtain the information stored in the profile's - description tag. + description tag. - :param profile: EITHER a valid CmsProfile object, OR a string of the filename - of an ICC profile. - :returns: A string containing the internal profile information stored in an ICC - tag. + :param profile: EITHER a valid CmsProfile object, OR a string of the + filename of an ICC profile. + :returns: A string containing the internal profile information stored in an + ICC tag. :exception PyCMSError: """ @@ -793,16 +844,18 @@ def getDefaultIntent(profile): If you wish to use a different intent than returned, use ImageCms.isIntentSupported() to verify it will work first. - :param profile: EITHER a valid CmsProfile object, OR a string of the filename - of an ICC profile. - :returns: Integer 0-3 specifying the default rendering intent for this profile. + :param profile: EITHER a valid CmsProfile object, OR a string of the + filename of an ICC profile. + :returns: Integer 0-3 specifying the default rendering intent for this + profile. INTENT_PERCEPTUAL = 0 (DEFAULT) (ImageCms.INTENT_PERCEPTUAL) INTENT_RELATIVE_COLORIMETRIC = 1 (ImageCms.INTENT_RELATIVE_COLORIMETRIC) INTENT_SATURATION = 2 (ImageCms.INTENT_SATURATION) INTENT_ABSOLUTE_COLORIMETRIC = 3 (ImageCms.INTENT_ABSOLUTE_COLORIMETRIC) - see the pyCMS documentation for details on rendering intents and what they do. + see the pyCMS documentation for details on rendering intents and what + they do. :exception PyCMSError: """ @@ -813,6 +866,7 @@ def getDefaultIntent(profile): except (AttributeError, IOError, TypeError, ValueError) as v: raise PyCMSError(v) + def isIntentSupported(profile, intent, direction): """ (pyCMS) Checks if a given intent is supported. @@ -828,17 +882,18 @@ def isIntentSupported(profile, intent, direction): potential PyCMSError that will occur if they don't support the modes you select. - :param profile: EITHER a valid CmsProfile object, OR a string of the filename - of an ICC profile. - :param intent: Integer (0-3) specifying the rendering intent you wish to use - with this profile + :param profile: EITHER a valid CmsProfile object, OR a string of the + filename of an ICC profile. + :param intent: Integer (0-3) specifying the rendering intent you wish to + use with this profile INTENT_PERCEPTUAL = 0 (DEFAULT) (ImageCms.INTENT_PERCEPTUAL) INTENT_RELATIVE_COLORIMETRIC = 1 (ImageCms.INTENT_RELATIVE_COLORIMETRIC) INTENT_SATURATION = 2 (ImageCms.INTENT_SATURATION) INTENT_ABSOLUTE_COLORIMETRIC = 3 (ImageCms.INTENT_ABSOLUTE_COLORIMETRIC) - see the pyCMS documentation for details on rendering intents and what they do. + see the pyCMS documentation for details on rendering intents and what + they do. :param direction: Integer specifing if the profile is to be used for input, output, or proof @@ -862,15 +917,17 @@ def isIntentSupported(profile, intent, direction): except (AttributeError, IOError, TypeError, ValueError) as v: raise PyCMSError(v) + def versions(): """ (pyCMS) Fetches versions. """ - + import sys return ( - VERSION, core.littlecms_version, sys.version.split()[0], Image.VERSION - ) + VERSION, core.littlecms_version, + sys.version.split()[0], Image.VERSION + ) # -------------------------------------------------------------------- @@ -880,14 +937,16 @@ if __name__ == "__main__": from PIL import ImageCms print(__doc__) - for f in dir(pyCMS): - print("="*80) - print("%s" %f) - + for f in dir(ImageCms): + doc = None try: - exec ("doc = ImageCms.%s.__doc__" %(f)) + exec("doc = %s.__doc__" % (f)) if "pyCMS" in doc: # so we don't get the __doc__ string for imported modules + print("=" * 80) + print("%s" % f) print(doc) - except AttributeError: + except (AttributeError, TypeError): pass + +# End of file diff --git a/PIL/Jpeg2KImagePlugin.py b/PIL/Jpeg2KImagePlugin.py index f57f4a784..ee8fc46aa 100644 --- a/PIL/Jpeg2KImagePlugin.py +++ b/PIL/Jpeg2KImagePlugin.py @@ -15,20 +15,21 @@ __version__ = "0.1" -from PIL import Image, ImageFile, _binary +from PIL import Image, ImageFile import struct import os import io + def _parse_codestream(fp): """Parse the JPEG 2000 codestream to extract the size and component count from the SIZ marker segment, returning a PIL (size, mode) tuple.""" - + hdr = fp.read(2) lsiz = struct.unpack('>H', hdr)[0] siz = hdr + fp.read(lsiz - 2) lsiz, rsiz, xsiz, ysiz, xosiz, yosiz, xtsiz, ytsiz, \ - xtosiz, ytosiz, csiz \ + xtosiz, ytosiz, csiz \ = struct.unpack('>HHIIIIIIIIH', siz[:38]) ssiz = [None]*csiz xrsiz = [None]*csiz @@ -48,13 +49,14 @@ def _parse_codestream(fp): mode == 'RGBA' else: mode = None - + return (size, mode) + def _parse_jp2_header(fp): """Parse the JP2 header box to extract size, component count and color space information, returning a PIL (size, mode) tuple.""" - + # Find the JP2 header box header = None while True: @@ -76,7 +78,7 @@ def _parse_jp2_header(fp): size = None mode = None - + hio = io.BytesIO(header) while True: lbox, tbox = struct.unpack('>I4s', hio.read(8)) @@ -90,7 +92,7 @@ def _parse_jp2_header(fp): if tbox == b'ihdr': height, width, nc, bpc, c, unkc, ipr \ - = struct.unpack('>IIHBBBB', content) + = struct.unpack('>IIHBBBB', content) size = (width, height) if unkc: if nc == 1: @@ -112,13 +114,13 @@ def _parse_jp2_header(fp): elif nc == 4: mode = 'RGBA' break - elif cs == 17: # grayscale + elif cs == 17: # grayscale if nc == 1: mode = 'L' elif nc == 2: mode = 'LA' break - elif cs == 18: # sYCC + elif cs == 18: # sYCC if nc == 3: mode = 'RGB' elif nc == 4: @@ -127,6 +129,7 @@ def _parse_jp2_header(fp): return (size, mode) + ## # Image plugin for JPEG2000 images. @@ -141,16 +144,16 @@ class Jpeg2KImageFile(ImageFile.ImageFile): self.size, self.mode = _parse_codestream(self.fp) else: sig = sig + self.fp.read(8) - + if sig == b'\x00\x00\x00\x0cjP \x0d\x0a\x87\x0a': self.codec = "jp2" self.size, self.mode = _parse_jp2_header(self.fp) else: raise SyntaxError('not a JPEG 2000 file') - + if self.size is None or self.mode is None: raise SyntaxError('unable to determine size/mode') - + self.reduce = 0 self.layers = 0 @@ -177,13 +180,15 @@ class Jpeg2KImageFile(ImageFile.ImageFile): t = self.tile[0] t3 = (t[3][0], self.reduce, self.layers, t[3][3]) self.tile = [(t[0], (0, 0) + self.size, t[2], t3)] - + ImageFile.ImageFile.load(self) - + + def _accept(prefix): return (prefix[:4] == b'\xff\x4f\xff\x51' or prefix[:12] == b'\x00\x00\x00\x0cjP \x0d\x0a\x87\x0a') + # ------------------------------------------------------------ # Save support @@ -214,7 +219,7 @@ def _save(im, fp, filename): fd = fp.fileno() except: fd = -1 - + im.encoderconfig = ( offset, tile_offset, @@ -228,10 +233,10 @@ def _save(im, fp, filename): progression, cinema_mode, fd - ) - + ) + ImageFile._save(im, fp, [('jpeg2k', (0, 0)+im.size, 0, kind)]) - + # ------------------------------------------------------------ # Registry stuff diff --git a/PIL/OleFileIO-README.md b/PIL/OleFileIO-README.md index 4a4fdcbca..11a0e9053 100644 --- a/PIL/OleFileIO-README.md +++ b/PIL/OleFileIO-README.md @@ -7,7 +7,7 @@ This is an improved version of the OleFileIO module from [PIL](http://www.python As far as I know, this module is now the most complete and robust Python implementation to read MS OLE2 files, portable on several operating systems. (please tell me if you know other similar Python modules) -OleFileIO_PL can be used as an independent module or with PIL. The goal is to have it integrated into [Pillow](http://python-imaging.github.io/), the friendly fork of PIL. +OleFileIO_PL can be used as an independent module or with PIL. The goal is to have it integrated into [Pillow](http://python-pillow.github.io/), the friendly fork of PIL. OleFileIO\_PL is mostly meant for developers. If you are looking for tools to analyze OLE files or to extract data, then please also check [python-oletools](http://www.decalage.info/python/oletools), which are built upon OleFileIO_PL. @@ -348,4 +348,4 @@ By obtaining, using, and/or copying this software and/or its associated document Permission to use, copy, modify, and distribute this software and its associated documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appears in all copies, and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of Secret Labs AB or the author not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. -SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. \ No newline at end of file +SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/PIL/SpiderImagePlugin.py b/PIL/SpiderImagePlugin.py index cd97c524d..306b348bc 100644 --- a/PIL/SpiderImagePlugin.py +++ b/PIL/SpiderImagePlugin.py @@ -36,17 +36,23 @@ from __future__ import print_function from PIL import Image, ImageFile -import os, struct, sys +import os +import struct +import sys + def isInt(f): try: i = int(f) - if f-i == 0: return 1 - else: return 0 + if f-i == 0: + return 1 + else: + return 0 except: return 0 -iforms = [1,3,-11,-12,-21,-22] +iforms = [1, 3, -11, -12, -21, -22] + # There is no magic number to identify Spider files, so just check a # series of header locations to see if they have reasonable values. @@ -56,30 +62,32 @@ iforms = [1,3,-11,-12,-21,-22] def isSpiderHeader(t): h = (99,) + t # add 1 value so can use spider header index start=1 # header values 1,2,5,12,13,22,23 should be integers - for i in [1,2,5,12,13,22,23]: - if not isInt(h[i]): return 0 + for i in [1, 2, 5, 12, 13, 22, 23]: + if not isInt(h[i]): + return 0 # check iform iform = int(h[5]) - if not iform in iforms: return 0 + if iform not in iforms: + return 0 # check other header values labrec = int(h[13]) # no. records in file header labbyt = int(h[22]) # total no. of bytes in header lenbyt = int(h[23]) # record length in bytes - #print "labrec = %d, labbyt = %d, lenbyt = %d" % (labrec,labbyt,lenbyt) - if labbyt != (labrec * lenbyt): return 0 + # print "labrec = %d, labbyt = %d, lenbyt = %d" % (labrec,labbyt,lenbyt) + if labbyt != (labrec * lenbyt): + return 0 # looks like a valid header return labbyt + def isSpiderImage(filename): - fp = open(filename,'rb') + fp = open(filename, 'rb') f = fp.read(92) # read 23 * 4 bytes fp.close() - bigendian = 1 - t = struct.unpack('>23f',f) # try big-endian first + t = struct.unpack('>23f', f) # try big-endian first hdrlen = isSpiderHeader(t) if hdrlen == 0: - bigendian = 0 - t = struct.unpack('<23f',f) # little-endian + t = struct.unpack('<23f', f) # little-endian hdrlen = isSpiderHeader(t) return hdrlen @@ -96,11 +104,11 @@ class SpiderImageFile(ImageFile.ImageFile): try: self.bigendian = 1 - t = struct.unpack('>27f',f) # try big-endian first + t = struct.unpack('>27f', f) # try big-endian first hdrlen = isSpiderHeader(t) if hdrlen == 0: self.bigendian = 0 - t = struct.unpack('<27f',f) # little-endian + t = struct.unpack('<27f', f) # little-endian hdrlen = isSpiderHeader(t) if hdrlen == 0: raise SyntaxError("not a valid Spider file") @@ -112,7 +120,7 @@ class SpiderImageFile(ImageFile.ImageFile): if iform != 1: raise SyntaxError("not a Spider 2D image") - self.size = int(h[12]), int(h[2]) # size in pixels (width, height) + self.size = int(h[12]), int(h[2]) # size in pixels (width, height) self.istack = int(h[24]) self.imgnumber = int(h[27]) @@ -141,9 +149,10 @@ class SpiderImageFile(ImageFile.ImageFile): self.rawmode = "F;32F" self.mode = "F" - self.tile = [("raw", (0, 0) + self.size, offset, - (self.rawmode, 0, 1))] - self.__fp = self.fp # FIXME: hack + self.tile = [ + ("raw", (0, 0) + self.size, offset, + (self.rawmode, 0, 1))] + self.__fp = self.fp # FIXME: hack # 1st image index is zero (although SPIDER imgnumber starts at 1) def tell(self): @@ -176,6 +185,7 @@ class SpiderImageFile(ImageFile.ImageFile): from PIL import ImageTk return ImageTk.PhotoImage(self.convert2byte(), palette=256) + # -------------------------------------------------------------------- # Image series @@ -200,17 +210,19 @@ def loadImageSeries(filelist=None): imglist.append(im) return imglist + # -------------------------------------------------------------------- # For saving images in Spider format def makeSpiderHeader(im): - nsam,nrow = im.size + nsam, nrow = im.size lenbyt = nsam * 4 # There are labrec records in the header labrec = 1024 / lenbyt - if 1024%lenbyt != 0: labrec += 1 + if 1024 % lenbyt != 0: + labrec += 1 labbyt = labrec * lenbyt hdr = [] - nvalues = labbyt / 4 + nvalues = int(labbyt / 4) for i in range(nvalues): hdr.append(0.0) @@ -218,13 +230,13 @@ def makeSpiderHeader(im): return [] # NB these are Fortran indices - hdr[1] = 1.0 # nslice (=1 for an image) - hdr[2] = float(nrow) # number of rows per slice - hdr[5] = 1.0 # iform for 2D image - hdr[12] = float(nsam) # number of pixels per line - hdr[13] = float(labrec) # number of records in file header - hdr[22] = float(labbyt) # total number of bytes in header - hdr[23] = float(lenbyt) # record length in bytes + hdr[1] = 1.0 # nslice (=1 for an image) + hdr[2] = float(nrow) # number of rows per slice + hdr[5] = 1.0 # iform for 2D image + hdr[12] = float(nsam) # number of pixels per line + hdr[13] = float(labrec) # number of records in file header + hdr[22] = float(labbyt) # total number of bytes in header + hdr[23] = float(lenbyt) # record length in bytes # adjust for Fortran indexing hdr = hdr[1:] @@ -232,9 +244,10 @@ def makeSpiderHeader(im): # pack binary data into a string hdrstr = [] for v in hdr: - hdrstr.append(struct.pack('f',v)) + hdrstr.append(struct.pack('f', v)) return hdrstr + def _save(im, fp, filename): if im.mode[0] != "F": im = im.convert('F') @@ -250,11 +263,12 @@ def _save(im, fp, filename): raise IOError("Unable to open %s for writing" % filename) fp.writelines(hdr) - rawmode = "F;32NF" #32-bit native floating point - ImageFile._save(im, fp, [("raw", (0,0)+im.size, 0, (rawmode,0,1))]) + rawmode = "F;32NF" # 32-bit native floating point + ImageFile._save(im, fp, [("raw", (0, 0)+im.size, 0, (rawmode, 0, 1))]) fp.close() + def _save_spider(im, fp, filename): # get the filename extension and register it with Image fn, ext = os.path.splitext(filename) @@ -292,5 +306,7 @@ if __name__ == "__main__": if outfile != "": # perform some image operation im = im.transpose(Image.FLIP_LEFT_RIGHT) - print("saving a flipped version of %s as %s " % (os.path.basename(filename), outfile)) + print( + "saving a flipped version of %s as %s " % + (os.path.basename(filename), outfile)) im.save(outfile, "SPIDER") diff --git a/PIL/TiffImagePlugin.py b/PIL/TiffImagePlugin.py index 11b92747c..34cb020aa 100644 --- a/PIL/TiffImagePlugin.py +++ b/PIL/TiffImagePlugin.py @@ -54,7 +54,7 @@ import collections import itertools import os -# Set these to true to force use of libtiff for reading or writing. +# Set these to true to force use of libtiff for reading or writing. READ_LIBTIFF = False WRITE_LIBTIFF= False @@ -238,7 +238,7 @@ class ImageFileDirectory(collections.MutableMapping): Value: integer corresponding to the data type from `TiffTags.TYPES` - 'internal' + 'internal' * self.tags = {} Key: numerical tiff tag number Value: Decoded data, Generally a tuple. * If set from __setval__ -- always a tuple @@ -489,10 +489,10 @@ class ImageFileDirectory(collections.MutableMapping): if tag in self.tagtype: typ = self.tagtype[tag] - + if Image.DEBUG: print ("Tag %s, Type: %s, Value: %s" % (tag, typ, value)) - + if typ == 1: # byte data if isinstance(value, tuple): @@ -512,7 +512,7 @@ class ImageFileDirectory(collections.MutableMapping): # and doesn't match the tiff spec: 8-bit byte that # contains a 7-bit ASCII code; the last byte must be # NUL (binary zero). Also, I don't think this was well - # excersized before. + # excersized before. data = value = b"" + value.encode('ascii', 'replace') + b"\0" else: # integer data @@ -859,7 +859,7 @@ class TiffImageFile(ImageFile.ImageFile): # libtiff handles the fillmode for us, so 1;IR should # actually be 1;I. Including the R double reverses the # bits, so stripes of the image are reversed. See - # https://github.com/python-imaging/Pillow/issues/279 + # https://github.com/python-pillow/Pillow/issues/279 if fillorder == 2: key = ( self.tag.prefix, photo, format, 1, @@ -984,11 +984,11 @@ def _save(im, fp, filename): compression = im.encoderinfo.get('compression',im.info.get('compression','raw')) - libtiff = WRITE_LIBTIFF or compression != 'raw' + libtiff = WRITE_LIBTIFF or compression != 'raw' # required for color libtiff images ifd[PLANAR_CONFIGURATION] = getattr(im, '_planar_configuration', 1) - + # -- multi-page -- skip TIFF header on subsequent pages if not libtiff and fp.tell() == 0: # tiff header (write via IFD to get everything right) @@ -1025,7 +1025,7 @@ def _save(im, fp, filename): # which support profiles as TIFF) -- 2008-06-06 Florian Hoech if "icc_profile" in im.info: ifd[ICCPROFILE] = im.info["icc_profile"] - + if "description" in im.encoderinfo: ifd[IMAGEDESCRIPTION] = im.encoderinfo["description"] if "resolution" in im.encoderinfo: @@ -1091,7 +1091,7 @@ def _save(im, fp, filename): blocklist = [STRIPOFFSETS, STRIPBYTECOUNTS, ROWSPERSTRIP, ICCPROFILE] # ICC Profile crashes. atts={} - # bits per sample is a single short in the tiff directory, not a list. + # bits per sample is a single short in the tiff directory, not a list. atts[BITSPERSAMPLE] = bits[0] # Merge the ones that we have with (optional) more bits from # the original file, e.g x,y resolution so that we can diff --git a/README.rst b/README.rst index 277c5d01f..0831a6b81 100644 --- a/README.rst +++ b/README.rst @@ -5,8 +5,8 @@ Pillow Pillow is the "friendly" PIL fork by Alex Clark and Contributors. PIL is the Python Imaging Library by Fredrik Lundh and Contributors. -.. image:: https://travis-ci.org/python-imaging/Pillow.svg?branch=master - :target: https://travis-ci.org/python-imaging/Pillow +.. image:: https://travis-ci.org/python-pillow/Pillow.svg?branch=master + :target: https://travis-ci.org/python-pillow/Pillow :alt: Travis CI build status .. image:: https://pypip.in/v/Pillow/badge.png @@ -17,7 +17,7 @@ Pillow is the "friendly" PIL fork by Alex Clark and Contributors. PIL is the Pyt :target: https://pypi.python.org/pypi/Pillow/ :alt: Number of PyPI downloads -.. image:: https://coveralls.io/repos/python-imaging/Pillow/badge.png?branch=master - :target: https://coveralls.io/r/python-imaging/Pillow?branch=master +.. image:: https://coveralls.io/repos/python-pillow/Pillow/badge.png?branch=master + :target: https://coveralls.io/r/python-pillow/Pillow?branch=master The documentation is hosted at http://pillow.readthedocs.org/. It contains installation instructions, tutorials, reference, compatibility details, and more. diff --git a/Tests/helper.py b/Tests/helper.py new file mode 100644 index 000000000..c203e67c2 --- /dev/null +++ b/Tests/helper.py @@ -0,0 +1,341 @@ +""" +Helper functions. +""" +from __future__ import print_function +import sys + +if sys.version_info[:2] <= (2, 6): + import unittest2 as unittest +else: + import unittest + + +def tearDownModule(): + import glob + import os + import tempfile + temp_root = os.path.join(tempfile.gettempdir(), 'pillow-tests') + tempfiles = glob.glob(os.path.join(temp_root, "temp_*")) + if tempfiles: + print("===", "remaining temporary files") + for file in tempfiles: + print(file) + print("-"*68) + + +class PillowTestCase(unittest.TestCase): + + currentResult = None # holds last result object passed to run method + _tempfiles = [] + + def run(self, result=None): + self.addCleanup(self.delete_tempfiles) + self.currentResult = result # remember result for use later + unittest.TestCase.run(self, result) # call superclass run method + + def delete_tempfiles(self): + try: + ok = self.currentResult.wasSuccessful() + except AttributeError: # for nosetests + proxy = self.currentResult + ok = (len(proxy.errors) + len(proxy.failures) == 0) + + if ok: + # only clean out tempfiles if test passed + import os + import os.path + import tempfile + for file in self._tempfiles: + try: + os.remove(file) + except OSError: + pass # report? + temp_root = os.path.join(tempfile.gettempdir(), 'pillow-tests') + try: + os.rmdir(temp_root) + except OSError: + pass + + def assert_almost_equal(self, a, b, msg=None, eps=1e-6): + self.assertLess( + abs(a-b), eps, + msg or "got %r, expected %r" % (a, b)) + + def assert_deep_equal(self, a, b, msg=None): + try: + self.assertEqual( + len(a), len(b), + msg or "got length %s, expected %s" % (len(a), len(b))) + self.assertTrue( + all([x == y for x, y in zip(a, b)]), + msg or "got %s, expected %s" % (a, b)) + except: + self.assertEqual(a, b, msg) + + def assert_image(self, im, mode, size, msg=None): + if mode is not None: + self.assertEqual( + im.mode, mode, + msg or "got mode %r, expected %r" % (im.mode, mode)) + + if size is not None: + self.assertEqual( + im.size, size, + msg or "got size %r, expected %r" % (im.size, size)) + + def assert_image_equal(self, a, b, msg=None): + self.assertEqual( + a.mode, b.mode, + msg or "got mode %r, expected %r" % (a.mode, b.mode)) + self.assertEqual( + a.size, b.size, + msg or "got size %r, expected %r" % (a.size, b.size)) + self.assertEqual( + a.tobytes(), b.tobytes(), + msg or "got different content") + + def assert_image_similar(self, a, b, epsilon, msg=None): + epsilon = float(epsilon) + self.assertEqual( + a.mode, b.mode, + msg or "got mode %r, expected %r" % (a.mode, b.mode)) + self.assertEqual( + a.size, b.size, + msg or "got size %r, expected %r" % (a.size, b.size)) + + diff = 0 + try: + ord(b'0') + for abyte, bbyte in zip(a.tobytes(), b.tobytes()): + diff += abs(ord(abyte)-ord(bbyte)) + except: + for abyte, bbyte in zip(a.tobytes(), b.tobytes()): + diff += abs(abyte-bbyte) + ave_diff = float(diff)/(a.size[0]*a.size[1]) + self.assertGreaterEqual( + epsilon, ave_diff, + msg or "average pixel value difference %.4f > epsilon %.4f" % ( + ave_diff, epsilon)) + + def assert_warning(self, warn_class, func): + import warnings + + result = None + with warnings.catch_warnings(record=True) as w: + # Cause all warnings to always be triggered. + warnings.simplefilter("always") + + # Hopefully trigger a warning. + result = func() + + # Verify some things. + self.assertGreaterEqual(len(w), 1) + found = False + for v in w: + if issubclass(v.category, warn_class): + found = True + break + self.assertTrue(found) + return result + + def tempfile(self, template, *extra): + import os + import os.path + import sys + import tempfile + files = [] + root = os.path.join(tempfile.gettempdir(), 'pillow-tests') + try: + os.mkdir(root) + except OSError: + pass + for temp in (template,) + extra: + assert temp[:5] in ("temp.", "temp_") + name = os.path.basename(sys.argv[0]) + name = temp[:4] + os.path.splitext(name)[0][4:] + name = name + "_%d" % len(self._tempfiles) + temp[4:] + name = os.path.join(root, name) + files.append(name) + self._tempfiles.extend(files) + return files[0] + + +# # require that deprecation warnings are triggered +# import warnings +# warnings.simplefilter('default') +# # temporarily turn off resource warnings that warn about unclosed +# # files in the test scripts. +# try: +# warnings.filterwarnings("ignore", category=ResourceWarning) +# except NameError: +# # we expect a NameError on py2.x, since it doesn't have ResourceWarnings. +# pass + +import sys +py3 = (sys.version_info >= (3, 0)) + +# # some test helpers +# +# _target = None +# _tempfiles = [] +# _logfile = None +# +# +# def success(): +# import sys +# success.count += 1 +# if _logfile: +# print(sys.argv[0], success.count, failure.count, file=_logfile) +# return True +# +# +# def failure(msg=None, frame=None): +# import sys +# import linecache +# failure.count += 1 +# if _target: +# if frame is None: +# frame = sys._getframe() +# while frame.f_globals.get("__name__") != _target.__name__: +# frame = frame.f_back +# location = (frame.f_code.co_filename, frame.f_lineno) +# prefix = "%s:%d: " % location +# line = linecache.getline(*location) +# print(prefix + line.strip() + " failed:") +# if msg: +# print("- " + msg) +# if _logfile: +# print(sys.argv[0], success.count, failure.count, file=_logfile) +# return False +# +# success.count = failure.count = 0 +# + + +# helpers + +def fromstring(data): + from io import BytesIO + from PIL import Image + return Image.open(BytesIO(data)) + + +def tostring(im, format, **options): + from io import BytesIO + out = BytesIO() + im.save(out, format, **options) + return out.getvalue() + + +def lena(mode="RGB", cache={}): + from PIL import Image + im = None + # im = cache.get(mode) + if im is None: + if mode == "RGB": + im = Image.open("Images/lena.ppm") + elif mode == "F": + im = lena("L").convert(mode) + elif mode[:4] == "I;16": + im = lena("I").convert(mode) + else: + im = lena("RGB").convert(mode) + # cache[mode] = im + return im + + +# def assert_image_completely_equal(a, b, msg=None): +# if a != b: +# failure(msg or "images different") +# else: +# success() +# +# +# # test runner +# +# def run(): +# global _target, _tests, run +# import sys +# import traceback +# _target = sys.modules["__main__"] +# run = None # no need to run twice +# tests = [] +# for name, value in list(vars(_target).items()): +# if name[:5] == "test_" and type(value) is type(success): +# tests.append((value.__code__.co_firstlineno, name, value)) +# tests.sort() # sort by line +# for lineno, name, func in tests: +# try: +# _tests = [] +# func() +# for func, args in _tests: +# func(*args) +# except: +# t, v, tb = sys.exc_info() +# tb = tb.tb_next +# if tb: +# failure(frame=tb.tb_frame) +# traceback.print_exception(t, v, tb) +# else: +# print("%s:%d: cannot call test function: %s" % ( +# sys.argv[0], lineno, v)) +# failure.count += 1 +# +# +# def yield_test(function, *args): +# # collect delayed/generated tests +# _tests.append((function, args)) +# +# +# def skip(msg=None): +# import os +# print("skip") +# os._exit(0) # don't run exit handlers +# +# +# def ignore(pattern): +# """Tells the driver to ignore messages matching the pattern, for the +# duration of the current test.""" +# print('ignore: %s' % pattern) +# +# +# def _setup(): +# global _logfile +# +# import sys +# if "--coverage" in sys.argv: +# # Temporary: ignore PendingDeprecationWarning from Coverage (Py3.4) +# with warnings.catch_warnings(): +# warnings.simplefilter("ignore") +# import coverage +# cov = coverage.coverage(auto_data=True, include="PIL/*") +# cov.start() +# +# def report(): +# if run: +# run() +# if success.count and not failure.count: +# print("ok") +# # only clean out tempfiles if test passed +# import os +# import os.path +# import tempfile +# for file in _tempfiles: +# try: +# os.remove(file) +# except OSError: +# pass # report? +# temp_root = os.path.join(tempfile.gettempdir(), 'pillow-tests') +# try: +# os.rmdir(temp_root) +# except OSError: +# pass +# +# import atexit +# atexit.register(report) +# +# if "--log" in sys.argv: +# _logfile = open("test.log", "a") +# +# +# _setup() diff --git a/Tests/images/imagedraw_arc.png b/Tests/images/imagedraw_arc.png new file mode 100644 index 000000000..b09774389 Binary files /dev/null and b/Tests/images/imagedraw_arc.png differ diff --git a/Tests/images/imagedraw_bitmap.png b/Tests/images/imagedraw_bitmap.png new file mode 100644 index 000000000..05337b693 Binary files /dev/null and b/Tests/images/imagedraw_bitmap.png differ diff --git a/Tests/images/imagedraw_chord.png b/Tests/images/imagedraw_chord.png new file mode 100644 index 000000000..db3b35310 Binary files /dev/null and b/Tests/images/imagedraw_chord.png differ diff --git a/Tests/images/imagedraw_ellipse.png b/Tests/images/imagedraw_ellipse.png new file mode 100644 index 000000000..fb03fd148 Binary files /dev/null and b/Tests/images/imagedraw_ellipse.png differ diff --git a/Tests/images/imagedraw_floodfill.png b/Tests/images/imagedraw_floodfill.png new file mode 100644 index 000000000..89376a0f0 Binary files /dev/null and b/Tests/images/imagedraw_floodfill.png differ diff --git a/Tests/images/imagedraw_floodfill2.png b/Tests/images/imagedraw_floodfill2.png new file mode 100644 index 000000000..41b92fb75 Binary files /dev/null and b/Tests/images/imagedraw_floodfill2.png differ diff --git a/Tests/images/imagedraw_line.png b/Tests/images/imagedraw_line.png new file mode 100644 index 000000000..6d0e6994d Binary files /dev/null and b/Tests/images/imagedraw_line.png differ diff --git a/Tests/images/imagedraw_pieslice.png b/Tests/images/imagedraw_pieslice.png new file mode 100644 index 000000000..1b2acff92 Binary files /dev/null and b/Tests/images/imagedraw_pieslice.png differ diff --git a/Tests/images/imagedraw_point.png b/Tests/images/imagedraw_point.png new file mode 100644 index 000000000..ab7c1a322 Binary files /dev/null and b/Tests/images/imagedraw_point.png differ diff --git a/Tests/images/imagedraw_polygon.png b/Tests/images/imagedraw_polygon.png new file mode 100644 index 000000000..5f160be76 Binary files /dev/null and b/Tests/images/imagedraw_polygon.png differ diff --git a/Tests/images/imagedraw_rectangle.png b/Tests/images/imagedraw_rectangle.png new file mode 100644 index 000000000..782d84461 Binary files /dev/null and b/Tests/images/imagedraw_rectangle.png differ diff --git a/Tests/images/lena.spider b/Tests/images/lena.spider new file mode 100644 index 000000000..df963c1c3 Binary files /dev/null and b/Tests/images/lena.spider differ diff --git a/Tests/test_000_sanity.py b/Tests/test_000_sanity.py index a30786458..1ad76cc50 100644 --- a/Tests/test_000_sanity.py +++ b/Tests/test_000_sanity.py @@ -1,24 +1,32 @@ -from __future__ import print_function -from tester import * +from helper import unittest, PillowTestCase, tearDownModule import PIL import PIL.Image -# Make sure we have the binary extension -im = PIL.Image.core.new("L", (100, 100)) -assert PIL.Image.VERSION[:3] == '1.1' +class TestSanity(PillowTestCase): -# Create an image and do stuff with it. -im = PIL.Image.new("1", (100, 100)) -assert (im.mode, im.size) == ('1', (100, 100)) -assert len(im.tobytes()) == 1300 + def test_sanity(self): -# Create images in all remaining major modes. -im = PIL.Image.new("L", (100, 100)) -im = PIL.Image.new("P", (100, 100)) -im = PIL.Image.new("RGB", (100, 100)) -im = PIL.Image.new("I", (100, 100)) -im = PIL.Image.new("F", (100, 100)) + # Make sure we have the binary extension + im = PIL.Image.core.new("L", (100, 100)) -print("ok") + self.assertEqual(PIL.Image.VERSION[:3], '1.1') + + # Create an image and do stuff with it. + im = PIL.Image.new("1", (100, 100)) + self.assertEqual((im.mode, im.size), ('1', (100, 100))) + self.assertEqual(len(im.tobytes()), 1300) + + # Create images in all remaining major modes. + im = PIL.Image.new("L", (100, 100)) + im = PIL.Image.new("P", (100, 100)) + im = PIL.Image.new("RGB", (100, 100)) + im = PIL.Image.new("I", (100, 100)) + im = PIL.Image.new("F", (100, 100)) + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_001_archive.py b/Tests/test_001_archive.py deleted file mode 100644 index a914a6c4c..000000000 --- a/Tests/test_001_archive.py +++ /dev/null @@ -1,23 +0,0 @@ -import PIL -import PIL.Image - -import glob, os - -for file in glob.glob("../pil-archive/*"): - f, e = os.path.splitext(file) - if e in [".txt", ".ttf", ".otf", ".zip"]: - continue - try: - im = PIL.Image.open(file) - im.load() - except IOError as v: - print("-", "failed to open", file, "-", v) - else: - print("+", file, im.mode, im.size, im.format) - if e == ".exif": - try: - info = im._getexif() - except KeyError as v: - print("-", "failed to get exif info from", file, "-", v) - -print("ok") diff --git a/Tests/test_bmp_reference.py b/Tests/test_bmp_reference.py index 99818229f..c8d93983b 100644 --- a/Tests/test_bmp_reference.py +++ b/Tests/test_bmp_reference.py @@ -1,4 +1,4 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule from PIL import Image import os @@ -6,81 +6,89 @@ import os base = os.path.join('Tests', 'images', 'bmp') -def get_files(d, ext='.bmp'): - return [os.path.join(base,d,f) for f - in os.listdir(os.path.join(base, d)) if ext in f] +class TestBmpReference(PillowTestCase): -def test_bad(): - """ These shouldn't crash/dos, but they shouldn't return anything either """ - for f in get_files('b'): - try: - im = Image.open(f) - im.load() - except Exception as msg: - pass - # print ("Bad Image %s: %s" %(f,msg)) + def get_files(self, d, ext='.bmp'): + return [os.path.join(base, d, f) for f + in os.listdir(os.path.join(base, d)) if ext in f] -def test_questionable(): - """ These shouldn't crash/dos, but its not well defined that these are in spec """ - for f in get_files('q'): - try: - im = Image.open(f) - im.load() - except Exception as msg: - pass - # print ("Bad Image %s: %s" %(f,msg)) + def test_bad(self): + """ These shouldn't crash/dos, but they shouldn't return anything + either """ + for f in self.get_files('b'): + try: + im = Image.open(f) + im.load() + except Exception: # as msg: + pass + # print ("Bad Image %s: %s" %(f,msg)) + + def test_questionable(self): + """ These shouldn't crash/dos, but its not well defined that these + are in spec """ + for f in self.get_files('q'): + try: + im = Image.open(f) + im.load() + except Exception: # as msg: + pass + # print ("Bad Image %s: %s" %(f,msg)) + + def test_good(self): + """ These should all work. There's a set of target files in the + html directory that we can compare against. """ + + # Target files, if they're not just replacing the extension + file_map = {'pal1wb.bmp': 'pal1.png', + 'pal4rle.bmp': 'pal4.png', + 'pal8-0.bmp': 'pal8.png', + 'pal8rle.bmp': 'pal8.png', + 'pal8topdown.bmp': 'pal8.png', + 'pal8nonsquare.bmp': 'pal8nonsquare-v.png', + 'pal8os2.bmp': 'pal8.png', + 'pal8os2sp.bmp': 'pal8.png', + 'pal8os2v2.bmp': 'pal8.png', + 'pal8os2v2-16.bmp': 'pal8.png', + 'pal8v4.bmp': 'pal8.png', + 'pal8v5.bmp': 'pal8.png', + 'rgb16-565pal.bmp': 'rgb16-565.png', + 'rgb24pal.bmp': 'rgb24.png', + 'rgb32.bmp': 'rgb24.png', + 'rgb32bf.bmp': 'rgb24.png' + } + + def get_compare(f): + (head, name) = os.path.split(f) + if name in file_map: + return os.path.join(base, 'html', file_map[name]) + (name, ext) = os.path.splitext(name) + return os.path.join(base, 'html', "%s.png" % name) + + for f in self.get_files('g'): + try: + im = Image.open(f) + im.load() + compare = Image.open(get_compare(f)) + compare.load() + if im.mode == 'P': + # assert image similar doesn't really work + # with paletized image, since the palette might + # be differently ordered for an equivalent image. + im = im.convert('RGBA') + compare = im.convert('RGBA') + self.assert_image_similar(im, compare, 5) + + except Exception as msg: + # there are three here that are unsupported: + unsupported = (os.path.join(base, 'g', 'rgb32bf.bmp'), + os.path.join(base, 'g', 'pal8rle.bmp'), + os.path.join(base, 'g', 'pal4rle.bmp')) + if f not in unsupported: + self.assertTrue( + False, "Unsupported Image %s: %s" % (f, msg)) -def test_good(): - """ These should all work. There's a set of target files in the - html directory that we can compare against. """ - - # Target files, if they're not just replacing the extension - file_map = { 'pal1wb.bmp': 'pal1.png', - 'pal4rle.bmp': 'pal4.png', - 'pal8-0.bmp': 'pal8.png', - 'pal8rle.bmp': 'pal8.png', - 'pal8topdown.bmp': 'pal8.png', - 'pal8nonsquare.bmp': 'pal8nonsquare-v.png', - 'pal8os2.bmp': 'pal8.png', - 'pal8os2sp.bmp': 'pal8.png', - 'pal8os2v2.bmp': 'pal8.png', - 'pal8os2v2-16.bmp': 'pal8.png', - 'pal8v4.bmp': 'pal8.png', - 'pal8v5.bmp': 'pal8.png', - 'rgb16-565pal.bmp': 'rgb16-565.png', - 'rgb24pal.bmp': 'rgb24.png', - 'rgb32.bmp': 'rgb24.png', - 'rgb32bf.bmp': 'rgb24.png' - } - - def get_compare(f): - (head, name) = os.path.split(f) - if name in file_map: - return os.path.join(base, 'html', file_map[name]) - (name,ext) = os.path.splitext(name) - return os.path.join(base, 'html', "%s.png"%name) - - for f in get_files('g'): - try: - im = Image.open(f) - im.load() - compare = Image.open(get_compare(f)) - compare.load() - if im.mode == 'P': - # assert image similar doesn't really work - # with paletized image, since the palette might - # be differently ordered for an equivalent image. - im = im.convert('RGBA') - compare = im.convert('RGBA') - assert_image_similar(im, compare,5) - - - except Exception as msg: - # there are three here that are unsupported: - unsupported = (os.path.join(base, 'g', 'rgb32bf.bmp'), - os.path.join(base, 'g', 'pal8rle.bmp'), - os.path.join(base, 'g', 'pal4rle.bmp')) - if f not in unsupported: - assert_true(False, "Unsupported Image %s: %s" %(f,msg)) +if __name__ == '__main__': + unittest.main() +# End of file diff --git a/Tests/test_cffi.py b/Tests/test_cffi.py index 1c0d8d31e..8ff4e817f 100644 --- a/Tests/test_cffi.py +++ b/Tests/test_cffi.py @@ -1,99 +1,136 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule, lena try: import cffi + from PIL import PyAccess except: - skip() - -from PIL import Image, PyAccess + # Skip in setUp() + pass -import test_image_putpixel as put -import test_image_getpixel as get +from PIL import Image +from test_image_putpixel import TestImagePutPixel +from test_image_getpixel import TestImageGetPixel Image.USE_CFFI_ACCESS = True -def test_put(): - put.test_sanity() -def test_get(): - get.test_basic() - get.test_signedness() +class TestCffiPutPixel(TestImagePutPixel): -def _test_get_access(im): - """ Do we get the same thing as the old pixel access """ + def setUp(self): + try: + import cffi + except: + self.skipTest("No cffi") - """ Using private interfaces, forcing a capi access and a pyaccess for the same image """ - caccess = im.im.pixel_access(False) - access = PyAccess.new(im, False) - - w,h = im.size - for x in range(0,w,10): - for y in range(0,h,10): - assert_equal(access[(x,y)], caccess[(x,y)]) - -def test_get_vs_c(): - _test_get_access(lena('RGB')) - _test_get_access(lena('RGBA')) - _test_get_access(lena('L')) - _test_get_access(lena('LA')) - _test_get_access(lena('1')) - _test_get_access(lena('P')) - #_test_get_access(lena('PA')) # PA -- how do I make a PA image??? - _test_get_access(lena('F')) - - im = Image.new('I;16', (10,10), 40000) - _test_get_access(im) - im = Image.new('I;16L', (10,10), 40000) - _test_get_access(im) - im = Image.new('I;16B', (10,10), 40000) - _test_get_access(im) - - im = Image.new('I', (10,10), 40000) - _test_get_access(im) - # These don't actually appear to be modes that I can actually make, - # as unpack sets them directly into the I mode. - #im = Image.new('I;32L', (10,10), -2**10) - #_test_get_access(im) - #im = Image.new('I;32B', (10,10), 2**10) - #_test_get_access(im) + def test_put(self): + self.test_sanity() +class TestCffiGetPixel(TestImageGetPixel): -def _test_set_access(im, color): - """ Are we writing the correct bits into the image? """ + def setUp(self): + try: + import cffi + except: + self.skipTest("No cffi") - """ Using private interfaces, forcing a capi access and a pyaccess for the same image """ - caccess = im.im.pixel_access(False) - access = PyAccess.new(im, False) + def test_get(self): + self.test_basic() + self.test_signedness() - w,h = im.size - for x in range(0,w,10): - for y in range(0,h,10): - access[(x,y)] = color - assert_equal(color, caccess[(x,y)]) -def test_set_vs_c(): - _test_set_access(lena('RGB'), (255, 128,0) ) - _test_set_access(lena('RGBA'), (255, 192, 128, 0)) - _test_set_access(lena('L'), 128) - _test_set_access(lena('LA'), (128,128)) - _test_set_access(lena('1'), 255) - _test_set_access(lena('P') , 128) - ##_test_set_access(i, (128,128)) #PA -- undone how to make - _test_set_access(lena('F'), 1024.0) - - im = Image.new('I;16', (10,10), 40000) - _test_set_access(im, 45000) - im = Image.new('I;16L', (10,10), 40000) - _test_set_access(im, 45000) - im = Image.new('I;16B', (10,10), 40000) - _test_set_access(im, 45000) - +class TestCffi(PillowTestCase): - im = Image.new('I', (10,10), 40000) - _test_set_access(im, 45000) -# im = Image.new('I;32L', (10,10), -(2**10)) -# _test_set_access(im, -(2**13)+1) - #im = Image.new('I;32B', (10,10), 2**10) - #_test_set_access(im, 2**13-1) + def setUp(self): + try: + import cffi + except: + self.skipTest("No cffi") + + def _test_get_access(self, im): + """ Do we get the same thing as the old pixel access """ + + """ Using private interfaces, forcing a capi access and + a pyaccess for the same image """ + caccess = im.im.pixel_access(False) + access = PyAccess.new(im, False) + + w, h = im.size + for x in range(0, w, 10): + for y in range(0, h, 10): + self.assertEqual(access[(x, y)], caccess[(x, y)]) + + def test_get_vs_c(self): + rgb = lena('RGB') + rgb.load() + self._test_get_access(rgb) + self._test_get_access(lena('RGBA')) + self._test_get_access(lena('L')) + self._test_get_access(lena('LA')) + self._test_get_access(lena('1')) + self._test_get_access(lena('P')) + # self._test_get_access(lena('PA')) # PA -- how do I make a PA image? + self._test_get_access(lena('F')) + + im = Image.new('I;16', (10, 10), 40000) + self._test_get_access(im) + im = Image.new('I;16L', (10, 10), 40000) + self._test_get_access(im) + im = Image.new('I;16B', (10, 10), 40000) + self._test_get_access(im) + + im = Image.new('I', (10, 10), 40000) + self._test_get_access(im) + # These don't actually appear to be modes that I can actually make, + # as unpack sets them directly into the I mode. + # im = Image.new('I;32L', (10, 10), -2**10) + # self._test_get_access(im) + # im = Image.new('I;32B', (10, 10), 2**10) + # self._test_get_access(im) + + def _test_set_access(self, im, color): + """ Are we writing the correct bits into the image? """ + + """ Using private interfaces, forcing a capi access and + a pyaccess for the same image """ + caccess = im.im.pixel_access(False) + access = PyAccess.new(im, False) + + w, h = im.size + for x in range(0, w, 10): + for y in range(0, h, 10): + access[(x, y)] = color + self.assertEqual(color, caccess[(x, y)]) + + def test_set_vs_c(self): + rgb = lena('RGB') + rgb.load() + self._test_set_access(rgb, (255, 128, 0)) + self._test_set_access(lena('RGBA'), (255, 192, 128, 0)) + self._test_set_access(lena('L'), 128) + self._test_set_access(lena('LA'), (128, 128)) + self._test_set_access(lena('1'), 255) + self._test_set_access(lena('P'), 128) + # self._test_set_access(i, (128, 128)) #PA -- undone how to make + self._test_set_access(lena('F'), 1024.0) + + im = Image.new('I;16', (10, 10), 40000) + self._test_set_access(im, 45000) + im = Image.new('I;16L', (10, 10), 40000) + self._test_set_access(im, 45000) + im = Image.new('I;16B', (10, 10), 40000) + self._test_set_access(im, 45000) + + im = Image.new('I', (10, 10), 40000) + self._test_set_access(im, 45000) + # im = Image.new('I;32L', (10, 10), -(2**10)) + # self._test_set_access(im, -(2**13)+1) + # im = Image.new('I;32B', (10, 10), 2**10) + # self._test_set_access(im, 2**13-1) + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_file_bmp.py b/Tests/test_file_bmp.py index dd5f31fd2..29ddb9824 100644 --- a/Tests/test_file_bmp.py +++ b/Tests/test_file_bmp.py @@ -1,38 +1,44 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule, lena from PIL import Image import io -def roundtrip(im): - outfile = tempfile("temp.bmp") - im.save(outfile, 'BMP') +class TestFileBmp(PillowTestCase): - reloaded = Image.open(outfile) - reloaded.load() - assert_equal(im.mode, reloaded.mode) - assert_equal(im.size, reloaded.size) - assert_equal(reloaded.format, "BMP") + def roundtrip(self, im): + outfile = self.tempfile("temp.bmp") + + im.save(outfile, 'BMP') + + reloaded = Image.open(outfile) + reloaded.load() + self.assertEqual(im.mode, reloaded.mode) + self.assertEqual(im.size, reloaded.size) + self.assertEqual(reloaded.format, "BMP") + + def test_sanity(self): + self.roundtrip(lena()) + + self.roundtrip(lena("1")) + self.roundtrip(lena("L")) + self.roundtrip(lena("P")) + self.roundtrip(lena("RGB")) + + def test_save_to_bytes(self): + output = io.BytesIO() + im = lena() + im.save(output, "BMP") + + output.seek(0) + reloaded = Image.open(output) + + self.assertEqual(im.mode, reloaded.mode) + self.assertEqual(im.size, reloaded.size) + self.assertEqual(reloaded.format, "BMP") -def test_sanity(): - roundtrip(lena()) - - roundtrip(lena("1")) - roundtrip(lena("L")) - roundtrip(lena("P")) - roundtrip(lena("RGB")) +if __name__ == '__main__': + unittest.main() - -def test_save_to_bytes(): - output = io.BytesIO() - im = lena() - im.save(output, "BMP") - - output.seek(0) - reloaded = Image.open(output) - - assert_equal(im.mode, reloaded.mode) - assert_equal(im.size, reloaded.size) - assert_equal(reloaded.format, "BMP") - +# End of file diff --git a/Tests/test_file_eps.py b/Tests/test_file_eps.py index 34ece8c8b..6a1a1b5e2 100644 --- a/Tests/test_file_eps.py +++ b/Tests/test_file_eps.py @@ -1,11 +1,8 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule from PIL import Image, EpsImagePlugin import io -if not EpsImagePlugin.has_ghostscript(): - skip() - # Our two EPS test files (they are identical except for their bounding boxes) file1 = "Tests/images/zero_bb.eps" file2 = "Tests/images/non_zero_bb.eps" @@ -20,123 +17,127 @@ file2_compare_scale2 = "Tests/images/non_zero_bb_scale2.png" # EPS test files with binary preview file3 = "Tests/images/binary_preview_map.eps" -def test_sanity(): - # Regular scale - image1 = Image.open(file1) - image1.load() - assert_equal(image1.mode, "RGB") - assert_equal(image1.size, (460, 352)) - assert_equal(image1.format, "EPS") - image2 = Image.open(file2) - image2.load() - assert_equal(image2.mode, "RGB") - assert_equal(image2.size, (360, 252)) - assert_equal(image2.format, "EPS") +class TestFileEps(PillowTestCase): - # Double scale - image1_scale2 = Image.open(file1) - image1_scale2.load(scale=2) - assert_equal(image1_scale2.mode, "RGB") - assert_equal(image1_scale2.size, (920, 704)) - assert_equal(image1_scale2.format, "EPS") + def setUp(self): + if not EpsImagePlugin.has_ghostscript(): + self.skipTest("Ghostscript not available") - image2_scale2 = Image.open(file2) - image2_scale2.load(scale=2) - assert_equal(image2_scale2.mode, "RGB") - assert_equal(image2_scale2.size, (720, 504)) - assert_equal(image2_scale2.format, "EPS") + def test_sanity(self): + # Regular scale + image1 = Image.open(file1) + image1.load() + self.assertEqual(image1.mode, "RGB") + self.assertEqual(image1.size, (460, 352)) + self.assertEqual(image1.format, "EPS") + image2 = Image.open(file2) + image2.load() + self.assertEqual(image2.mode, "RGB") + self.assertEqual(image2.size, (360, 252)) + self.assertEqual(image2.format, "EPS") -def test_file_object(): - # issue 479 - image1 = Image.open(file1) - with open(tempfile('temp_file.eps'), 'wb') as fh: - image1.save(fh, 'EPS') + # Double scale + image1_scale2 = Image.open(file1) + image1_scale2.load(scale=2) + self.assertEqual(image1_scale2.mode, "RGB") + self.assertEqual(image1_scale2.size, (920, 704)) + self.assertEqual(image1_scale2.format, "EPS") + image2_scale2 = Image.open(file2) + image2_scale2.load(scale=2) + self.assertEqual(image2_scale2.mode, "RGB") + self.assertEqual(image2_scale2.size, (720, 504)) + self.assertEqual(image2_scale2.format, "EPS") -def test_iobase_object(): - # issue 479 - image1 = Image.open(file1) - with io.open(tempfile('temp_iobase.eps'), 'wb') as fh: - image1.save(fh, 'EPS') + def test_file_object(self): + # issue 479 + image1 = Image.open(file1) + with open(self.tempfile('temp_file.eps'), 'wb') as fh: + image1.save(fh, 'EPS') + def test_iobase_object(self): + # issue 479 + image1 = Image.open(file1) + with io.open(self.tempfile('temp_iobase.eps'), 'wb') as fh: + image1.save(fh, 'EPS') -def test_render_scale1(): - # We need png support for these render test - codecs = dir(Image.core) - if "zip_encoder" not in codecs or "zip_decoder" not in codecs: - skip("zip/deflate support not available") + def test_render_scale1(self): + # We need png support for these render test + codecs = dir(Image.core) + if "zip_encoder" not in codecs or "zip_decoder" not in codecs: + self.skipTest("zip/deflate support not available") - # Zero bounding box - image1_scale1 = Image.open(file1) - image1_scale1.load() - image1_scale1_compare = Image.open(file1_compare).convert("RGB") - image1_scale1_compare.load() - assert_image_similar(image1_scale1, image1_scale1_compare, 5) + # Zero bounding box + image1_scale1 = Image.open(file1) + image1_scale1.load() + image1_scale1_compare = Image.open(file1_compare).convert("RGB") + image1_scale1_compare.load() + self.assert_image_similar(image1_scale1, image1_scale1_compare, 5) - # Non-Zero bounding box - image2_scale1 = Image.open(file2) - image2_scale1.load() - image2_scale1_compare = Image.open(file2_compare).convert("RGB") - image2_scale1_compare.load() - assert_image_similar(image2_scale1, image2_scale1_compare, 10) + # Non-Zero bounding box + image2_scale1 = Image.open(file2) + image2_scale1.load() + image2_scale1_compare = Image.open(file2_compare).convert("RGB") + image2_scale1_compare.load() + self.assert_image_similar(image2_scale1, image2_scale1_compare, 10) + def test_render_scale2(self): + # We need png support for these render test + codecs = dir(Image.core) + if "zip_encoder" not in codecs or "zip_decoder" not in codecs: + self.skipTest("zip/deflate support not available") -def test_render_scale2(): - # We need png support for these render test - codecs = dir(Image.core) - if "zip_encoder" not in codecs or "zip_decoder" not in codecs: - skip("zip/deflate support not available") + # Zero bounding box + image1_scale2 = Image.open(file1) + image1_scale2.load(scale=2) + image1_scale2_compare = Image.open(file1_compare_scale2).convert("RGB") + image1_scale2_compare.load() + self.assert_image_similar(image1_scale2, image1_scale2_compare, 5) - # Zero bounding box - image1_scale2 = Image.open(file1) - image1_scale2.load(scale=2) - image1_scale2_compare = Image.open(file1_compare_scale2).convert("RGB") - image1_scale2_compare.load() - assert_image_similar(image1_scale2, image1_scale2_compare, 5) + # Non-Zero bounding box + image2_scale2 = Image.open(file2) + image2_scale2.load(scale=2) + image2_scale2_compare = Image.open(file2_compare_scale2).convert("RGB") + image2_scale2_compare.load() + self.assert_image_similar(image2_scale2, image2_scale2_compare, 10) - # Non-Zero bounding box - image2_scale2 = Image.open(file2) - image2_scale2.load(scale=2) - image2_scale2_compare = Image.open(file2_compare_scale2).convert("RGB") - image2_scale2_compare.load() - assert_image_similar(image2_scale2, image2_scale2_compare, 10) + def test_resize(self): + # Arrange + image1 = Image.open(file1) + image2 = Image.open(file2) + new_size = (100, 100) + # Act + image1 = image1.resize(new_size) + image2 = image2.resize(new_size) -def test_resize(): - # Arrange - image1 = Image.open(file1) - image2 = Image.open(file2) - new_size = (100, 100) + # Assert + self.assertEqual(image1.size, new_size) + self.assertEqual(image2.size, new_size) - # Act - image1 = image1.resize(new_size) - image2 = image2.resize(new_size) + def test_thumbnail(self): + # Issue #619 + # Arrange + image1 = Image.open(file1) + image2 = Image.open(file2) + new_size = (100, 100) - # Assert - assert_equal(image1.size, new_size) - assert_equal(image2.size, new_size) + # Act + image1.thumbnail(new_size) + image2.thumbnail(new_size) + # Assert + self.assertEqual(max(image1.size), max(new_size)) + self.assertEqual(max(image2.size), max(new_size)) -def test_thumbnail(): - # Issue #619 - # Arrange - image1 = Image.open(file1) - image2 = Image.open(file2) - new_size = (100, 100) + def test_read_binary_preview(self): + # Issue 302 + # open image with binary preview + Image.open(file3) - # Act - image1.thumbnail(new_size) - image2.thumbnail(new_size) - - # Assert - assert_equal(max(image1.size), max(new_size)) - assert_equal(max(image2.size), max(new_size)) - -def test_read_binary_preview(): - # Issue 302 - # open image with binary preview - image1 = Image.open(file3) +if __name__ == '__main__': + unittest.main() # End of file diff --git a/Tests/test_file_fli.py b/Tests/test_file_fli.py index 4e06a732e..787365c14 100644 --- a/Tests/test_file_fli.py +++ b/Tests/test_file_fli.py @@ -1,4 +1,4 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule from PIL import Image @@ -6,9 +6,18 @@ from PIL import Image file = "Images/lena.fli" data = open(file, "rb").read() -def test_sanity(): - im = Image.open(file) - im.load() - assert_equal(im.mode, "P") - assert_equal(im.size, (128, 128)) - assert_equal(im.format, "FLI") + +class TestFileFli(PillowTestCase): + + def test_sanity(self): + im = Image.open(file) + im.load() + self.assertEqual(im.mode, "P") + self.assertEqual(im.size, (128, 128)) + self.assertEqual(im.format, "FLI") + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_file_gif.py b/Tests/test_file_gif.py index 4318e178e..3aefbe9b3 100644 --- a/Tests/test_file_gif.py +++ b/Tests/test_file_gif.py @@ -1,87 +1,96 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule, lena from PIL import Image codecs = dir(Image.core) -if "gif_encoder" not in codecs or "gif_decoder" not in codecs: - skip("gif support not available") # can this happen? - # sample gif stream file = "Images/lena.gif" with open(file, "rb") as f: data = f.read() -def test_sanity(): - im = Image.open(file) - im.load() - assert_equal(im.mode, "P") - assert_equal(im.size, (128, 128)) - assert_equal(im.format, "GIF") -def test_optimize(): - def test(optimize): - im = Image.new("L", (1, 1), 0) - file = BytesIO() - im.save(file, "GIF", optimize=optimize) - return len(file.getvalue()) - assert_equal(test(0), 800) - assert_equal(test(1), 38) +class TestFileGif(PillowTestCase): -def test_roundtrip(): - out = tempfile('temp.gif') - im = lena() - im.save(out) - reread = Image.open(out) + def setUp(self): + if "gif_encoder" not in codecs or "gif_decoder" not in codecs: + self.skipTest("gif support not available") # can this happen? - assert_image_similar(reread.convert('RGB'), im, 50) + def test_sanity(self): + im = Image.open(file) + im.load() + self.assertEqual(im.mode, "P") + self.assertEqual(im.size, (128, 128)) + self.assertEqual(im.format, "GIF") -def test_roundtrip2(): - #see https://github.com/python-imaging/Pillow/issues/403 - out = tempfile('temp.gif') - im = Image.open('Images/lena.gif') - im2 = im.copy() - im2.save(out) - reread = Image.open(out) + def test_optimize(self): + from io import BytesIO - assert_image_similar(reread.convert('RGB'), lena(), 50) + def test(optimize): + im = Image.new("L", (1, 1), 0) + file = BytesIO() + im.save(file, "GIF", optimize=optimize) + return len(file.getvalue()) + self.assertEqual(test(0), 800) + self.assertEqual(test(1), 38) + + def test_roundtrip(self): + out = self.tempfile('temp.gif') + im = lena() + im.save(out) + reread = Image.open(out) + + self.assert_image_similar(reread.convert('RGB'), im, 50) + + def test_roundtrip2(self): + # see https://github.com/python-pillow/Pillow/issues/403 + out = self.tempfile('temp.gif') + im = Image.open('Images/lena.gif') + im2 = im.copy() + im2.save(out) + reread = Image.open(out) + + self.assert_image_similar(reread.convert('RGB'), lena(), 50) + + def test_palette_handling(self): + # see https://github.com/python-pillow/Pillow/issues/513 + + im = Image.open('Images/lena.gif') + im = im.convert('RGB') + + im = im.resize((100, 100), Image.ANTIALIAS) + im2 = im.convert('P', palette=Image.ADAPTIVE, colors=256) + + f = self.tempfile('temp.gif') + im2.save(f, optimize=True) + + reloaded = Image.open(f) + + self.assert_image_similar(im, reloaded.convert('RGB'), 10) + + def test_palette_434(self): + # see https://github.com/python-pillow/Pillow/issues/434 + + def roundtrip(im, *args, **kwargs): + out = self.tempfile('temp.gif') + im.save(out, *args, **kwargs) + reloaded = Image.open(out) + + return [im, reloaded] + + orig = "Tests/images/test.colors.gif" + im = Image.open(orig) + + self.assert_image_equal(*roundtrip(im)) + self.assert_image_equal(*roundtrip(im, optimize=True)) + + im = im.convert("RGB") + # check automatic P conversion + reloaded = roundtrip(im)[1].convert('RGB') + self.assert_image_equal(im, reloaded) -def test_palette_handling(): - # see https://github.com/python-imaging/Pillow/issues/513 +if __name__ == '__main__': + unittest.main() - im = Image.open('Images/lena.gif') - im = im.convert('RGB') - - im = im.resize((100,100), Image.ANTIALIAS) - im2 = im.convert('P', palette=Image.ADAPTIVE, colors=256) - - f = tempfile('temp.gif') - im2.save(f, optimize=True) - - reloaded = Image.open(f) - - assert_image_similar(im, reloaded.convert('RGB'), 10) - -def test_palette_434(): - # see https://github.com/python-imaging/Pillow/issues/434 - - def roundtrip(im, *args, **kwargs): - out = tempfile('temp.gif') - im.save(out, *args, **kwargs) - reloaded = Image.open(out) - - return [im, reloaded] - - orig = "Tests/images/test.colors.gif" - im = Image.open(orig) - - assert_image_equal(*roundtrip(im)) - assert_image_equal(*roundtrip(im, optimize=True)) - - im = im.convert("RGB") - # check automatic P conversion - reloaded = roundtrip(im)[1].convert('RGB') - assert_image_equal(im, reloaded) - - +# End of file diff --git a/Tests/test_file_icns.py b/Tests/test_file_icns.py index 3e31f8879..c307ec844 100644 --- a/Tests/test_file_icns.py +++ b/Tests/test_file_icns.py @@ -1,4 +1,4 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule from PIL import Image @@ -8,59 +8,67 @@ data = open(file, "rb").read() enable_jpeg2k = hasattr(Image.core, 'jp2klib_version') -def test_sanity(): - # Loading this icon by default should result in the largest size - # (512x512@2x) being loaded - im = Image.open(file) - im.load() - assert_equal(im.mode, "RGBA") - assert_equal(im.size, (1024, 1024)) - assert_equal(im.format, "ICNS") -def test_sizes(): - # Check that we can load all of the sizes, and that the final pixel - # dimensions are as expected - im = Image.open(file) - for w,h,r in im.info['sizes']: - wr = w * r - hr = h * r - im2 = Image.open(file) - im2.size = (w, h, r) - im2.load() - assert_equal(im2.mode, 'RGBA') - assert_equal(im2.size, (wr, hr)) +class TestFileIcns(PillowTestCase): -def test_older_icon(): - # This icon was made with Icon Composer rather than iconutil; it still - # uses PNG rather than JP2, however (since it was made on 10.9). - im = Image.open('Tests/images/pillow2.icns') - for w,h,r in im.info['sizes']: - wr = w * r - hr = h * r - im2 = Image.open('Tests/images/pillow2.icns') - im2.size = (w, h, r) - im2.load() - assert_equal(im2.mode, 'RGBA') - assert_equal(im2.size, (wr, hr)) + def test_sanity(self): + # Loading this icon by default should result in the largest size + # (512x512@2x) being loaded + im = Image.open(file) + im.load() + self.assertEqual(im.mode, "RGBA") + self.assertEqual(im.size, (1024, 1024)) + self.assertEqual(im.format, "ICNS") -def test_jp2_icon(): - # This icon was made by using Uli Kusterer's oldiconutil to replace - # the PNG images with JPEG 2000 ones. The advantage of doing this is - # that OS X 10.5 supports JPEG 2000 but not PNG; some commercial - # software therefore does just this. - - # (oldiconutil is here: https://github.com/uliwitness/oldiconutil) + def test_sizes(self): + # Check that we can load all of the sizes, and that the final pixel + # dimensions are as expected + im = Image.open(file) + for w, h, r in im.info['sizes']: + wr = w * r + hr = h * r + im2 = Image.open(file) + im2.size = (w, h, r) + im2.load() + self.assertEqual(im2.mode, 'RGBA') + self.assertEqual(im2.size, (wr, hr)) - if not enable_jpeg2k: - return - - im = Image.open('Tests/images/pillow3.icns') - for w,h,r in im.info['sizes']: - wr = w * r - hr = h * r - im2 = Image.open('Tests/images/pillow3.icns') - im2.size = (w, h, r) - im2.load() - assert_equal(im2.mode, 'RGBA') - assert_equal(im2.size, (wr, hr)) - + def test_older_icon(self): + # This icon was made with Icon Composer rather than iconutil; it still + # uses PNG rather than JP2, however (since it was made on 10.9). + im = Image.open('Tests/images/pillow2.icns') + for w, h, r in im.info['sizes']: + wr = w * r + hr = h * r + im2 = Image.open('Tests/images/pillow2.icns') + im2.size = (w, h, r) + im2.load() + self.assertEqual(im2.mode, 'RGBA') + self.assertEqual(im2.size, (wr, hr)) + + def test_jp2_icon(self): + # This icon was made by using Uli Kusterer's oldiconutil to replace + # the PNG images with JPEG 2000 ones. The advantage of doing this is + # that OS X 10.5 supports JPEG 2000 but not PNG; some commercial + # software therefore does just this. + + # (oldiconutil is here: https://github.com/uliwitness/oldiconutil) + + if not enable_jpeg2k: + return + + im = Image.open('Tests/images/pillow3.icns') + for w, h, r in im.info['sizes']: + wr = w * r + hr = h * r + im2 = Image.open('Tests/images/pillow3.icns') + im2.size = (w, h, r) + im2.load() + self.assertEqual(im2.mode, 'RGBA') + self.assertEqual(im2.size, (wr, hr)) + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_file_ico.py b/Tests/test_file_ico.py index e0db34acc..5bad94a53 100644 --- a/Tests/test_file_ico.py +++ b/Tests/test_file_ico.py @@ -1,4 +1,4 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule from PIL import Image @@ -6,9 +6,18 @@ from PIL import Image file = "Images/lena.ico" data = open(file, "rb").read() -def test_sanity(): - im = Image.open(file) - im.load() - assert_equal(im.mode, "RGBA") - assert_equal(im.size, (16, 16)) - assert_equal(im.format, "ICO") + +class TestFileIco(PillowTestCase): + + def test_sanity(self): + im = Image.open(file) + im.load() + self.assertEqual(im.mode, "RGBA") + self.assertEqual(im.size, (16, 16)) + self.assertEqual(im.format, "ICO") + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_file_jpeg.py b/Tests/test_file_jpeg.py index c9ee4eec2..74ee8a1c3 100644 --- a/Tests/test_file_jpeg.py +++ b/Tests/test_file_jpeg.py @@ -1,245 +1,237 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule, lena, py3 import random +from io import BytesIO from PIL import Image from PIL import ImageFile codecs = dir(Image.core) -if "jpeg_encoder" not in codecs or "jpeg_decoder" not in codecs: - skip("jpeg support not available") - -test_file = "Images/lena.jpg" +test_file = "Tests/images/lena.jpg" -def roundtrip(im, **options): - out = BytesIO() - im.save(out, "JPEG", **options) - bytes = out.tell() - out.seek(0) - im = Image.open(out) - im.bytes = bytes # for testing only - return im +class TestFileJpeg(PillowTestCase): -# -------------------------------------------------------------------- + def setUp(self): + if "jpeg_encoder" not in codecs or "jpeg_decoder" not in codecs: + self.skipTest("jpeg support not available") + def roundtrip(self, im, **options): + out = BytesIO() + im.save(out, "JPEG", **options) + bytes = out.tell() + out.seek(0) + im = Image.open(out) + im.bytes = bytes # for testing only + return im -def test_sanity(): + def test_sanity(self): - # internal version number - assert_match(Image.core.jpeglib_version, "\d+\.\d+$") + # internal version number + self.assertRegexpMatches(Image.core.jpeglib_version, "\d+\.\d+$") - im = Image.open(test_file) - im.load() - assert_equal(im.mode, "RGB") - assert_equal(im.size, (128, 128)) - assert_equal(im.format, "JPEG") - - -# -------------------------------------------------------------------- - -def test_app(): - # Test APP/COM reader (@PIL135) - im = Image.open(test_file) - assert_equal(im.applist[0], - ("APP0", b"JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00")) - assert_equal(im.applist[1], ("COM", b"Python Imaging Library")) - assert_equal(len(im.applist), 2) - - -def test_cmyk(): - # Test CMYK handling. Thanks to Tim and Charlie for test data, - # Michael for getting me to look one more time. - f = "Tests/images/pil_sample_cmyk.jpg" - im = Image.open(f) - # the source image has red pixels in the upper left corner. - c, m, y, k = [x / 255.0 for x in im.getpixel((0, 0))] - assert_true(c == 0.0 and m > 0.8 and y > 0.8 and k == 0.0) - # the opposite corner is black - c, m, y, k = [x / 255.0 for x in im.getpixel((im.size[0]-1, im.size[1]-1))] - assert_true(k > 0.9) - # roundtrip, and check again - im = roundtrip(im) - c, m, y, k = [x / 255.0 for x in im.getpixel((0, 0))] - assert_true(c == 0.0 and m > 0.8 and y > 0.8 and k == 0.0) - c, m, y, k = [x / 255.0 for x in im.getpixel((im.size[0]-1, im.size[1]-1))] - assert_true(k > 0.9) - - -def test_dpi(): - def test(xdpi, ydpi=None): im = Image.open(test_file) - im = roundtrip(im, dpi=(xdpi, ydpi or xdpi)) - return im.info.get("dpi") - assert_equal(test(72), (72, 72)) - assert_equal(test(300), (300, 300)) - assert_equal(test(100, 200), (100, 200)) - assert_equal(test(0), None) # square pixels + im.load() + self.assertEqual(im.mode, "RGB") + self.assertEqual(im.size, (128, 128)) + self.assertEqual(im.format, "JPEG") + + def test_app(self): + # Test APP/COM reader (@PIL135) + im = Image.open(test_file) + self.assertEqual( + im.applist[0], + ("APP0", b"JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00")) + self.assertEqual(im.applist[1], ("COM", b"Python Imaging Library")) + self.assertEqual(len(im.applist), 2) + + def test_cmyk(self): + # Test CMYK handling. Thanks to Tim and Charlie for test data, + # Michael for getting me to look one more time. + f = "Tests/images/pil_sample_cmyk.jpg" + im = Image.open(f) + # the source image has red pixels in the upper left corner. + c, m, y, k = [x / 255.0 for x in im.getpixel((0, 0))] + self.assertEqual(c, 0.0) + self.assertGreater(m, 0.8) + self.assertGreater(y, 0.8) + self.assertEqual(k, 0.0) + # the opposite corner is black + c, m, y, k = [x / 255.0 for x in im.getpixel((im.size[0]-1, im.size[1]-1))] + self.assertGreater(k, 0.9) + # roundtrip, and check again + im = self.roundtrip(im) + c, m, y, k = [x / 255.0 for x in im.getpixel((0, 0))] + self.assertEqual(c, 0.0) + self.assertGreater(m, 0.8) + self.assertGreater(y, 0.8) + self.assertEqual(k, 0.0) + c, m, y, k = [x / 255.0 for x in im.getpixel((im.size[0]-1, im.size[1]-1))] + self.assertGreater(k, 0.9) + + def test_dpi(self): + def test(xdpi, ydpi=None): + im = Image.open(test_file) + im = self.roundtrip(im, dpi=(xdpi, ydpi or xdpi)) + return im.info.get("dpi") + self.assertEqual(test(72), (72, 72)) + self.assertEqual(test(300), (300, 300)) + self.assertEqual(test(100, 200), (100, 200)) + self.assertEqual(test(0), None) # square pixels + + def test_icc(self): + # Test ICC support + im1 = Image.open("Tests/images/rgb.jpg") + icc_profile = im1.info["icc_profile"] + self.assertEqual(len(icc_profile), 3144) + # Roundtrip via physical file. + f = self.tempfile("temp.jpg") + im1.save(f, icc_profile=icc_profile) + im2 = Image.open(f) + self.assertEqual(im2.info.get("icc_profile"), icc_profile) + # Roundtrip via memory buffer. + im1 = self.roundtrip(lena()) + im2 = self.roundtrip(lena(), icc_profile=icc_profile) + self.assert_image_equal(im1, im2) + self.assertFalse(im1.info.get("icc_profile")) + self.assertTrue(im2.info.get("icc_profile")) + + def test_icc_big(self): + # Make sure that the "extra" support handles large blocks + def test(n): + # The ICC APP marker can store 65519 bytes per marker, so + # using a 4-byte test code should allow us to detect out of + # order issues. + icc_profile = (b"Test"*int(n/4+1))[:n] + assert len(icc_profile) == n # sanity + im1 = self.roundtrip(lena(), icc_profile=icc_profile) + self.assertEqual(im1.info.get("icc_profile"), icc_profile or None) + test(0) + test(1) + test(3) + test(4) + test(5) + test(65533-14) # full JPEG marker block + test(65533-14+1) # full block plus one byte + test(ImageFile.MAXBLOCK) # full buffer block + test(ImageFile.MAXBLOCK+1) # full buffer block plus one byte + test(ImageFile.MAXBLOCK*4+3) # large block + + def test_optimize(self): + im1 = self.roundtrip(lena()) + im2 = self.roundtrip(lena(), optimize=1) + self.assert_image_equal(im1, im2) + self.assertGreaterEqual(im1.bytes, im2.bytes) + + def test_optimize_large_buffer(self): + # https://github.com/python-pillow/Pillow/issues/148 + f = self.tempfile('temp.jpg') + # this requires ~ 1.5x Image.MAXBLOCK + im = Image.new("RGB", (4096, 4096), 0xff3333) + im.save(f, format="JPEG", optimize=True) + + def test_progressive(self): + im1 = self.roundtrip(lena()) + im2 = self.roundtrip(lena(), progressive=True) + self.assert_image_equal(im1, im2) + self.assertGreaterEqual(im1.bytes, im2.bytes) + + def test_progressive_large_buffer(self): + f = self.tempfile('temp.jpg') + # this requires ~ 1.5x Image.MAXBLOCK + im = Image.new("RGB", (4096, 4096), 0xff3333) + im.save(f, format="JPEG", progressive=True) + + def test_progressive_large_buffer_highest_quality(self): + f = self.tempfile('temp.jpg') + if py3: + a = bytes(random.randint(0, 255) for _ in range(256 * 256 * 3)) + else: + a = b''.join(chr(random.randint(0, 255)) for _ in range(256 * 256 * 3)) + im = Image.frombuffer("RGB", (256, 256), a, "raw", "RGB", 0, 1) + # this requires more bytes than pixels in the image + im.save(f, format="JPEG", progressive=True, quality=100) + + def test_large_exif(self): + # https://github.com/python-pillow/Pillow/issues/148 + f = self.tempfile('temp.jpg') + im = lena() + im.save(f, 'JPEG', quality=90, exif=b"1"*65532) + + def test_progressive_compat(self): + im1 = self.roundtrip(lena()) + im2 = self.roundtrip(lena(), progressive=1) + im3 = self.roundtrip(lena(), progression=1) # compatibility + self.assert_image_equal(im1, im2) + self.assert_image_equal(im1, im3) + self.assertFalse(im1.info.get("progressive")) + self.assertFalse(im1.info.get("progression")) + self.assertTrue(im2.info.get("progressive")) + self.assertTrue(im2.info.get("progression")) + self.assertTrue(im3.info.get("progressive")) + self.assertTrue(im3.info.get("progression")) + + def test_quality(self): + im1 = self.roundtrip(lena()) + im2 = self.roundtrip(lena(), quality=50) + self.assert_image(im1, im2.mode, im2.size) + self.assertGreaterEqual(im1.bytes, im2.bytes) + + def test_smooth(self): + im1 = self.roundtrip(lena()) + im2 = self.roundtrip(lena(), smooth=100) + self.assert_image(im1, im2.mode, im2.size) + + def test_subsampling(self): + def getsampling(im): + layer = im.layer + return layer[0][1:3] + layer[1][1:3] + layer[2][1:3] + # experimental API + im = self.roundtrip(lena(), subsampling=-1) # default + self.assertEqual(getsampling(im), (2, 2, 1, 1, 1, 1)) + im = self.roundtrip(lena(), subsampling=0) # 4:4:4 + self.assertEqual(getsampling(im), (1, 1, 1, 1, 1, 1)) + im = self.roundtrip(lena(), subsampling=1) # 4:2:2 + self.assertEqual(getsampling(im), (2, 1, 1, 1, 1, 1)) + im = self.roundtrip(lena(), subsampling=2) # 4:1:1 + self.assertEqual(getsampling(im), (2, 2, 1, 1, 1, 1)) + im = self.roundtrip(lena(), subsampling=3) # default (undefined) + self.assertEqual(getsampling(im), (2, 2, 1, 1, 1, 1)) + + im = self.roundtrip(lena(), subsampling="4:4:4") + self.assertEqual(getsampling(im), (1, 1, 1, 1, 1, 1)) + im = self.roundtrip(lena(), subsampling="4:2:2") + self.assertEqual(getsampling(im), (2, 1, 1, 1, 1, 1)) + im = self.roundtrip(lena(), subsampling="4:1:1") + self.assertEqual(getsampling(im), (2, 2, 1, 1, 1, 1)) + + self.assertRaises( + TypeError, lambda: self.roundtrip(lena(), subsampling="1:1:1")) + + def test_exif(self): + im = Image.open("Tests/images/pil_sample_rgb.jpg") + info = im._getexif() + self.assertEqual(info[305], 'Adobe Photoshop CS Macintosh') + + def test_quality_keep(self): + im = Image.open("Tests/images/lena.jpg") + f = self.tempfile('temp.jpg') + im.save(f, quality='keep') + + def test_junk_jpeg_header(self): + # https://github.com/python-pillow/Pillow/issues/630 + filename = "Tests/images/junk_jpeg_header.jpg" + Image.open(filename) + + def test_qtables(): + im = Image.open("Tests/images/lena.jpg") + qtables = im.quantization + reloaded = self.roundtrip(im, qtables=qtables, subsampling=0) + self.assertEqual(im.quantization, reloaded.quantization) -def test_icc(): - # Test ICC support - im1 = Image.open("Tests/images/rgb.jpg") - icc_profile = im1.info["icc_profile"] - assert_equal(len(icc_profile), 3144) - # Roundtrip via physical file. - f = tempfile("temp.jpg") - im1.save(f, icc_profile=icc_profile) - im2 = Image.open(f) - assert_equal(im2.info.get("icc_profile"), icc_profile) - # Roundtrip via memory buffer. - im1 = roundtrip(lena()) - im2 = roundtrip(lena(), icc_profile=icc_profile) - assert_image_equal(im1, im2) - assert_false(im1.info.get("icc_profile")) - assert_true(im2.info.get("icc_profile")) - - -def test_icc_big(): - # Make sure that the "extra" support handles large blocks - def test(n): - # The ICC APP marker can store 65519 bytes per marker, so - # using a 4-byte test code should allow us to detect out of - # order issues. - icc_profile = (b"Test"*int(n/4+1))[:n] - assert len(icc_profile) == n # sanity - im1 = roundtrip(lena(), icc_profile=icc_profile) - assert_equal(im1.info.get("icc_profile"), icc_profile or None) - test(0) - test(1) - test(3) - test(4) - test(5) - test(65533-14) # full JPEG marker block - test(65533-14+1) # full block plus one byte - test(ImageFile.MAXBLOCK) # full buffer block - test(ImageFile.MAXBLOCK+1) # full buffer block plus one byte - test(ImageFile.MAXBLOCK*4+3) # large block - - -def test_optimize(): - im1 = roundtrip(lena()) - im2 = roundtrip(lena(), optimize=1) - assert_image_equal(im1, im2) - assert_true(im1.bytes >= im2.bytes) - - -def test_optimize_large_buffer(): - # https://github.com/python-imaging/Pillow/issues/148 - f = tempfile('temp.jpg') - # this requires ~ 1.5x Image.MAXBLOCK - im = Image.new("RGB", (4096, 4096), 0xff3333) - im.save(f, format="JPEG", optimize=True) - - -def test_progressive(): - im1 = roundtrip(lena()) - im2 = roundtrip(lena(), progressive=True) - assert_image_equal(im1, im2) - assert_true(im1.bytes >= im2.bytes) - - -def test_progressive_large_buffer(): - f = tempfile('temp.jpg') - # this requires ~ 1.5x Image.MAXBLOCK - im = Image.new("RGB", (4096, 4096), 0xff3333) - im.save(f, format="JPEG", progressive=True) - - -def test_progressive_large_buffer_highest_quality(): - f = tempfile('temp.jpg') - if py3: - a = bytes(random.randint(0, 255) for _ in range(256 * 256 * 3)) - else: - a = b''.join(chr(random.randint(0, 255)) for _ in range(256 * 256 * 3)) - im = Image.frombuffer("RGB", (256, 256), a, "raw", "RGB", 0, 1) - # this requires more bytes than pixels in the image - im.save(f, format="JPEG", progressive=True, quality=100) - - -def test_large_exif(): - # https://github.com/python-imaging/Pillow/issues/148 - f = tempfile('temp.jpg') - im = lena() - im.save(f, 'JPEG', quality=90, exif=b"1"*65532) - - -def test_progressive_compat(): - im1 = roundtrip(lena()) - im2 = roundtrip(lena(), progressive=1) - im3 = roundtrip(lena(), progression=1) # compatibility - assert_image_equal(im1, im2) - assert_image_equal(im1, im3) - assert_false(im1.info.get("progressive")) - assert_false(im1.info.get("progression")) - assert_true(im2.info.get("progressive")) - assert_true(im2.info.get("progression")) - assert_true(im3.info.get("progressive")) - assert_true(im3.info.get("progression")) - - -def test_quality(): - im1 = roundtrip(lena()) - im2 = roundtrip(lena(), quality=50) - assert_image(im1, im2.mode, im2.size) - assert_true(im1.bytes >= im2.bytes) - - -def test_smooth(): - im1 = roundtrip(lena()) - im2 = roundtrip(lena(), smooth=100) - assert_image(im1, im2.mode, im2.size) - - -def test_subsampling(): - def getsampling(im): - layer = im.layer - return layer[0][1:3] + layer[1][1:3] + layer[2][1:3] - # experimental API - im = roundtrip(lena(), subsampling=-1) # default - assert_equal(getsampling(im), (2, 2, 1, 1, 1, 1)) - im = roundtrip(lena(), subsampling=0) # 4:4:4 - assert_equal(getsampling(im), (1, 1, 1, 1, 1, 1)) - im = roundtrip(lena(), subsampling=1) # 4:2:2 - assert_equal(getsampling(im), (2, 1, 1, 1, 1, 1)) - im = roundtrip(lena(), subsampling=2) # 4:1:1 - assert_equal(getsampling(im), (2, 2, 1, 1, 1, 1)) - im = roundtrip(lena(), subsampling=3) # default (undefined) - assert_equal(getsampling(im), (2, 2, 1, 1, 1, 1)) - - im = roundtrip(lena(), subsampling="4:4:4") - assert_equal(getsampling(im), (1, 1, 1, 1, 1, 1)) - im = roundtrip(lena(), subsampling="4:2:2") - assert_equal(getsampling(im), (2, 1, 1, 1, 1, 1)) - im = roundtrip(lena(), subsampling="4:1:1") - assert_equal(getsampling(im), (2, 2, 1, 1, 1, 1)) - - assert_exception(TypeError, lambda: roundtrip(lena(), subsampling="1:1:1")) - - -def test_exif(): - im = Image.open("Tests/images/pil_sample_rgb.jpg") - info = im._getexif() - assert_equal(info[305], 'Adobe Photoshop CS Macintosh') - - -def test_quality_keep(): - im = Image.open("Images/lena.jpg") - f = tempfile('temp.jpg') - assert_no_exception(lambda: im.save(f, quality='keep')) - - -def test_qtables(): - im = Image.open("Images/lena.jpg") - qtables = im.quantization - f = tempfile('temp.jpg') - assert_no_exception(lambda: im.save(f, qtables=qtables, subsampling=0)) - - -def test_junk_jpeg_header(): - # https://github.com/python-imaging/Pillow/issues/630 - filename = "Tests/images/junk_jpeg_header.jpg" - assert_no_exception(lambda: Image.open(filename)) +if __name__ == '__main__': + unittest.main() # End of file diff --git a/Tests/test_file_jpeg2k.py b/Tests/test_file_jpeg2k.py index b11e5e6ab..9111f4f8a 100644 --- a/Tests/test_file_jpeg2k.py +++ b/Tests/test_file_jpeg2k.py @@ -1,110 +1,114 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule from PIL import Image -from PIL import ImageFile +from io import BytesIO codecs = dir(Image.core) -if "jpeg2k_encoder" not in codecs or "jpeg2k_decoder" not in codecs: - skip('JPEG 2000 support not available') - -# OpenJPEG 2.0.0 outputs this debugging message sometimes; we should -# ignore it---it doesn't represent a test failure. -ignore('Not enough memory to handle tile data') - test_card = Image.open('Tests/images/test-card.png') test_card.load() -def roundtrip(im, **options): - out = BytesIO() - im.save(out, "JPEG2000", **options) - bytes = out.tell() - out.seek(0) - im = Image.open(out) - im.bytes = bytes # for testing only - im.load() - return im +# OpenJPEG 2.0.0 outputs this debugging message sometimes; we should +# ignore it---it doesn't represent a test failure. +# 'Not enough memory to handle tile data' -# ---------------------------------------------------------------------- -def test_sanity(): - # Internal version number - assert_match(Image.core.jp2klib_version, '\d+\.\d+\.\d+$') +class TestFileJpeg2k(PillowTestCase): - im = Image.open('Tests/images/test-card-lossless.jp2') - im.load() - assert_equal(im.mode, 'RGB') - assert_equal(im.size, (640, 480)) - assert_equal(im.format, 'JPEG2000') - -# ---------------------------------------------------------------------- + def setUp(self): + if "jpeg2k_encoder" not in codecs or "jpeg2k_decoder" not in codecs: + self.skipTest('JPEG 2000 support not available') -# These two test pre-written JPEG 2000 files that were not written with -# PIL (they were made using Adobe Photoshop) + def roundtrip(self, im, **options): + out = BytesIO() + im.save(out, "JPEG2000", **options) + bytes = out.tell() + out.seek(0) + im = Image.open(out) + im.bytes = bytes # for testing only + im.load() + return im -def test_lossless(): - im = Image.open('Tests/images/test-card-lossless.jp2') - im.load() - im.save('/tmp/test-card.png') - assert_image_similar(im, test_card, 1.0e-3) + def test_sanity(self): + # Internal version number + self.assertRegexpMatches(Image.core.jp2klib_version, '\d+\.\d+\.\d+$') -def test_lossy_tiled(): - im = Image.open('Tests/images/test-card-lossy-tiled.jp2') - im.load() - assert_image_similar(im, test_card, 2.0) + im = Image.open('Tests/images/test-card-lossless.jp2') + im.load() + self.assertEqual(im.mode, 'RGB') + self.assertEqual(im.size, (640, 480)) + self.assertEqual(im.format, 'JPEG2000') -# ---------------------------------------------------------------------- + # These two test pre-written JPEG 2000 files that were not written with + # PIL (they were made using Adobe Photoshop) -def test_lossless_rt(): - im = roundtrip(test_card) - assert_image_equal(im, test_card) + def test_lossless(self): + im = Image.open('Tests/images/test-card-lossless.jp2') + im.load() + im.save('/tmp/test-card.png') + self.assert_image_similar(im, test_card, 1.0e-3) -def test_lossy_rt(): - im = roundtrip(test_card, quality_layers=[20]) - assert_image_similar(im, test_card, 2.0) + def test_lossy_tiled(self): + im = Image.open('Tests/images/test-card-lossy-tiled.jp2') + im.load() + self.assert_image_similar(im, test_card, 2.0) -def test_tiled_rt(): - im = roundtrip(test_card, tile_size=(128, 128)) - assert_image_equal(im, test_card) + def test_lossless_rt(self): + im = self.roundtrip(test_card) + self.assert_image_equal(im, test_card) -def test_tiled_offset_rt(): - im = roundtrip(test_card, tile_size=(128, 128), tile_offset=(0, 0), - offset=(32, 32)) - assert_image_equal(im, test_card) - -def test_irreversible_rt(): - im = roundtrip(test_card, irreversible=True, quality_layers=[20]) - assert_image_similar(im, test_card, 2.0) + def test_lossy_rt(self): + im = self.roundtrip(test_card, quality_layers=[20]) + self.assert_image_similar(im, test_card, 2.0) -def test_prog_qual_rt(): - im = roundtrip(test_card, quality_layers=[60, 40, 20], progression='LRCP') - assert_image_similar(im, test_card, 2.0) + def test_tiled_rt(self): + im = self.roundtrip(test_card, tile_size=(128, 128)) + self.assert_image_equal(im, test_card) -def test_prog_res_rt(): - im = roundtrip(test_card, num_resolutions=8, progression='RLCP') - assert_image_equal(im, test_card) + def test_tiled_offset_rt(self): + im = self.roundtrip( + test_card, tile_size=(128, 128), + tile_offset=(0, 0), offset=(32, 32)) + self.assert_image_equal(im, test_card) -# ---------------------------------------------------------------------- + def test_irreversible_rt(self): + im = self.roundtrip(test_card, irreversible=True, quality_layers=[20]) + self.assert_image_similar(im, test_card, 2.0) -def test_reduce(): - im = Image.open('Tests/images/test-card-lossless.jp2') - im.reduce = 2 - im.load() - assert_equal(im.size, (160, 120)) + def test_prog_qual_rt(self): + im = self.roundtrip( + test_card, quality_layers=[60, 40, 20], progression='LRCP') + self.assert_image_similar(im, test_card, 2.0) -def test_layers(): - out = BytesIO() - test_card.save(out, 'JPEG2000', quality_layers=[100, 50, 10], - progression='LRCP') - out.seek(0) - - im = Image.open(out) - im.layers = 1 - im.load() - assert_image_similar(im, test_card, 13) + def test_prog_res_rt(self): + im = self.roundtrip(test_card, num_resolutions=8, progression='RLCP') + self.assert_image_equal(im, test_card) - out.seek(0) - im = Image.open(out) - im.layers = 3 - im.load() - assert_image_similar(im, test_card, 0.4) + def test_reduce(self): + im = Image.open('Tests/images/test-card-lossless.jp2') + im.reduce = 2 + im.load() + self.assertEqual(im.size, (160, 120)) + + def test_layers(self): + out = BytesIO() + test_card.save(out, 'JPEG2000', quality_layers=[100, 50, 10], + progression='LRCP') + out.seek(0) + + im = Image.open(out) + im.layers = 1 + im.load() + self.assert_image_similar(im, test_card, 13) + + out.seek(0) + im = Image.open(out) + im.layers = 3 + im.load() + self.assert_image_similar(im, test_card, 0.4) + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_file_libtiff.py b/Tests/test_file_libtiff.py index 58fa75239..1afeee488 100644 --- a/Tests/test_file_libtiff.py +++ b/Tests/test_file_libtiff.py @@ -1,300 +1,318 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule, lena, py3 + import os from PIL import Image, TiffImagePlugin -codecs = dir(Image.core) -if "libtiff_encoder" not in codecs or "libtiff_decoder" not in codecs: - skip("tiff support not available") +class TestFileLibTiff(PillowTestCase): -def _assert_noerr(im): - """Helper tests that assert basic sanity about the g4 tiff reading""" - #1 bit - assert_equal(im.mode, "1") + def setUp(self): + codecs = dir(Image.core) - # Does the data actually load - assert_no_exception(lambda: im.load()) - assert_no_exception(lambda: im.getdata()) + if "libtiff_encoder" not in codecs or "libtiff_decoder" not in codecs: + self.skipTest("tiff support not available") - try: - assert_equal(im._compression, 'group4') - except: - print("No _compression") - print (dir(im)) + def _assert_noerr(self, im): + """Helper tests that assert basic sanity about the g4 tiff reading""" + # 1 bit + self.assertEqual(im.mode, "1") - # can we write it back out, in a different form. - out = tempfile("temp.png") - assert_no_exception(lambda: im.save(out)) + # Does the data actually load + im.load() + im.getdata() -def test_g4_tiff(): - """Test the ordinary file path load path""" + try: + self.assertEqual(im._compression, 'group4') + except: + print("No _compression") + print (dir(im)) - file = "Tests/images/lena_g4_500.tif" - im = Image.open(file) + # can we write it back out, in a different form. + out = self.tempfile("temp.png") + im.save(out) - assert_equal(im.size, (500,500)) - _assert_noerr(im) + def test_g4_tiff(self): + """Test the ordinary file path load path""" -def test_g4_large(): - file = "Tests/images/pport_g4.tif" - im = Image.open(file) - _assert_noerr(im) + file = "Tests/images/lena_g4_500.tif" + im = Image.open(file) -def test_g4_tiff_file(): - """Testing the string load path""" + self.assertEqual(im.size, (500, 500)) + self._assert_noerr(im) - file = "Tests/images/lena_g4_500.tif" - with open(file,'rb') as f: - im = Image.open(f) + def test_g4_large(self): + file = "Tests/images/pport_g4.tif" + im = Image.open(file) + self._assert_noerr(im) - assert_equal(im.size, (500,500)) - _assert_noerr(im) + def test_g4_tiff_file(self): + """Testing the string load path""" -def test_g4_tiff_bytesio(): - """Testing the stringio loading code path""" - from io import BytesIO - file = "Tests/images/lena_g4_500.tif" - s = BytesIO() - with open(file,'rb') as f: - s.write(f.read()) - s.seek(0) - im = Image.open(s) + file = "Tests/images/lena_g4_500.tif" + with open(file, 'rb') as f: + im = Image.open(f) - assert_equal(im.size, (500,500)) - _assert_noerr(im) + self.assertEqual(im.size, (500, 500)) + self._assert_noerr(im) -def test_g4_eq_png(): - """ Checking that we're actually getting the data that we expect""" - png = Image.open('Tests/images/lena_bw_500.png') - g4 = Image.open('Tests/images/lena_g4_500.tif') + def test_g4_tiff_bytesio(self): + """Testing the stringio loading code path""" + from io import BytesIO + file = "Tests/images/lena_g4_500.tif" + s = BytesIO() + with open(file, 'rb') as f: + s.write(f.read()) + s.seek(0) + im = Image.open(s) - assert_image_equal(g4, png) + self.assertEqual(im.size, (500, 500)) + self._assert_noerr(im) -# see https://github.com/python-imaging/Pillow/issues/279 -def test_g4_fillorder_eq_png(): - """ Checking that we're actually getting the data that we expect""" - png = Image.open('Tests/images/g4-fillorder-test.png') - g4 = Image.open('Tests/images/g4-fillorder-test.tif') + def test_g4_eq_png(self): + """ Checking that we're actually getting the data that we expect""" + png = Image.open('Tests/images/lena_bw_500.png') + g4 = Image.open('Tests/images/lena_g4_500.tif') - assert_image_equal(g4, png) + self.assert_image_equal(g4, png) -def test_g4_write(): - """Checking to see that the saved image is the same as what we wrote""" - file = "Tests/images/lena_g4_500.tif" - orig = Image.open(file) + # see https://github.com/python-pillow/Pillow/issues/279 + def test_g4_fillorder_eq_png(self): + """ Checking that we're actually getting the data that we expect""" + png = Image.open('Tests/images/g4-fillorder-test.png') + g4 = Image.open('Tests/images/g4-fillorder-test.tif') - out = tempfile("temp.tif") - rot = orig.transpose(Image.ROTATE_90) - assert_equal(rot.size,(500,500)) - rot.save(out) + self.assert_image_equal(g4, png) - reread = Image.open(out) - assert_equal(reread.size,(500,500)) - _assert_noerr(reread) - assert_image_equal(reread, rot) - assert_equal(reread.info['compression'], 'group4') + def test_g4_write(self): + """Checking to see that the saved image is the same as what we wrote""" + file = "Tests/images/lena_g4_500.tif" + orig = Image.open(file) - assert_equal(reread.info['compression'], orig.info['compression']) - - assert_false(orig.tobytes() == reread.tobytes()) + out = self.tempfile("temp.tif") + rot = orig.transpose(Image.ROTATE_90) + self.assertEqual(rot.size, (500, 500)) + rot.save(out) -def test_adobe_deflate_tiff(): - file = "Tests/images/tiff_adobe_deflate.tif" - im = Image.open(file) + reread = Image.open(out) + self.assertEqual(reread.size, (500, 500)) + self._assert_noerr(reread) + self.assert_image_equal(reread, rot) + self.assertEqual(reread.info['compression'], 'group4') - assert_equal(im.mode, "RGB") - assert_equal(im.size, (278, 374)) - assert_equal(im.tile[0][:3], ('tiff_adobe_deflate', (0, 0, 278, 374), 0)) - assert_no_exception(lambda: im.load()) + self.assertEqual(reread.info['compression'], orig.info['compression']) -def test_write_metadata(): - """ Test metadata writing through libtiff """ - img = Image.open('Tests/images/lena_g4.tif') - f = tempfile('temp.tiff') + self.assertNotEqual(orig.tobytes(), reread.tobytes()) - img.save(f, tiffinfo = img.tag) + def test_adobe_deflate_tiff(self): + file = "Tests/images/tiff_adobe_deflate.tif" + im = Image.open(file) - loaded = Image.open(f) + self.assertEqual(im.mode, "RGB") + self.assertEqual(im.size, (278, 374)) + self.assertEqual( + im.tile[0][:3], ('tiff_adobe_deflate', (0, 0, 278, 374), 0)) + im.load() - original = img.tag.named() - reloaded = loaded.tag.named() + def test_write_metadata(self): + """ Test metadata writing through libtiff """ + img = Image.open('Tests/images/lena_g4.tif') + f = self.tempfile('temp.tiff') - # PhotometricInterpretation is set from SAVE_INFO, not the original image. - ignored = ['StripByteCounts', 'RowsPerStrip', 'PageNumber', 'PhotometricInterpretation'] + img.save(f, tiffinfo=img.tag) - for tag, value in reloaded.items(): - if tag not in ignored: - if tag.endswith('Resolution'): - val = original[tag] - assert_almost_equal(val[0][0]/val[0][1], value[0][0]/value[0][1], - msg="%s didn't roundtrip" % tag) - else: - assert_equal(original[tag], value, "%s didn't roundtrip" % tag) + loaded = Image.open(f) - for tag, value in original.items(): - if tag not in ignored: - if tag.endswith('Resolution'): - val = reloaded[tag] - assert_almost_equal(val[0][0]/val[0][1], value[0][0]/value[0][1], - msg="%s didn't roundtrip" % tag) - else: - assert_equal(value, reloaded[tag], "%s didn't roundtrip" % tag) + original = img.tag.named() + reloaded = loaded.tag.named() + # PhotometricInterpretation is set from SAVE_INFO, + # not the original image. + ignored = [ + 'StripByteCounts', 'RowsPerStrip', + 'PageNumber', 'PhotometricInterpretation'] -def test_g3_compression(): - i = Image.open('Tests/images/lena_g4_500.tif') - out = tempfile("temp.tif") - i.save(out, compression='group3') + for tag, value in reloaded.items(): + if tag not in ignored: + if tag.endswith('Resolution'): + val = original[tag] + self.assert_almost_equal( + val[0][0]/val[0][1], value[0][0]/value[0][1], + msg="%s didn't roundtrip" % tag) + else: + self.assertEqual( + original[tag], value, "%s didn't roundtrip" % tag) - reread = Image.open(out) - assert_equal(reread.info['compression'], 'group3') - assert_image_equal(reread, i) + for tag, value in original.items(): + if tag not in ignored: + if tag.endswith('Resolution'): + val = reloaded[tag] + self.assert_almost_equal( + val[0][0]/val[0][1], value[0][0]/value[0][1], + msg="%s didn't roundtrip" % tag) + else: + self.assertEqual( + value, reloaded[tag], "%s didn't roundtrip" % tag) -def test_little_endian(): - im = Image.open('Tests/images/16bit.deflate.tif') - assert_equal(im.getpixel((0,0)), 480) - assert_equal(im.mode, 'I;16') + def test_g3_compression(self): + i = Image.open('Tests/images/lena_g4_500.tif') + out = self.tempfile("temp.tif") + i.save(out, compression='group3') - b = im.tobytes() - # Bytes are in image native order (little endian) - if py3: - assert_equal(b[0], ord(b'\xe0')) - assert_equal(b[1], ord(b'\x01')) - else: - assert_equal(b[0], b'\xe0') - assert_equal(b[1], b'\x01') - + reread = Image.open(out) + self.assertEqual(reread.info['compression'], 'group3') + self.assert_image_equal(reread, i) - out = tempfile("temp.tif") - #out = "temp.le.tif" - im.save(out) - reread = Image.open(out) + def test_little_endian(self): + im = Image.open('Tests/images/16bit.deflate.tif') + self.assertEqual(im.getpixel((0, 0)), 480) + self.assertEqual(im.mode, 'I;16') - assert_equal(reread.info['compression'], im.info['compression']) - assert_equal(reread.getpixel((0,0)), 480) - # UNDONE - libtiff defaults to writing in native endian, so - # on big endian, we'll get back mode = 'I;16B' here. - -def test_big_endian(): - im = Image.open('Tests/images/16bit.MM.deflate.tif') + b = im.tobytes() + # Bytes are in image native order (little endian) + if py3: + self.assertEqual(b[0], ord(b'\xe0')) + self.assertEqual(b[1], ord(b'\x01')) + else: + self.assertEqual(b[0], b'\xe0') + self.assertEqual(b[1], b'\x01') - assert_equal(im.getpixel((0,0)), 480) - assert_equal(im.mode, 'I;16B') + out = self.tempfile("temp.tif") + # out = "temp.le.tif" + im.save(out) + reread = Image.open(out) - b = im.tobytes() + self.assertEqual(reread.info['compression'], im.info['compression']) + self.assertEqual(reread.getpixel((0, 0)), 480) + # UNDONE - libtiff defaults to writing in native endian, so + # on big endian, we'll get back mode = 'I;16B' here. - # Bytes are in image native order (big endian) - if py3: - assert_equal(b[0], ord(b'\x01')) - assert_equal(b[1], ord(b'\xe0')) - else: - assert_equal(b[0], b'\x01') - assert_equal(b[1], b'\xe0') - - out = tempfile("temp.tif") - im.save(out) - reread = Image.open(out) + def test_big_endian(self): + im = Image.open('Tests/images/16bit.MM.deflate.tif') - assert_equal(reread.info['compression'], im.info['compression']) - assert_equal(reread.getpixel((0,0)), 480) + self.assertEqual(im.getpixel((0, 0)), 480) + self.assertEqual(im.mode, 'I;16B') -def test_g4_string_info(): - """Tests String data in info directory""" - file = "Tests/images/lena_g4_500.tif" - orig = Image.open(file) - - out = tempfile("temp.tif") + b = im.tobytes() - orig.tag[269] = 'temp.tif' - orig.save(out) - - reread = Image.open(out) - assert_equal('temp.tif', reread.tag[269]) + # Bytes are in image native order (big endian) + if py3: + self.assertEqual(b[0], ord(b'\x01')) + self.assertEqual(b[1], ord(b'\xe0')) + else: + self.assertEqual(b[0], b'\x01') + self.assertEqual(b[1], b'\xe0') -def test_12bit_rawmode(): - """ Are we generating the same interpretation of the image as Imagemagick is? """ - TiffImagePlugin.READ_LIBTIFF = True - #Image.DEBUG = True - im = Image.open('Tests/images/12bit.cropped.tif') - im.load() - TiffImagePlugin.READ_LIBTIFF = False - # to make the target -- - # convert 12bit.cropped.tif -depth 16 tmp.tif - # convert tmp.tif -evaluate RightShift 4 12in16bit2.tif - # imagemagick will auto scale so that a 12bit FFF is 16bit FFF0, - # so we need to unshift so that the integer values are the same. - - im2 = Image.open('Tests/images/12in16bit.tif') + out = self.tempfile("temp.tif") + im.save(out) + reread = Image.open(out) - if Image.DEBUG: - print (im.getpixel((0,0))) - print (im.getpixel((0,1))) - print (im.getpixel((0,2))) + self.assertEqual(reread.info['compression'], im.info['compression']) + self.assertEqual(reread.getpixel((0, 0)), 480) - print (im2.getpixel((0,0))) - print (im2.getpixel((0,1))) - print (im2.getpixel((0,2))) - - assert_image_equal(im, im2) + def test_g4_string_info(self): + """Tests String data in info directory""" + file = "Tests/images/lena_g4_500.tif" + orig = Image.open(file) -def test_blur(): - # test case from irc, how to do blur on b/w image and save to compressed tif. - from PIL import ImageFilter - out = tempfile('temp.tif') - im = Image.open('Tests/images/pport_g4.tif') - im = im.convert('L') + out = self.tempfile("temp.tif") - im=im.filter(ImageFilter.GaussianBlur(4)) - im.save(out, compression='tiff_adobe_deflate') + orig.tag[269] = 'temp.tif' + orig.save(out) - im2 = Image.open(out) - im2.load() + reread = Image.open(out) + self.assertEqual('temp.tif', reread.tag[269]) - assert_image_equal(im, im2) + def test_12bit_rawmode(self): + """ Are we generating the same interpretation + of the image as Imagemagick is? """ + TiffImagePlugin.READ_LIBTIFF = True + # Image.DEBUG = True + im = Image.open('Tests/images/12bit.cropped.tif') + im.load() + TiffImagePlugin.READ_LIBTIFF = False + # to make the target -- + # convert 12bit.cropped.tif -depth 16 tmp.tif + # convert tmp.tif -evaluate RightShift 4 12in16bit2.tif + # imagemagick will auto scale so that a 12bit FFF is 16bit FFF0, + # so we need to unshift so that the integer values are the same. + im2 = Image.open('Tests/images/12in16bit.tif') -def test_compressions(): - im = lena('RGB') - out = tempfile('temp.tif') + if Image.DEBUG: + print (im.getpixel((0, 0))) + print (im.getpixel((0, 1))) + print (im.getpixel((0, 2))) + + print (im2.getpixel((0, 0))) + print (im2.getpixel((0, 1))) + print (im2.getpixel((0, 2))) + + self.assert_image_equal(im, im2) + + def test_blur(self): + # test case from irc, how to do blur on b/w image + # and save to compressed tif. + from PIL import ImageFilter + out = self.tempfile('temp.tif') + im = Image.open('Tests/images/pport_g4.tif') + im = im.convert('L') + + im = im.filter(ImageFilter.GaussianBlur(4)) + im.save(out, compression='tiff_adobe_deflate') - for compression in ('packbits', 'tiff_lzw'): - im.save(out, compression=compression) im2 = Image.open(out) - assert_image_equal(im, im2) + im2.load() - im.save(out, compression='jpeg') - im2 = Image.open(out) - assert_image_similar(im, im2, 30) - + self.assert_image_equal(im, im2) -def test_cmyk_save(): - im = lena('CMYK') - out = tempfile('temp.tif') + def test_compressions(self): + im = lena('RGB') + out = self.tempfile('temp.tif') - im.save(out, compression='tiff_adobe_deflate') - im2 = Image.open(out) - assert_image_equal(im, im2) + for compression in ('packbits', 'tiff_lzw'): + im.save(out, compression=compression) + im2 = Image.open(out) + self.assert_image_equal(im, im2) -def xtest_bw_compression_wRGB(): - """ This test passes, but when running all tests causes a failure due to - output on stderr from the error thrown by libtiff. We need to capture that - but not now""" - - im = lena('RGB') - out = tempfile('temp.tif') + im.save(out, compression='jpeg') + im2 = Image.open(out) + self.assert_image_similar(im, im2, 30) - assert_exception(IOError, lambda: im.save(out, compression='tiff_ccitt')) - assert_exception(IOError, lambda: im.save(out, compression='group3')) - assert_exception(IOError, lambda: im.save(out, compression='group4')) + def test_cmyk_save(self): + im = lena('CMYK') + out = self.tempfile('temp.tif') -def test_fp_leak(): - im = Image.open("Tests/images/lena_g4_500.tif") - fn = im.fp.fileno() + im.save(out, compression='tiff_adobe_deflate') + im2 = Image.open(out) + self.assert_image_equal(im, im2) - assert_no_exception(lambda: os.fstat(fn)) - im.load() # this should close it. - assert_exception(OSError, lambda: os.fstat(fn)) - im = None # this should force even more closed. - assert_exception(OSError, lambda: os.fstat(fn)) - assert_exception(OSError, lambda: os.close(fn)) + def xtest_bw_compression_wRGB(self): + """ This test passes, but when running all tests causes a failure due + to output on stderr from the error thrown by libtiff. We need to + capture that but not now""" + + im = lena('RGB') + out = self.tempfile('temp.tif') + + self.assertRaises( + IOError, lambda: im.save(out, compression='tiff_ccitt')) + self.assertRaises(IOError, lambda: im.save(out, compression='group3')) + self.assertRaises(IOError, lambda: im.save(out, compression='group4')) + + def test_fp_leak(self): + im = Image.open("Tests/images/lena_g4_500.tif") + fn = im.fp.fileno() + + os.fstat(fn) + im.load() # this should close it. + self.assertRaises(OSError, lambda: os.fstat(fn)) + im = None # this should force even more closed. + self.assertRaises(OSError, lambda: os.fstat(fn)) + self.assertRaises(OSError, lambda: os.close(fn)) + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_file_libtiff_small.py b/Tests/test_file_libtiff_small.py index 2ad71d6e6..acc2390c9 100644 --- a/Tests/test_file_libtiff_small.py +++ b/Tests/test_file_libtiff_small.py @@ -1,52 +1,56 @@ -from tester import * +from helper import unittest, tearDownModule from PIL import Image -from test_file_libtiff import _assert_noerr - -codecs = dir(Image.core) - -if "libtiff_encoder" not in codecs or "libtiff_decoder" not in codecs: - skip("tiff support not available") - -""" The small lena image was failing on open in the libtiff - decoder because the file pointer was set to the wrong place - by a spurious seek. It wasn't failing with the byteio method. - - It was fixed by forcing an lseek to the beginning of the - file just before reading in libtiff. These tests remain - to ensure that it stays fixed. """ +from test_file_libtiff import TestFileLibTiff -def test_g4_lena_file(): - """Testing the open file load path""" +class TestFileLibTiffSmall(TestFileLibTiff): - file = "Tests/images/lena_g4.tif" - with open(file,'rb') as f: - im = Image.open(f) + # Inherits TestFileLibTiff's setUp() and self._assert_noerr() - assert_equal(im.size, (128,128)) - _assert_noerr(im) + """ The small lena image was failing on open in the libtiff + decoder because the file pointer was set to the wrong place + by a spurious seek. It wasn't failing with the byteio method. -def test_g4_lena_bytesio(): - """Testing the bytesio loading code path""" - from io import BytesIO - file = "Tests/images/lena_g4.tif" - s = BytesIO() - with open(file,'rb') as f: - s.write(f.read()) - s.seek(0) - im = Image.open(s) + It was fixed by forcing an lseek to the beginning of the + file just before reading in libtiff. These tests remain + to ensure that it stays fixed. """ - assert_equal(im.size, (128,128)) - _assert_noerr(im) + def test_g4_lena_file(self): + """Testing the open file load path""" -def test_g4_lena(): - """The 128x128 lena image fails for some reason. Investigating""" + file = "Tests/images/lena_g4.tif" + with open(file, 'rb') as f: + im = Image.open(f) - file = "Tests/images/lena_g4.tif" - im = Image.open(file) + self.assertEqual(im.size, (128, 128)) + self._assert_noerr(im) - assert_equal(im.size, (128,128)) - _assert_noerr(im) + def test_g4_lena_bytesio(self): + """Testing the bytesio loading code path""" + from io import BytesIO + file = "Tests/images/lena_g4.tif" + s = BytesIO() + with open(file, 'rb') as f: + s.write(f.read()) + s.seek(0) + im = Image.open(s) + self.assertEqual(im.size, (128, 128)) + self._assert_noerr(im) + + def test_g4_lena(self): + """The 128x128 lena image fails for some reason. Investigating""" + + file = "Tests/images/lena_g4.tif" + im = Image.open(file) + + self.assertEqual(im.size, (128, 128)) + self._assert_noerr(im) + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_file_msp.py b/Tests/test_file_msp.py index 7ed200e43..2444879d1 100644 --- a/Tests/test_file_msp.py +++ b/Tests/test_file_msp.py @@ -1,15 +1,24 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule, lena from PIL import Image -def test_sanity(): - file = tempfile("temp.msp") +class TestFileMsp(PillowTestCase): - lena("1").save(file) + def test_sanity(self): - im = Image.open(file) - im.load() - assert_equal(im.mode, "1") - assert_equal(im.size, (128, 128)) - assert_equal(im.format, "MSP") + file = self.tempfile("temp.msp") + + lena("1").save(file) + + im = Image.open(file) + im.load() + self.assertEqual(im.mode, "1") + self.assertEqual(im.size, (128, 128)) + self.assertEqual(im.format, "MSP") + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_file_pcx.py b/Tests/test_file_pcx.py index cb785ec54..d0800e203 100644 --- a/Tests/test_file_pcx.py +++ b/Tests/test_file_pcx.py @@ -1,40 +1,47 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule, lena from PIL import Image -def _roundtrip(im): - f = tempfile("temp.pcx") - im.save(f) - im2 = Image.open(f) +class TestFilePcx(PillowTestCase): - assert_equal(im2.mode, im.mode) - assert_equal(im2.size, im.size) - assert_equal(im2.format, "PCX") - assert_image_equal(im2, im) - -def test_sanity(): - for mode in ('1', 'L', 'P', 'RGB'): - _roundtrip(lena(mode)) + def _roundtrip(self, im): + f = self.tempfile("temp.pcx") + im.save(f) + im2 = Image.open(f) -def test_odd(): - # see issue #523, odd sized images should have a stride that's even. - # not that imagemagick or gimp write pcx that way. - # we were not handling properly. - for mode in ('1', 'L', 'P', 'RGB'): - # larger, odd sized images are better here to ensure that - # we handle interrupted scan lines properly. - _roundtrip(lena(mode).resize((511,511))) - + self.assertEqual(im2.mode, im.mode) + self.assertEqual(im2.size, im.size) + self.assertEqual(im2.format, "PCX") + self.assert_image_equal(im2, im) -def test_pil184(): - # Check reading of files where xmin/xmax is not zero. + def test_sanity(self): + for mode in ('1', 'L', 'P', 'RGB'): + self._roundtrip(lena(mode)) - file = "Tests/images/pil184.pcx" - im = Image.open(file) + def test_odd(self): + # see issue #523, odd sized images should have a stride that's even. + # not that imagemagick or gimp write pcx that way. + # we were not handling properly. + for mode in ('1', 'L', 'P', 'RGB'): + # larger, odd sized images are better here to ensure that + # we handle interrupted scan lines properly. + self._roundtrip(lena(mode).resize((511, 511))) - assert_equal(im.size, (447, 144)) - assert_equal(im.tile[0][1], (0, 0, 447, 144)) + def test_pil184(self): + # Check reading of files where xmin/xmax is not zero. - # Make sure all pixels are either 0 or 255. - assert_equal(im.histogram()[0] + im.histogram()[255], 447*144) + file = "Tests/images/pil184.pcx" + im = Image.open(file) + + self.assertEqual(im.size, (447, 144)) + self.assertEqual(im.tile[0][1], (0, 0, 447, 144)) + + # Make sure all pixels are either 0 or 255. + self.assertEqual(im.histogram()[0] + im.histogram()[255], 447*144) + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_file_pdf.py b/Tests/test_file_pdf.py index e99f22db1..089168393 100644 --- a/Tests/test_file_pdf.py +++ b/Tests/test_file_pdf.py @@ -1,58 +1,59 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule, lena + import os.path -def helper_save_as_pdf(mode): - # Arrange - im = lena(mode) - outfile = tempfile("temp_" + mode + ".pdf") +class TestFilePdf(PillowTestCase): - # Act - im.save(outfile) + def helper_save_as_pdf(self, mode): + # Arrange + im = lena(mode) + outfile = self.tempfile("temp_" + mode + ".pdf") - # Assert - assert_true(os.path.isfile(outfile)) - assert_greater(os.path.getsize(outfile), 0) + # Act + im.save(outfile) + + # Assert + self.assertTrue(os.path.isfile(outfile)) + self.assertGreater(os.path.getsize(outfile), 0) + + def test_monochrome(self): + # Arrange + mode = "1" + + # Act / Assert + self.helper_save_as_pdf(mode) + + def test_greyscale(self): + # Arrange + mode = "L" + + # Act / Assert + self.helper_save_as_pdf(mode) + + def test_rgb(self): + # Arrange + mode = "RGB" + + # Act / Assert + self.helper_save_as_pdf(mode) + + def test_p_mode(self): + # Arrange + mode = "P" + + # Act / Assert + self.helper_save_as_pdf(mode) + + def test_cmyk_mode(self): + # Arrange + mode = "CMYK" + + # Act / Assert + self.helper_save_as_pdf(mode) -def test_monochrome(): - # Arrange - mode = "1" - - # Act / Assert - helper_save_as_pdf(mode) - - -def test_greyscale(): - # Arrange - mode = "L" - - # Act / Assert - helper_save_as_pdf(mode) - - -def test_rgb(): - # Arrange - mode = "RGB" - - # Act / Assert - helper_save_as_pdf(mode) - - -def test_p_mode(): - # Arrange - mode = "P" - - # Act / Assert - helper_save_as_pdf(mode) - - -def test_cmyk_mode(): - # Arrange - mode = "CMYK" - - # Act / Assert - helper_save_as_pdf(mode) - +if __name__ == '__main__': + unittest.main() # End of file diff --git a/Tests/test_file_png.py b/Tests/test_file_png.py index c17829194..6da61be6b 100644 --- a/Tests/test_file_png.py +++ b/Tests/test_file_png.py @@ -1,4 +1,6 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule, lena + +from io import BytesIO from PIL import Image from PIL import PngImagePlugin @@ -6,9 +8,6 @@ import zlib codecs = dir(Image.core) -if "zip_encoder" not in codecs or "zip_decoder" not in codecs: - skip("zip/deflate support not available") - # sample png stream file = "Images/lena.png" @@ -18,6 +17,7 @@ data = open(file, "rb").read() MAGIC = PngImagePlugin._MAGIC + def chunk(cid, *data): file = BytesIO() PngImagePlugin.putchunk(*(file, cid) + data) @@ -32,256 +32,268 @@ IEND = chunk(b"IEND") HEAD = MAGIC + IHDR TAIL = IDAT + IEND + def load(data): return Image.open(BytesIO(data)) + def roundtrip(im, **options): out = BytesIO() im.save(out, "PNG", **options) out.seek(0) return Image.open(out) -# -------------------------------------------------------------------- -def test_sanity(): +class TestFilePng(PillowTestCase): - # internal version number - assert_match(Image.core.zlib_version, "\d+\.\d+\.\d+(\.\d+)?$") + def setUp(self): + if "zip_encoder" not in codecs or "zip_decoder" not in codecs: + self.skipTest("zip/deflate support not available") - file = tempfile("temp.png") + def test_sanity(self): - lena("RGB").save(file) + # internal version number + self.assertRegexpMatches( + Image.core.zlib_version, "\d+\.\d+\.\d+(\.\d+)?$") - im = Image.open(file) - im.load() - assert_equal(im.mode, "RGB") - assert_equal(im.size, (128, 128)) - assert_equal(im.format, "PNG") + file = self.tempfile("temp.png") - lena("1").save(file) - im = Image.open(file) + lena("RGB").save(file) - lena("L").save(file) - im = Image.open(file) + im = Image.open(file) + im.load() + self.assertEqual(im.mode, "RGB") + self.assertEqual(im.size, (128, 128)) + self.assertEqual(im.format, "PNG") - lena("P").save(file) - im = Image.open(file) + lena("1").save(file) + im = Image.open(file) - lena("RGB").save(file) - im = Image.open(file) + lena("L").save(file) + im = Image.open(file) - lena("I").save(file) - im = Image.open(file) + lena("P").save(file) + im = Image.open(file) -# -------------------------------------------------------------------- + lena("RGB").save(file) + im = Image.open(file) -def test_broken(): - # Check reading of totally broken files. In this case, the test - # file was checked into Subversion as a text file. + lena("I").save(file) + im = Image.open(file) - file = "Tests/images/broken.png" - assert_exception(IOError, lambda: Image.open(file)) + def test_broken(self): + # Check reading of totally broken files. In this case, the test + # file was checked into Subversion as a text file. -def test_bad_text(): - # Make sure PIL can read malformed tEXt chunks (@PIL152) + file = "Tests/images/broken.png" + self.assertRaises(IOError, lambda: Image.open(file)) - im = load(HEAD + chunk(b'tEXt') + TAIL) - assert_equal(im.info, {}) + def test_bad_text(self): + # Make sure PIL can read malformed tEXt chunks (@PIL152) - im = load(HEAD + chunk(b'tEXt', b'spam') + TAIL) - assert_equal(im.info, {'spam': ''}) + im = load(HEAD + chunk(b'tEXt') + TAIL) + self.assertEqual(im.info, {}) - im = load(HEAD + chunk(b'tEXt', b'spam\0') + TAIL) - assert_equal(im.info, {'spam': ''}) + im = load(HEAD + chunk(b'tEXt', b'spam') + TAIL) + self.assertEqual(im.info, {'spam': ''}) - im = load(HEAD + chunk(b'tEXt', b'spam\0egg') + TAIL) - assert_equal(im.info, {'spam': 'egg'}) + im = load(HEAD + chunk(b'tEXt', b'spam\0') + TAIL) + self.assertEqual(im.info, {'spam': ''}) - im = load(HEAD + chunk(b'tEXt', b'spam\0egg\0') + TAIL) - assert_equal(im.info, {'spam': 'egg\x00'}) + im = load(HEAD + chunk(b'tEXt', b'spam\0egg') + TAIL) + self.assertEqual(im.info, {'spam': 'egg'}) -def test_bad_ztxt(): - # Test reading malformed zTXt chunks (python-imaging/Pillow#318) + im = load(HEAD + chunk(b'tEXt', b'spam\0egg\0') + TAIL) + self.assertEqual(im.info, {'spam': 'egg\x00'}) - im = load(HEAD + chunk(b'zTXt') + TAIL) - assert_equal(im.info, {}) + def test_bad_ztxt(self): + # Test reading malformed zTXt chunks (python-pillow/Pillow#318) - im = load(HEAD + chunk(b'zTXt', b'spam') + TAIL) - assert_equal(im.info, {'spam': ''}) + im = load(HEAD + chunk(b'zTXt') + TAIL) + self.assertEqual(im.info, {}) - im = load(HEAD + chunk(b'zTXt', b'spam\0') + TAIL) - assert_equal(im.info, {'spam': ''}) + im = load(HEAD + chunk(b'zTXt', b'spam') + TAIL) + self.assertEqual(im.info, {'spam': ''}) - im = load(HEAD + chunk(b'zTXt', b'spam\0\0') + TAIL) - assert_equal(im.info, {'spam': ''}) + im = load(HEAD + chunk(b'zTXt', b'spam\0') + TAIL) + self.assertEqual(im.info, {'spam': ''}) - im = load(HEAD + chunk(b'zTXt', b'spam\0\0' + zlib.compress(b'egg')[:1]) + TAIL) - assert_equal(im.info, {'spam': ''}) + im = load(HEAD + chunk(b'zTXt', b'spam\0\0') + TAIL) + self.assertEqual(im.info, {'spam': ''}) - im = load(HEAD + chunk(b'zTXt', b'spam\0\0' + zlib.compress(b'egg')) + TAIL) - assert_equal(im.info, {'spam': 'egg'}) + im = load(HEAD + chunk( + b'zTXt', b'spam\0\0' + zlib.compress(b'egg')[:1]) + TAIL) + self.assertEqual(im.info, {'spam': ''}) -def test_interlace(): + im = load( + HEAD + chunk(b'zTXt', b'spam\0\0' + zlib.compress(b'egg')) + TAIL) + self.assertEqual(im.info, {'spam': 'egg'}) - file = "Tests/images/pil123p.png" - im = Image.open(file) + def test_interlace(self): - assert_image(im, "P", (162, 150)) - assert_true(im.info.get("interlace")) + file = "Tests/images/pil123p.png" + im = Image.open(file) - assert_no_exception(lambda: im.load()) + self.assert_image(im, "P", (162, 150)) + self.assertTrue(im.info.get("interlace")) - file = "Tests/images/pil123rgba.png" - im = Image.open(file) + im.load() - assert_image(im, "RGBA", (162, 150)) - assert_true(im.info.get("interlace")) + file = "Tests/images/pil123rgba.png" + im = Image.open(file) - assert_no_exception(lambda: im.load()) + self.assert_image(im, "RGBA", (162, 150)) + self.assertTrue(im.info.get("interlace")) -def test_load_transparent_p(): - file = "Tests/images/pil123p.png" - im = Image.open(file) + im.load() - assert_image(im, "P", (162, 150)) - im = im.convert("RGBA") - assert_image(im, "RGBA", (162, 150)) + def test_load_transparent_p(self): + file = "Tests/images/pil123p.png" + im = Image.open(file) - # image has 124 uniqe qlpha values - assert_equal(len(im.split()[3].getcolors()), 124) + self.assert_image(im, "P", (162, 150)) + im = im.convert("RGBA") + self.assert_image(im, "RGBA", (162, 150)) -def test_load_transparent_rgb(): - file = "Tests/images/rgb_trns.png" - im = Image.open(file) + # image has 124 uniqe qlpha values + self.assertEqual(len(im.split()[3].getcolors()), 124) - assert_image(im, "RGB", (64, 64)) - im = im.convert("RGBA") - assert_image(im, "RGBA", (64, 64)) + def test_load_transparent_rgb(self): + file = "Tests/images/rgb_trns.png" + im = Image.open(file) - # image has 876 transparent pixels - assert_equal(im.split()[3].getcolors()[0][0], 876) + self.assert_image(im, "RGB", (64, 64)) + im = im.convert("RGBA") + self.assert_image(im, "RGBA", (64, 64)) -def test_save_p_transparent_palette(): - in_file = "Tests/images/pil123p.png" - im = Image.open(in_file) + # image has 876 transparent pixels + self.assertEqual(im.split()[3].getcolors()[0][0], 876) - file = tempfile("temp.png") - assert_no_exception(lambda: im.save(file)) + def test_save_p_transparent_palette(self): + in_file = "Tests/images/pil123p.png" + im = Image.open(in_file) -def test_save_p_single_transparency(): - in_file = "Tests/images/p_trns_single.png" - im = Image.open(in_file) + file = self.tempfile("temp.png") + im.save(file) - file = tempfile("temp.png") - assert_no_exception(lambda: im.save(file)) + def test_save_p_single_transparency(self): + in_file = "Tests/images/p_trns_single.png" + im = Image.open(in_file) -def test_save_l_transparency(): - in_file = "Tests/images/l_trns.png" - im = Image.open(in_file) + file = self.tempfile("temp.png") + im.save(file) - file = tempfile("temp.png") - assert_no_exception(lambda: im.save(file)) + def test_save_l_transparency(self): + in_file = "Tests/images/l_trns.png" + im = Image.open(in_file) - # There are 559 transparent pixels. - im = im.convert('RGBA') - assert_equal(im.split()[3].getcolors()[0][0], 559) + file = self.tempfile("temp.png") + im.save(file) -def test_save_rgb_single_transparency(): - in_file = "Tests/images/caption_6_33_22.png" - im = Image.open(in_file) + # There are 559 transparent pixels. + im = im.convert('RGBA') + self.assertEqual(im.split()[3].getcolors()[0][0], 559) - file = tempfile("temp.png") - assert_no_exception(lambda: im.save(file)) + def test_save_rgb_single_transparency(self): + in_file = "Tests/images/caption_6_33_22.png" + im = Image.open(in_file) -def test_load_verify(): - # Check open/load/verify exception (@PIL150) + file = self.tempfile("temp.png") + im.save(file) - im = Image.open("Images/lena.png") - assert_no_exception(lambda: im.verify()) + def test_load_verify(self): + # Check open/load/verify exception (@PIL150) - im = Image.open("Images/lena.png") - im.load() - assert_exception(RuntimeError, lambda: im.verify()) + im = Image.open("Images/lena.png") + im.verify() -def test_roundtrip_dpi(): - # Check dpi roundtripping + im = Image.open("Images/lena.png") + im.load() + self.assertRaises(RuntimeError, lambda: im.verify()) - im = Image.open(file) + def test_roundtrip_dpi(self): + # Check dpi roundtripping - im = roundtrip(im, dpi=(100, 100)) - assert_equal(im.info["dpi"], (100, 100)) + im = Image.open(file) -def test_roundtrip_text(): - # Check text roundtripping + im = roundtrip(im, dpi=(100, 100)) + self.assertEqual(im.info["dpi"], (100, 100)) - im = Image.open(file) + def test_roundtrip_text(self): + # Check text roundtripping - info = PngImagePlugin.PngInfo() - info.add_text("TXT", "VALUE") - info.add_text("ZIP", "VALUE", 1) + im = Image.open(file) - im = roundtrip(im, pnginfo=info) - assert_equal(im.info, {'TXT': 'VALUE', 'ZIP': 'VALUE'}) - assert_equal(im.text, {'TXT': 'VALUE', 'ZIP': 'VALUE'}) + info = PngImagePlugin.PngInfo() + info.add_text("TXT", "VALUE") + info.add_text("ZIP", "VALUE", 1) -def test_scary(): - # Check reading of evil PNG file. For information, see: - # http://scary.beasts.org/security/CESA-2004-001.txt - # The first byte is removed from pngtest_bad.png - # to avoid classification as malware. + im = roundtrip(im, pnginfo=info) + self.assertEqual(im.info, {'TXT': 'VALUE', 'ZIP': 'VALUE'}) + self.assertEqual(im.text, {'TXT': 'VALUE', 'ZIP': 'VALUE'}) - with open("Tests/images/pngtest_bad.png.bin", 'rb') as fd: - data = b'\x89' + fd.read() + def test_scary(self): + # Check reading of evil PNG file. For information, see: + # http://scary.beasts.org/security/CESA-2004-001.txt + # The first byte is removed from pngtest_bad.png + # to avoid classification as malware. - pngfile = BytesIO(data) - assert_exception(IOError, lambda: Image.open(pngfile)) + with open("Tests/images/pngtest_bad.png.bin", 'rb') as fd: + data = b'\x89' + fd.read() -def test_trns_rgb(): - # Check writing and reading of tRNS chunks for RGB images. - # Independent file sample provided by Sebastian Spaeth. + pngfile = BytesIO(data) + self.assertRaises(IOError, lambda: Image.open(pngfile)) - file = "Tests/images/caption_6_33_22.png" - im = Image.open(file) - assert_equal(im.info["transparency"], (248, 248, 248)) + def test_trns_rgb(self): + # Check writing and reading of tRNS chunks for RGB images. + # Independent file sample provided by Sebastian Spaeth. - # check saving transparency by default - im = roundtrip(im) - assert_equal(im.info["transparency"], (248, 248, 248)) + file = "Tests/images/caption_6_33_22.png" + im = Image.open(file) + self.assertEqual(im.info["transparency"], (248, 248, 248)) - im = roundtrip(im, transparency=(0, 1, 2)) - assert_equal(im.info["transparency"], (0, 1, 2)) + # check saving transparency by default + im = roundtrip(im) + self.assertEqual(im.info["transparency"], (248, 248, 248)) -def test_trns_p(): - # Check writing a transparency of 0, issue #528 - im = lena('P') - im.info['transparency']=0 - - f = tempfile("temp.png") - im.save(f) + im = roundtrip(im, transparency=(0, 1, 2)) + self.assertEqual(im.info["transparency"], (0, 1, 2)) - im2 = Image.open(f) - assert_true('transparency' in im2.info) + def test_trns_p(self): + # Check writing a transparency of 0, issue #528 + im = lena('P') + im.info['transparency'] = 0 - assert_image_equal(im2.convert('RGBA'), im.convert('RGBA')) - - -def test_save_icc_profile_none(): - # check saving files with an ICC profile set to None (omit profile) - in_file = "Tests/images/icc_profile_none.png" - im = Image.open(in_file) - assert_equal(im.info['icc_profile'], None) + f = self.tempfile("temp.png") + im.save(f) - im = roundtrip(im) - assert_false('icc_profile' in im.info) + im2 = Image.open(f) + self.assertIn('transparency', im2.info) -def test_roundtrip_icc_profile(): - # check that we can roundtrip the icc profile - im = lena('RGB') + self.assert_image_equal(im2.convert('RGBA'), im.convert('RGBA')) - jpeg_image = Image.open('Tests/images/flower2.jpg') - expected_icc = jpeg_image.info['icc_profile'] + def test_save_icc_profile_none(self): + # check saving files with an ICC profile set to None (omit profile) + in_file = "Tests/images/icc_profile_none.png" + im = Image.open(in_file) + self.assertEqual(im.info['icc_profile'], None) - im.info['icc_profile'] = expected_icc - im = roundtrip(im) - assert_equal(im.info['icc_profile'], expected_icc) + im = roundtrip(im) + self.assertNotIn('icc_profile', im.info) + def test_roundtrip_icc_profile(self): + # check that we can roundtrip the icc profile + im = lena('RGB') + + jpeg_image = Image.open('Tests/images/flower2.jpg') + expected_icc = jpeg_image.info['icc_profile'] + + im.info['icc_profile'] = expected_icc + im = roundtrip(im) + self.assertEqual(im.info['icc_profile'], expected_icc) + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_file_ppm.py b/Tests/test_file_ppm.py index 34136a83c..9d5dd806a 100644 --- a/Tests/test_file_ppm.py +++ b/Tests/test_file_ppm.py @@ -1,4 +1,4 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule from PIL import Image @@ -6,31 +6,37 @@ from PIL import Image file = "Images/lena.ppm" data = open(file, "rb").read() -def test_sanity(): - im = Image.open(file) - im.load() - assert_equal(im.mode, "RGB") - assert_equal(im.size, (128, 128)) - assert_equal(im.format, "PPM") -def test_16bit_pgm(): - im = Image.open('Tests/images/16_bit_binary.pgm') - im.load() - assert_equal(im.mode, 'I') - assert_equal(im.size, (20,100)) +class TestFilePpm(PillowTestCase): - tgt = Image.open('Tests/images/16_bit_binary_pgm.png') - assert_image_equal(im, tgt) + def test_sanity(self): + im = Image.open(file) + im.load() + self.assertEqual(im.mode, "RGB") + self.assertEqual(im.size, (128, 128)) + self.assertEqual(im.format, "PPM") + + def test_16bit_pgm(self): + im = Image.open('Tests/images/16_bit_binary.pgm') + im.load() + self.assertEqual(im.mode, 'I') + self.assertEqual(im.size, (20, 100)) + + tgt = Image.open('Tests/images/16_bit_binary_pgm.png') + self.assert_image_equal(im, tgt) + + def test_16bit_pgm_write(self): + im = Image.open('Tests/images/16_bit_binary.pgm') + im.load() + + f = self.tempfile('temp.pgm') + im.save(f, 'PPM') + + reloaded = Image.open(f) + self.assert_image_equal(im, reloaded) -def test_16bit_pgm_write(): - im = Image.open('Tests/images/16_bit_binary.pgm') - im.load() - - f = tempfile('temp.pgm') - assert_no_exception(lambda: im.save(f, 'PPM')) - - reloaded = Image.open(f) - assert_image_equal(im, reloaded) - +if __name__ == '__main__': + unittest.main() +# End of file diff --git a/Tests/test_file_psd.py b/Tests/test_file_psd.py index ef2d40594..e7f86fd98 100644 --- a/Tests/test_file_psd.py +++ b/Tests/test_file_psd.py @@ -1,4 +1,4 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule from PIL import Image @@ -6,9 +6,18 @@ from PIL import Image file = "Images/lena.psd" data = open(file, "rb").read() -def test_sanity(): - im = Image.open(file) - im.load() - assert_equal(im.mode, "RGB") - assert_equal(im.size, (128, 128)) - assert_equal(im.format, "PSD") + +class TestImagePsd(PillowTestCase): + + def test_sanity(self): + im = Image.open(file) + im.load() + self.assertEqual(im.mode, "RGB") + self.assertEqual(im.size, (128, 128)) + self.assertEqual(im.format, "PSD") + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_file_spider.py b/Tests/test_file_spider.py new file mode 100644 index 000000000..e0731ca8c --- /dev/null +++ b/Tests/test_file_spider.py @@ -0,0 +1,39 @@ +from helper import unittest, PillowTestCase, tearDownModule, lena + +from PIL import Image +from PIL import SpiderImagePlugin + +test_file = "Tests/images/lena.spider" + + +class TestImageSpider(PillowTestCase): + + def test_sanity(self): + im = Image.open(test_file) + im.load() + self.assertEqual(im.mode, "F") + self.assertEqual(im.size, (128, 128)) + self.assertEqual(im.format, "SPIDER") + + def test_save(self): + # Arrange + temp = self.tempfile('temp.spider') + im = lena() + + # Act + im.save(temp, "SPIDER") + + # Assert + im2 = Image.open(temp) + self.assertEqual(im2.mode, "F") + self.assertEqual(im2.size, (128, 128)) + self.assertEqual(im2.format, "SPIDER") + + def test_isSpiderImage(self): + self.assertTrue(SpiderImagePlugin.isSpiderImage(test_file)) + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_file_tar.py b/Tests/test_file_tar.py index fa33d3802..36a625add 100644 --- a/Tests/test_file_tar.py +++ b/Tests/test_file_tar.py @@ -1,28 +1,38 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule from PIL import Image, TarIO codecs = dir(Image.core) -if "zip_decoder" not in codecs and "jpeg_decoder" not in codecs: - skip("neither jpeg nor zip support not available") # sample ppm stream tarfile = "Images/lena.tar" -def test_sanity(): - if "zip_decoder" in codecs: - tar = TarIO.TarIO(tarfile, 'lena.png') - im = Image.open(tar) - im.load() - assert_equal(im.mode, "RGB") - assert_equal(im.size, (128, 128)) - assert_equal(im.format, "PNG") - if "jpeg_decoder" in codecs: - tar = TarIO.TarIO(tarfile, 'lena.jpg') - im = Image.open(tar) - im.load() - assert_equal(im.mode, "RGB") - assert_equal(im.size, (128, 128)) - assert_equal(im.format, "JPEG") +class TestFileTar(PillowTestCase): + def setUp(self): + if "zip_decoder" not in codecs and "jpeg_decoder" not in codecs: + self.skipTest("neither jpeg nor zip support not available") + + def test_sanity(self): + if "zip_decoder" in codecs: + tar = TarIO.TarIO(tarfile, 'lena.png') + im = Image.open(tar) + im.load() + self.assertEqual(im.mode, "RGB") + self.assertEqual(im.size, (128, 128)) + self.assertEqual(im.format, "PNG") + + if "jpeg_decoder" in codecs: + tar = TarIO.TarIO(tarfile, 'lena.jpg') + im = Image.open(tar) + im.load() + self.assertEqual(im.mode, "RGB") + self.assertEqual(im.size, (128, 128)) + self.assertEqual(im.format, "JPEG") + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_file_tiff.py b/Tests/test_file_tiff.py index 804ae04e4..ed3d1e9cd 100644 --- a/Tests/test_file_tiff.py +++ b/Tests/test_file_tiff.py @@ -1,141 +1,148 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule, lena, py3 from PIL import Image -def test_sanity(): - file = tempfile("temp.tif") +class TestFileTiff(PillowTestCase): - lena("RGB").save(file) + def test_sanity(self): - im = Image.open(file) - im.load() - assert_equal(im.mode, "RGB") - assert_equal(im.size, (128, 128)) - assert_equal(im.format, "TIFF") + file = self.tempfile("temp.tif") - lena("1").save(file) - im = Image.open(file) + lena("RGB").save(file) - lena("L").save(file) - im = Image.open(file) + im = Image.open(file) + im.load() + self.assertEqual(im.mode, "RGB") + self.assertEqual(im.size, (128, 128)) + self.assertEqual(im.format, "TIFF") - lena("P").save(file) - im = Image.open(file) + lena("1").save(file) + im = Image.open(file) - lena("RGB").save(file) - im = Image.open(file) + lena("L").save(file) + im = Image.open(file) - lena("I").save(file) - im = Image.open(file) + lena("P").save(file) + im = Image.open(file) -def test_mac_tiff(): - # Read RGBa images from Mac OS X [@PIL136] + lena("RGB").save(file) + im = Image.open(file) - file = "Tests/images/pil136.tiff" - im = Image.open(file) + lena("I").save(file) + im = Image.open(file) - assert_equal(im.mode, "RGBA") - assert_equal(im.size, (55, 43)) - assert_equal(im.tile, [('raw', (0, 0, 55, 43), 8, ('RGBa', 0, 1))]) - assert_no_exception(lambda: im.load()) + def test_mac_tiff(self): + # Read RGBa images from Mac OS X [@PIL136] -def test_gimp_tiff(): - # Read TIFF JPEG images from GIMP [@PIL168] + file = "Tests/images/pil136.tiff" + im = Image.open(file) - codecs = dir(Image.core) - if "jpeg_decoder" not in codecs: - skip("jpeg support not available") + self.assertEqual(im.mode, "RGBA") + self.assertEqual(im.size, (55, 43)) + self.assertEqual(im.tile, [('raw', (0, 0, 55, 43), 8, ('RGBa', 0, 1))]) + im.load() - file = "Tests/images/pil168.tif" - im = Image.open(file) + def test_gimp_tiff(self): + # Read TIFF JPEG images from GIMP [@PIL168] - assert_equal(im.mode, "RGB") - assert_equal(im.size, (256, 256)) - assert_equal(im.tile, [ - ('jpeg', (0, 0, 256, 64), 8, ('RGB', '')), - ('jpeg', (0, 64, 256, 128), 1215, ('RGB', '')), - ('jpeg', (0, 128, 256, 192), 2550, ('RGB', '')), - ('jpeg', (0, 192, 256, 256), 3890, ('RGB', '')), - ]) - assert_no_exception(lambda: im.load()) + codecs = dir(Image.core) + if "jpeg_decoder" not in codecs: + self.skipTest("jpeg support not available") -def test_xyres_tiff(): - from PIL.TiffImagePlugin import X_RESOLUTION, Y_RESOLUTION - file = "Tests/images/pil168.tif" - im = Image.open(file) - assert isinstance(im.tag.tags[X_RESOLUTION][0], tuple) - assert isinstance(im.tag.tags[Y_RESOLUTION][0], tuple) - #Try to read a file where X,Y_RESOLUTION are ints - im.tag.tags[X_RESOLUTION] = (72,) - im.tag.tags[Y_RESOLUTION] = (72,) - im._setup() - assert_equal(im.info['dpi'], (72., 72.)) + file = "Tests/images/pil168.tif" + im = Image.open(file) + + self.assertEqual(im.mode, "RGB") + self.assertEqual(im.size, (256, 256)) + self.assertEqual( + im.tile, [ + ('jpeg', (0, 0, 256, 64), 8, ('RGB', '')), + ('jpeg', (0, 64, 256, 128), 1215, ('RGB', '')), + ('jpeg', (0, 128, 256, 192), 2550, ('RGB', '')), + ('jpeg', (0, 192, 256, 256), 3890, ('RGB', '')), + ]) + im.load() + + def test_xyres_tiff(self): + from PIL.TiffImagePlugin import X_RESOLUTION, Y_RESOLUTION + file = "Tests/images/pil168.tif" + im = Image.open(file) + assert isinstance(im.tag.tags[X_RESOLUTION][0], tuple) + assert isinstance(im.tag.tags[Y_RESOLUTION][0], tuple) + # Try to read a file where X,Y_RESOLUTION are ints + im.tag.tags[X_RESOLUTION] = (72,) + im.tag.tags[Y_RESOLUTION] = (72,) + im._setup() + self.assertEqual(im.info['dpi'], (72., 72.)) + + def test_little_endian(self): + im = Image.open('Tests/images/16bit.cropped.tif') + self.assertEqual(im.getpixel((0, 0)), 480) + self.assertEqual(im.mode, 'I;16') + + b = im.tobytes() + # Bytes are in image native order (little endian) + if py3: + self.assertEqual(b[0], ord(b'\xe0')) + self.assertEqual(b[1], ord(b'\x01')) + else: + self.assertEqual(b[0], b'\xe0') + self.assertEqual(b[1], b'\x01') + + def test_big_endian(self): + im = Image.open('Tests/images/16bit.MM.cropped.tif') + self.assertEqual(im.getpixel((0, 0)), 480) + self.assertEqual(im.mode, 'I;16B') + + b = im.tobytes() + + # Bytes are in image native order (big endian) + if py3: + self.assertEqual(b[0], ord(b'\x01')) + self.assertEqual(b[1], ord(b'\xe0')) + else: + self.assertEqual(b[0], b'\x01') + self.assertEqual(b[1], b'\xe0') + + def test_12bit_rawmode(self): + """ Are we generating the same interpretation + of the image as Imagemagick is? """ + + # Image.DEBUG = True + im = Image.open('Tests/images/12bit.cropped.tif') + + # to make the target -- + # convert 12bit.cropped.tif -depth 16 tmp.tif + # convert tmp.tif -evaluate RightShift 4 12in16bit2.tif + # imagemagick will auto scale so that a 12bit FFF is 16bit FFF0, + # so we need to unshift so that the integer values are the same. + + im2 = Image.open('Tests/images/12in16bit.tif') + + if Image.DEBUG: + print (im.getpixel((0, 0))) + print (im.getpixel((0, 1))) + print (im.getpixel((0, 2))) + + print (im2.getpixel((0, 0))) + print (im2.getpixel((0, 1))) + print (im2.getpixel((0, 2))) + + self.assert_image_equal(im, im2) + + def test_32bit_float(self): + # Issue 614, specific 32 bit float format + path = 'Tests/images/10ct_32bit_128.tiff' + im = Image.open(path) + im.load() + + self.assertEqual(im.getpixel((0, 0)), -0.4526388943195343) + self.assertEqual( + im.getextrema(), (-3.140936851501465, 3.140684127807617)) -def test_little_endian(): - im = Image.open('Tests/images/16bit.cropped.tif') - assert_equal(im.getpixel((0,0)), 480) - assert_equal(im.mode, 'I;16') +if __name__ == '__main__': + unittest.main() - b = im.tobytes() - # Bytes are in image native order (little endian) - if py3: - assert_equal(b[0], ord(b'\xe0')) - assert_equal(b[1], ord(b'\x01')) - else: - assert_equal(b[0], b'\xe0') - assert_equal(b[1], b'\x01') - - -def test_big_endian(): - im = Image.open('Tests/images/16bit.MM.cropped.tif') - assert_equal(im.getpixel((0,0)), 480) - assert_equal(im.mode, 'I;16B') - - b = im.tobytes() - - # Bytes are in image native order (big endian) - if py3: - assert_equal(b[0], ord(b'\x01')) - assert_equal(b[1], ord(b'\xe0')) - else: - assert_equal(b[0], b'\x01') - assert_equal(b[1], b'\xe0') - - -def test_12bit_rawmode(): - """ Are we generating the same interpretation of the image as Imagemagick is? """ - - #Image.DEBUG = True - im = Image.open('Tests/images/12bit.cropped.tif') - - # to make the target -- - # convert 12bit.cropped.tif -depth 16 tmp.tif - # convert tmp.tif -evaluate RightShift 4 12in16bit2.tif - # imagemagick will auto scale so that a 12bit FFF is 16bit FFF0, - # so we need to unshift so that the integer values are the same. - - im2 = Image.open('Tests/images/12in16bit.tif') - - if Image.DEBUG: - print (im.getpixel((0,0))) - print (im.getpixel((0,1))) - print (im.getpixel((0,2))) - - print (im2.getpixel((0,0))) - print (im2.getpixel((0,1))) - print (im2.getpixel((0,2))) - - assert_image_equal(im, im2) - -def test_32bit_float(): - # Issue 614, specific 32 bit float format - path = 'Tests/images/10ct_32bit_128.tiff' - im = Image.open(path) - im.load() - - assert_equal(im.getpixel((0,0)), -0.4526388943195343) - assert_equal(im.getextrema(), (-3.140936851501465, 3.140684127807617)) - - +# End of file diff --git a/Tests/test_file_tiff_metadata.py b/Tests/test_file_tiff_metadata.py index 354eb972f..2019f3455 100644 --- a/Tests/test_file_tiff_metadata.py +++ b/Tests/test_file_tiff_metadata.py @@ -1,80 +1,93 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule, lena + from PIL import Image, TiffImagePlugin, TiffTags tag_ids = dict(zip(TiffTags.TAGS.values(), TiffTags.TAGS.keys())) -def test_rt_metadata(): - """ Test writing arbitray metadata into the tiff image directory - Use case is ImageJ private tags, one numeric, one arbitrary - data. https://github.com/python-imaging/Pillow/issues/291 - """ - - img = lena() - textdata = "This is some arbitrary metadata for a text field" - info = TiffImagePlugin.ImageFileDirectory() +class TestFileTiffMetadata(PillowTestCase): - info[tag_ids['ImageJMetaDataByteCounts']] = len(textdata) - info[tag_ids['ImageJMetaData']] = textdata + def test_rt_metadata(self): + """ Test writing arbitray metadata into the tiff image directory + Use case is ImageJ private tags, one numeric, one arbitrary + data. https://github.com/python-pillow/Pillow/issues/291 + """ - f = tempfile("temp.tif") + img = lena() - img.save(f, tiffinfo=info) - - loaded = Image.open(f) + textdata = "This is some arbitrary metadata for a text field" + info = TiffImagePlugin.ImageFileDirectory() - assert_equal(loaded.tag[50838], (len(textdata),)) - assert_equal(loaded.tag[50839], textdata) - -def test_read_metadata(): - img = Image.open('Tests/images/lena_g4.tif') - - known = {'YResolution': ((1207959552, 16777216),), - 'PlanarConfiguration': (1,), - 'BitsPerSample': (1,), - 'ImageLength': (128,), - 'Compression': (4,), - 'FillOrder': (1,), - 'DocumentName': 'lena.g4.tif', - 'RowsPerStrip': (128,), - 'ResolutionUnit': (1,), - 'PhotometricInterpretation': (0,), - 'PageNumber': (0, 1), - 'XResolution': ((1207959552, 16777216),), - 'ImageWidth': (128,), - 'Orientation': (1,), - 'StripByteCounts': (1796,), - 'SamplesPerPixel': (1,), - 'StripOffsets': (8,), - 'Software': 'ImageMagick 6.5.7-8 2012-08-17 Q16 http://www.imagemagick.org'} + info[tag_ids['ImageJMetaDataByteCounts']] = len(textdata) + info[tag_ids['ImageJMetaData']] = textdata - # assert_equal is equivalent, but less helpful in telling what's wrong. - named = img.tag.named() - for tag, value in named.items(): - assert_equal(known[tag], value) + f = self.tempfile("temp.tif") - for tag, value in known.items(): - assert_equal(value, named[tag]) + img.save(f, tiffinfo=info) + + loaded = Image.open(f) + + self.assertEqual(loaded.tag[50838], (len(textdata),)) + self.assertEqual(loaded.tag[50839], textdata) + + def test_read_metadata(self): + img = Image.open('Tests/images/lena_g4.tif') + + known = {'YResolution': ((1207959552, 16777216),), + 'PlanarConfiguration': (1,), + 'BitsPerSample': (1,), + 'ImageLength': (128,), + 'Compression': (4,), + 'FillOrder': (1,), + 'DocumentName': 'lena.g4.tif', + 'RowsPerStrip': (128,), + 'ResolutionUnit': (1,), + 'PhotometricInterpretation': (0,), + 'PageNumber': (0, 1), + 'XResolution': ((1207959552, 16777216),), + 'ImageWidth': (128,), + 'Orientation': (1,), + 'StripByteCounts': (1796,), + 'SamplesPerPixel': (1,), + 'StripOffsets': (8,), + 'Software': 'ImageMagick 6.5.7-8 2012-08-17 Q16 http://www.imagemagick.org'} + + # self.assertEqual is equivalent, + # but less helpful in telling what's wrong. + named = img.tag.named() + for tag, value in named.items(): + self.assertEqual(known[tag], value) + + for tag, value in known.items(): + self.assertEqual(value, named[tag]) + + def test_write_metadata(self): + """ Test metadata writing through the python code """ + img = Image.open('Tests/images/lena.tif') + + f = self.tempfile('temp.tiff') + img.save(f, tiffinfo=img.tag) + + loaded = Image.open(f) + + original = img.tag.named() + reloaded = loaded.tag.named() + + ignored = [ + 'StripByteCounts', 'RowsPerStrip', 'PageNumber', 'StripOffsets'] + + for tag, value in reloaded.items(): + if tag not in ignored: + self.assertEqual( + original[tag], value, "%s didn't roundtrip" % tag) + + for tag, value in original.items(): + if tag not in ignored: + self.assertEqual( + value, reloaded[tag], "%s didn't roundtrip" % tag) -def test_write_metadata(): - """ Test metadata writing through the python code """ - img = Image.open('Tests/images/lena.tif') +if __name__ == '__main__': + unittest.main() - f = tempfile('temp.tiff') - img.save(f, tiffinfo = img.tag) - - loaded = Image.open(f) - - original = img.tag.named() - reloaded = loaded.tag.named() - - ignored = ['StripByteCounts', 'RowsPerStrip', 'PageNumber', 'StripOffsets'] - - for tag, value in reloaded.items(): - if tag not in ignored: - assert_equal(original[tag], value, "%s didn't roundtrip" % tag) - - for tag, value in original.items(): - if tag not in ignored: - assert_equal(value, reloaded[tag], "%s didn't roundtrip" % tag) +# End of file diff --git a/Tests/test_file_webp.py b/Tests/test_file_webp.py index a89dea3c4..ea1c2e19f 100644 --- a/Tests/test_file_webp.py +++ b/Tests/test_file_webp.py @@ -1,68 +1,79 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule, lena from PIL import Image - try: from PIL import _webp except: - skip('webp support not installed') + # Skip in setUp() + pass -def test_version(): - assert_no_exception(lambda: _webp.WebPDecoderVersion()) - assert_no_exception(lambda: _webp.WebPDecoderBuggyAlpha()) +class TestFileWebp(PillowTestCase): -def test_read_rgb(): + def setUp(self): + try: + from PIL import _webp + except: + self.skipTest('WebP support not installed') - file_path = "Images/lena.webp" - image = Image.open(file_path) + def test_version(self): + _webp.WebPDecoderVersion() + _webp.WebPDecoderBuggyAlpha() - assert_equal(image.mode, "RGB") - assert_equal(image.size, (128, 128)) - assert_equal(image.format, "WEBP") - assert_no_exception(lambda: image.load()) - assert_no_exception(lambda: image.getdata()) - - # generated with: dwebp -ppm ../../Images/lena.webp -o lena_webp_bits.ppm - target = Image.open('Tests/images/lena_webp_bits.ppm') - assert_image_similar(image, target, 20.0) - - -def test_write_rgb(): - """ - Can we write a RGB mode file to webp without error. Does it have the bits we - expect? - - """ - - temp_file = tempfile("temp.webp") - - lena("RGB").save(temp_file) - - image = Image.open(temp_file) - image.load() - - assert_equal(image.mode, "RGB") - assert_equal(image.size, (128, 128)) - assert_equal(image.format, "WEBP") - assert_no_exception(lambda: image.load()) - assert_no_exception(lambda: image.getdata()) - - # If we're using the exact same version of webp, this test should pass. - # but it doesn't if the webp is generated on Ubuntu and tested on Fedora. - - # generated with: dwebp -ppm temp.webp -o lena_webp_write.ppm - #target = Image.open('Tests/images/lena_webp_write.ppm') - #assert_image_equal(image, target) - - # This test asserts that the images are similar. If the average pixel difference - # between the two images is less than the epsilon value, then we're going to - # accept that it's a reasonable lossy version of the image. The included lena images - # for webp are showing ~16 on Ubuntu, the jpegs are showing ~18. - target = lena("RGB") - assert_image_similar(image, target, 20.0) + def test_read_rgb(self): + file_path = "Images/lena.webp" + image = Image.open(file_path) + + self.assertEqual(image.mode, "RGB") + self.assertEqual(image.size, (128, 128)) + self.assertEqual(image.format, "WEBP") + image.load() + image.getdata() + + # generated with: + # dwebp -ppm ../../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) + + def test_write_rgb(self): + """ + Can we write a RGB mode file to webp without error. + Does it have the bits we expect? + """ + + temp_file = self.tempfile("temp.webp") + + lena("RGB").save(temp_file) + + image = Image.open(temp_file) + image.load() + + self.assertEqual(image.mode, "RGB") + self.assertEqual(image.size, (128, 128)) + self.assertEqual(image.format, "WEBP") + image.load() + image.getdata() + + # If we're using the exact same version of WebP, this test should pass. + # but it doesn't if the WebP is generated on Ubuntu and tested on + # Fedora. + + # generated with: dwebp -ppm temp.webp -o lena_webp_write.ppm + # target = Image.open('Tests/images/lena_webp_write.ppm') + # self.assert_image_equal(image, target) + + # This test asserts that the images are similar. If the average pixel + # difference between the two images is less than the epsilon value, + # then we're going to accept that it's a reasonable lossy version of + # the image. The included lena images for WebP are showing ~16 on + # Ubuntu, the jpegs are showing ~18. + target = lena("RGB") + self.assert_image_similar(image, target, 20.0) +if __name__ == '__main__': + unittest.main() +# End of file diff --git a/Tests/test_file_webp_alpha.py b/Tests/test_file_webp_alpha.py index 5ac03b9d4..c9787c60e 100644 --- a/Tests/test_file_webp_alpha.py +++ b/Tests/test_file_webp_alpha.py @@ -1,82 +1,91 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule, lena from PIL import Image try: from PIL import _webp except: - skip('webp support not installed') + pass + # Skip in setUp() -if _webp.WebPDecoderBuggyAlpha(): - skip("Buggy early version of webp installed, not testing transparency") +class TestFileWebpAlpha(PillowTestCase): -def test_read_rgba(): - # Generated with `cwebp transparent.png -o transparent.webp` - file_path = "Images/transparent.webp" - image = Image.open(file_path) + def setUp(self): + try: + from PIL import _webp + except: + self.skipTest('WebP support not installed') - assert_equal(image.mode, "RGBA") - assert_equal(image.size, (200, 150)) - assert_equal(image.format, "WEBP") - assert_no_exception(lambda: image.load()) - assert_no_exception(lambda: image.getdata()) + if _webp.WebPDecoderBuggyAlpha(self): + self.skipTest("Buggy early version of WebP installed, not testing transparency") - orig_bytes = image.tobytes() - - target = Image.open('Images/transparent.png') - assert_image_similar(image, target, 20.0) - - -def test_write_lossless_rgb(): - temp_file = tempfile("temp.webp") - #temp_file = "temp.webp" - - pil_image = lena('RGBA') - - mask = Image.new("RGBA", (64, 64), (128,128,128,128)) - pil_image.paste(mask, (0,0), mask) # add some partially transparent bits. - - pil_image.save(temp_file, lossless=True) - - image = Image.open(temp_file) - image.load() - - assert_equal(image.mode, "RGBA") - assert_equal(image.size, pil_image.size) - assert_equal(image.format, "WEBP") - assert_no_exception(lambda: image.load()) - assert_no_exception(lambda: image.getdata()) - - - assert_image_equal(image, pil_image) - -def test_write_rgba(): - """ - Can we write a RGBA mode file to webp without error. Does it have the bits we - expect? - - """ - - temp_file = tempfile("temp.webp") - - pil_image = Image.new("RGBA", (10, 10), (255, 0, 0, 20)) - pil_image.save(temp_file) - - if _webp.WebPDecoderBuggyAlpha(): - return - - image = Image.open(temp_file) - image.load() - - assert_equal(image.mode, "RGBA") - assert_equal(image.size, (10, 10)) - assert_equal(image.format, "WEBP") - assert_no_exception(image.load) - assert_no_exception(image.getdata) - - assert_image_similar(image, pil_image, 1.0) + def test_read_rgba(self): + # Generated with `cwebp transparent.png -o transparent.webp` + file_path = "Images/transparent.webp" + image = Image.open(file_path) + self.assertEqual(image.mode, "RGBA") + self.assertEqual(image.size, (200, 150)) + self.assertEqual(image.format, "WEBP") + image.load() + image.getdata() + + image.tobytes() + + target = Image.open('Images/transparent.png') + self.assert_image_similar(image, target, 20.0) + + def test_write_lossless_rgb(self): + temp_file = self.tempfile("temp.webp") + # temp_file = "temp.webp" + + pil_image = lena('RGBA') + + mask = Image.new("RGBA", (64, 64), (128, 128, 128, 128)) + # Add some partially transparent bits: + pil_image.paste(mask, (0, 0), mask) + + pil_image.save(temp_file, lossless=True) + + image = Image.open(temp_file) + image.load() + + self.assertEqual(image.mode, "RGBA") + self.assertEqual(image.size, pil_image.size) + self.assertEqual(image.format, "WEBP") + image.load() + image.getdata() + + self.assert_image_equal(image, pil_image) + + def test_write_rgba(self): + """ + Can we write a RGBA mode file to webp without error. + Does it have the bits we expect? + """ + + temp_file = self.tempfile("temp.webp") + + pil_image = Image.new("RGBA", (10, 10), (255, 0, 0, 20)) + pil_image.save(temp_file) + + if _webp.WebPDecoderBuggyAlpha(self): + return + + image = Image.open(temp_file) + image.load() + + self.assertEqual(image.mode, "RGBA") + self.assertEqual(image.size, (10, 10)) + self.assertEqual(image.format, "WEBP") + image.load + image.getdata + + self.assert_image_similar(image, pil_image, 1.0) +if __name__ == '__main__': + unittest.main() +# End of file diff --git a/Tests/test_file_webp_lossless.py b/Tests/test_file_webp_lossless.py index ca2b5af19..9f8e339de 100644 --- a/Tests/test_file_webp_lossless.py +++ b/Tests/test_file_webp_lossless.py @@ -1,33 +1,43 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule, lena from PIL import Image - try: from PIL import _webp except: - skip('webp support not installed') + pass + # Skip in setUp() -if (_webp.WebPDecoderVersion() < 0x0200): - skip('lossless not included') +class TestFileWebpLossless(PillowTestCase): -def test_write_lossless_rgb(): - temp_file = tempfile("temp.webp") + def setUp(self): + try: + from PIL import _webp + except: + self.skipTest('WebP support not installed') - lena("RGB").save(temp_file, lossless=True) + if (_webp.WebPDecoderVersion() < 0x0200): + self.skipTest('lossless not included') - image = Image.open(temp_file) - image.load() + def test_write_lossless_rgb(self): + temp_file = self.tempfile("temp.webp") - assert_equal(image.mode, "RGB") - assert_equal(image.size, (128, 128)) - assert_equal(image.format, "WEBP") - assert_no_exception(lambda: image.load()) - assert_no_exception(lambda: image.getdata()) - - - assert_image_equal(image, lena("RGB")) + lena("RGB").save(temp_file, lossless=True) + + image = Image.open(temp_file) + image.load() + + self.assertEqual(image.mode, "RGB") + self.assertEqual(image.size, (128, 128)) + self.assertEqual(image.format, "WEBP") + image.load() + image.getdata() + + self.assert_image_equal(image, lena("RGB")) +if __name__ == '__main__': + unittest.main() +# End of file diff --git a/Tests/test_file_webp_metadata.py b/Tests/test_file_webp_metadata.py index b4146c3ee..93021ac07 100644 --- a/Tests/test_file_webp_metadata.py +++ b/Tests/test_file_webp_metadata.py @@ -1,101 +1,112 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule from PIL import Image -try: - from PIL import _webp - if not _webp.HAVE_WEBPMUX: - skip('webpmux support not installed') -except: - skip('webp support not installed') + +class TestFileWebpMetadata(PillowTestCase): + + def setUp(self): + try: + from PIL import _webp + if not _webp.HAVE_WEBPMUX: + self.skipTest('webpmux support not installed') + except: + self.skipTest('WebP support not installed') + + def test_read_exif_metadata(self): + + file_path = "Images/flower.webp" + image = Image.open(file_path) + + self.assertEqual(image.format, "WEBP") + exif_data = image.info.get("exif", None) + self.assertTrue(exif_data) + + exif = image._getexif() + + # camera make + self.assertEqual(exif[271], "Canon") + + jpeg_image = Image.open('Tests/images/flower.jpg') + expected_exif = jpeg_image.info['exif'] + + self.assertEqual(exif_data, expected_exif) + + def test_write_exif_metadata(self): + from io import BytesIO + + file_path = "Tests/images/flower.jpg" + image = Image.open(file_path) + expected_exif = image.info['exif'] + + buffer = BytesIO() + + image.save(buffer, "webp", exif=expected_exif) + + buffer.seek(0) + webp_image = Image.open(buffer) + + webp_exif = webp_image.info.get('exif', None) + self.assertTrue(webp_exif) + if webp_exif: + self.assertEqual( + webp_exif, expected_exif, "WebP EXIF didn't match") + + def test_read_icc_profile(self): + + file_path = "Images/flower2.webp" + image = Image.open(file_path) + + self.assertEqual(image.format, "WEBP") + self.assertTrue(image.info.get("icc_profile", None)) + + icc = image.info['icc_profile'] + + jpeg_image = Image.open('Tests/images/flower2.jpg') + expected_icc = jpeg_image.info['icc_profile'] + + self.assertEqual(icc, expected_icc) + + def test_write_icc_metadata(self): + from io import BytesIO + + file_path = "Tests/images/flower2.jpg" + image = Image.open(file_path) + expected_icc_profile = image.info['icc_profile'] + + buffer = BytesIO() + + image.save(buffer, "webp", icc_profile=expected_icc_profile) + + buffer.seek(0) + webp_image = Image.open(buffer) + + webp_icc_profile = webp_image.info.get('icc_profile', None) + + self.assertTrue(webp_icc_profile) + if webp_icc_profile: + self.assertEqual( + webp_icc_profile, expected_icc_profile, + "Webp ICC didn't match") + + def test_read_no_exif(self): + from io import BytesIO + + file_path = "Tests/images/flower.jpg" + image = Image.open(file_path) + image.info['exif'] + + buffer = BytesIO() + + image.save(buffer, "webp") + + buffer.seek(0) + webp_image = Image.open(buffer) + + self.assertFalse(webp_image._getexif()) +if __name__ == '__main__': + unittest.main() -def test_read_exif_metadata(): - - file_path = "Images/flower.webp" - image = Image.open(file_path) - - assert_equal(image.format, "WEBP") - exif_data = image.info.get("exif", None) - assert_true(exif_data) - - exif = image._getexif() - - #camera make - assert_equal(exif[271], "Canon") - - jpeg_image = Image.open('Tests/images/flower.jpg') - expected_exif = jpeg_image.info['exif'] - - assert_equal(exif_data, expected_exif) - - -def test_write_exif_metadata(): - file_path = "Tests/images/flower.jpg" - image = Image.open(file_path) - expected_exif = image.info['exif'] - - buffer = BytesIO() - - image.save(buffer, "webp", exif=expected_exif) - - buffer.seek(0) - webp_image = Image.open(buffer) - - webp_exif = webp_image.info.get('exif', None) - assert_true(webp_exif) - if webp_exif: - assert_equal(webp_exif, expected_exif, "Webp Exif didn't match") - - -def test_read_icc_profile(): - - file_path = "Images/flower2.webp" - image = Image.open(file_path) - - assert_equal(image.format, "WEBP") - assert_true(image.info.get("icc_profile", None)) - - icc = image.info['icc_profile'] - - jpeg_image = Image.open('Tests/images/flower2.jpg') - expected_icc = jpeg_image.info['icc_profile'] - - assert_equal(icc, expected_icc) - - -def test_write_icc_metadata(): - file_path = "Tests/images/flower2.jpg" - image = Image.open(file_path) - expected_icc_profile = image.info['icc_profile'] - - buffer = BytesIO() - - image.save(buffer, "webp", icc_profile=expected_icc_profile) - - buffer.seek(0) - webp_image = Image.open(buffer) - - webp_icc_profile = webp_image.info.get('icc_profile', None) - - assert_true(webp_icc_profile) - if webp_icc_profile: - assert_equal(webp_icc_profile, expected_icc_profile, "Webp ICC didn't match") - - -def test_read_no_exif(): - file_path = "Tests/images/flower.jpg" - image = Image.open(file_path) - expected_exif = image.info['exif'] - - buffer = BytesIO() - - image.save(buffer, "webp") - - buffer.seek(0) - webp_image = Image.open(buffer) - - assert_false(webp_image._getexif()) - - +# End of file diff --git a/Tests/test_file_xbm.py b/Tests/test_file_xbm.py index f27a3a349..d520ef460 100644 --- a/Tests/test_file_xbm.py +++ b/Tests/test_file_xbm.py @@ -1,4 +1,4 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule from PIL import Image @@ -25,10 +25,20 @@ static char basic_bits[] = { }; """ -def test_pil151(): - im = Image.open(BytesIO(PIL151)) +class TestFileXbm(PillowTestCase): - assert_no_exception(lambda: im.load()) - assert_equal(im.mode, '1') - assert_equal(im.size, (32, 32)) + def test_pil151(self): + from io import BytesIO + + im = Image.open(BytesIO(PIL151)) + + im.load() + self.assertEqual(im.mode, '1') + self.assertEqual(im.size, (32, 32)) + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_file_xpm.py b/Tests/test_file_xpm.py index 44135d028..0c765da8e 100644 --- a/Tests/test_file_xpm.py +++ b/Tests/test_file_xpm.py @@ -1,4 +1,4 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule from PIL import Image @@ -6,9 +6,18 @@ from PIL import Image file = "Images/lena.xpm" data = open(file, "rb").read() -def test_sanity(): - im = Image.open(file) - im.load() - assert_equal(im.mode, "P") - assert_equal(im.size, (128, 128)) - assert_equal(im.format, "XPM") + +class TestFileXpm(PillowTestCase): + + def test_sanity(self): + im = Image.open(file) + im.load() + self.assertEqual(im.mode, "P") + self.assertEqual(im.size, (128, 128)) + self.assertEqual(im.format, "XPM") + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_font_bdf.py b/Tests/test_font_bdf.py index 366bb4468..9a8f19d03 100644 --- a/Tests/test_font_bdf.py +++ b/Tests/test_font_bdf.py @@ -1,13 +1,22 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule -from PIL import Image, FontFile, BdfFontFile +from PIL import FontFile, BdfFontFile filename = "Images/courB08.bdf" -def test_sanity(): - file = open(filename, "rb") - font = BdfFontFile.BdfFontFile(file) +class TestFontBdf(PillowTestCase): - assert_true(isinstance(font, FontFile.FontFile)) - assert_equal(len([_f for _f in font.glyph if _f]), 190) + def test_sanity(self): + + file = open(filename, "rb") + font = BdfFontFile.BdfFontFile(file) + + self.assertIsInstance(font, FontFile.FontFile) + self.assertEqual(len([_f for _f in font.glyph if _f]), 190) + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_font_pcf.py b/Tests/test_font_pcf.py index bae214e35..24abcf73d 100644 --- a/Tests/test_font_pcf.py +++ b/Tests/test_font_pcf.py @@ -1,49 +1,63 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule from PIL import Image, FontFile, PcfFontFile from PIL import ImageFont, ImageDraw codecs = dir(Image.core) -if "zip_encoder" not in codecs or "zip_decoder" not in codecs: - skip("zlib support not available") - fontname = "Tests/fonts/helvO18.pcf" -tempname = tempfile("temp.pil", "temp.pbm") -message = "hello, world" +message = "hello, world" -def test_sanity(): - file = open(fontname, "rb") - font = PcfFontFile.PcfFontFile(file) - assert_true(isinstance(font, FontFile.FontFile)) - assert_equal(len([_f for _f in font.glyph if _f]), 192) +class TestFontPcf(PillowTestCase): - font.save(tempname) + def setUp(self): + if "zip_encoder" not in codecs or "zip_decoder" not in codecs: + self.skipTest("zlib support not available") -def xtest_draw(): + def save_font(self): + file = open(fontname, "rb") + font = PcfFontFile.PcfFontFile(file) + self.assertIsInstance(font, FontFile.FontFile) + self.assertEqual(len([_f for _f in font.glyph if _f]), 192) - font = ImageFont.load(tempname) - image = Image.new("L", font.getsize(message), "white") - draw = ImageDraw.Draw(image) - draw.text((0, 0), message, font=font) - # assert_signature(image, "7216c60f988dea43a46bb68321e3c1b03ec62aee") + tempname = self.tempfile("temp.pil", "temp.pbm") + font.save(tempname) + return tempname -def _test_high_characters(message): + def test_sanity(self): + self.save_font() - font = ImageFont.load(tempname) - image = Image.new("L", font.getsize(message), "white") - draw = ImageDraw.Draw(image) - draw.text((0, 0), message, font=font) + def xtest_draw(self): - compare = Image.open('Tests/images/high_ascii_chars.png') - assert_image_equal(image, compare) + tempname = self.save_font() + font = ImageFont.load(tempname) + image = Image.new("L", font.getsize(message), "white") + draw = ImageDraw.Draw(image) + draw.text((0, 0), message, font=font) + # assert_signature(image, "7216c60f988dea43a46bb68321e3c1b03ec62aee") -def test_high_characters(): - message = "".join([chr(i+1) for i in range(140,232)]) - _test_high_characters(message) - # accept bytes instances in Py3. - if bytes is not str: - _test_high_characters(message.encode('latin1')) + def _test_high_characters(self, message): + tempname = self.save_font() + font = ImageFont.load(tempname) + image = Image.new("L", font.getsize(message), "white") + draw = ImageDraw.Draw(image) + draw.text((0, 0), message, font=font) + + compare = Image.open('Tests/images/high_ascii_chars.png') + self.assert_image_equal(image, compare) + + def test_high_characters(self): + message = "".join([chr(i+1) for i in range(140, 232)]) + self._test_high_characters(message) + # accept bytes instances in Py3. + if bytes is not str: + self._test_high_characters(message.encode('latin1')) + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_format_lab.py b/Tests/test_format_lab.py index 371b06a0b..188b0d1fa 100644 --- a/Tests/test_format_lab.py +++ b/Tests/test_format_lab.py @@ -1,41 +1,48 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule from PIL import Image -def test_white(): - i = Image.open('Tests/images/lab.tif') - bits = i.load() - - assert_equal(i.mode, 'LAB') +class TestFormatLab(PillowTestCase): - assert_equal(i.getbands(), ('L','A', 'B')) + def test_white(self): + i = Image.open('Tests/images/lab.tif') - k = i.getpixel((0,0)) - assert_equal(k, (255,128,128)) + i.load() - L = i.getdata(0) - a = i.getdata(1) - b = i.getdata(2) + self.assertEqual(i.mode, 'LAB') - assert_equal(list(L), [255]*100) - assert_equal(list(a), [128]*100) - assert_equal(list(b), [128]*100) - + self.assertEqual(i.getbands(), ('L', 'A', 'B')) -def test_green(): - # l= 50 (/100), a = -100 (-128 .. 128) b=0 in PS - # == RGB: 0, 152, 117 - i = Image.open('Tests/images/lab-green.tif') + k = i.getpixel((0, 0)) + self.assertEqual(k, (255, 128, 128)) - k = i.getpixel((0,0)) - assert_equal(k, (128,28,128)) + L = i.getdata(0) + a = i.getdata(1) + b = i.getdata(2) + + self.assertEqual(list(L), [255]*100) + self.assertEqual(list(a), [128]*100) + self.assertEqual(list(b), [128]*100) + + def test_green(self): + # l= 50 (/100), a = -100 (-128 .. 128) b=0 in PS + # == RGB: 0, 152, 117 + i = Image.open('Tests/images/lab-green.tif') + + k = i.getpixel((0, 0)) + self.assertEqual(k, (128, 28, 128)) + + def test_red(self): + # l= 50 (/100), a = 100 (-128 .. 128) b=0 in PS + # == RGB: 255, 0, 124 + i = Image.open('Tests/images/lab-red.tif') + + k = i.getpixel((0, 0)) + self.assertEqual(k, (128, 228, 128)) -def test_red(): - # l= 50 (/100), a = 100 (-128 .. 128) b=0 in PS - # == RGB: 255, 0, 124 - i = Image.open('Tests/images/lab-red.tif') +if __name__ == '__main__': + unittest.main() - k = i.getpixel((0,0)) - assert_equal(k, (128,228,128)) +# End of file diff --git a/Tests/test_image.py b/Tests/test_image.py index 26c699e66..ec82eb419 100644 --- a/Tests/test_image.py +++ b/Tests/test_image.py @@ -1,39 +1,51 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule from PIL import Image -def test_sanity(): - im = Image.new("L", (100, 100)) - assert_equal(repr(im)[:45], " 8 bit lut for converting I->L images - see https://github.com/python-imaging/Pillow/issues/440 - """ +class TestImagePoint(PillowTestCase): - im = lena("I") - assert_no_exception(lambda: im.point(list(range(256))*256, 'L')) + def setUp(self): + if hasattr(sys, 'pypy_version_info'): + # This takes _forever_ on PyPy. Open Bug, + # see https://github.com/python-pillow/Pillow/issues/484 + self.skipTest("Too slow on PyPy") + + def test_sanity(self): + im = lena() + + self.assertRaises(ValueError, lambda: im.point(list(range(256)))) + im.point(list(range(256))*3) + im.point(lambda x: x) + + im = im.convert("I") + self.assertRaises(ValueError, lambda: im.point(list(range(256)))) + im.point(lambda x: x*1) + im.point(lambda x: x+1) + im.point(lambda x: x*1+1) + self.assertRaises(TypeError, lambda: im.point(lambda x: x-1)) + self.assertRaises(TypeError, lambda: im.point(lambda x: x/1)) + + def test_16bit_lut(self): + """ Tests for 16 bit -> 8 bit lut for converting I->L images + see https://github.com/python-pillow/Pillow/issues/440 + """ + + im = lena("I") + im.point(list(range(256))*256, 'L') + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_image_putalpha.py b/Tests/test_image_putalpha.py index b23f69834..bb36b335e 100644 --- a/Tests/test_image_putalpha.py +++ b/Tests/test_image_putalpha.py @@ -1,43 +1,52 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule from PIL import Image -def test_interface(): - im = Image.new("RGBA", (1, 1), (1, 2, 3, 0)) - assert_equal(im.getpixel((0, 0)), (1, 2, 3, 0)) +class TestImagePutAlpha(PillowTestCase): - im = Image.new("RGBA", (1, 1), (1, 2, 3)) - assert_equal(im.getpixel((0, 0)), (1, 2, 3, 255)) + def test_interface(self): - im.putalpha(Image.new("L", im.size, 4)) - assert_equal(im.getpixel((0, 0)), (1, 2, 3, 4)) + im = Image.new("RGBA", (1, 1), (1, 2, 3, 0)) + self.assertEqual(im.getpixel((0, 0)), (1, 2, 3, 0)) - im.putalpha(5) - assert_equal(im.getpixel((0, 0)), (1, 2, 3, 5)) + im = Image.new("RGBA", (1, 1), (1, 2, 3)) + self.assertEqual(im.getpixel((0, 0)), (1, 2, 3, 255)) -def test_promote(): + im.putalpha(Image.new("L", im.size, 4)) + self.assertEqual(im.getpixel((0, 0)), (1, 2, 3, 4)) - im = Image.new("L", (1, 1), 1) - assert_equal(im.getpixel((0, 0)), 1) + im.putalpha(5) + self.assertEqual(im.getpixel((0, 0)), (1, 2, 3, 5)) - im.putalpha(2) - assert_equal(im.mode, 'LA') - assert_equal(im.getpixel((0, 0)), (1, 2)) + def test_promote(self): - im = Image.new("RGB", (1, 1), (1, 2, 3)) - assert_equal(im.getpixel((0, 0)), (1, 2, 3)) + im = Image.new("L", (1, 1), 1) + self.assertEqual(im.getpixel((0, 0)), 1) - im.putalpha(4) - assert_equal(im.mode, 'RGBA') - assert_equal(im.getpixel((0, 0)), (1, 2, 3, 4)) + im.putalpha(2) + self.assertEqual(im.mode, 'LA') + self.assertEqual(im.getpixel((0, 0)), (1, 2)) -def test_readonly(): + im = Image.new("RGB", (1, 1), (1, 2, 3)) + self.assertEqual(im.getpixel((0, 0)), (1, 2, 3)) - im = Image.new("RGB", (1, 1), (1, 2, 3)) - im.readonly = 1 + im.putalpha(4) + self.assertEqual(im.mode, 'RGBA') + self.assertEqual(im.getpixel((0, 0)), (1, 2, 3, 4)) - im.putalpha(4) - assert_false(im.readonly) - assert_equal(im.mode, 'RGBA') - assert_equal(im.getpixel((0, 0)), (1, 2, 3, 4)) + def test_readonly(self): + + im = Image.new("RGB", (1, 1), (1, 2, 3)) + im.readonly = 1 + + im.putalpha(4) + self.assertFalse(im.readonly) + self.assertEqual(im.mode, 'RGBA') + self.assertEqual(im.getpixel((0, 0)), (1, 2, 3, 4)) + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_image_putdata.py b/Tests/test_image_putdata.py index e25359fdf..d792adfe6 100644 --- a/Tests/test_image_putdata.py +++ b/Tests/test_image_putdata.py @@ -1,40 +1,48 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule, lena import sys from PIL import Image -def test_sanity(): - im1 = lena() +class TestImagePutData(PillowTestCase): - data = list(im1.getdata()) + def test_sanity(self): - im2 = Image.new(im1.mode, im1.size, 0) - im2.putdata(data) + im1 = lena() - assert_image_equal(im1, im2) + data = list(im1.getdata()) - # readonly - im2 = Image.new(im1.mode, im2.size, 0) - im2.readonly = 1 - im2.putdata(data) + im2 = Image.new(im1.mode, im1.size, 0) + im2.putdata(data) - assert_false(im2.readonly) - assert_image_equal(im1, im2) + self.assert_image_equal(im1, im2) + + # readonly + im2 = Image.new(im1.mode, im2.size, 0) + im2.readonly = 1 + im2.putdata(data) + + self.assertFalse(im2.readonly) + self.assert_image_equal(im1, im2) + + def test_long_integers(self): + # see bug-200802-systemerror + def put(value): + im = Image.new("RGBA", (1, 1)) + im.putdata([value]) + return im.getpixel((0, 0)) + self.assertEqual(put(0xFFFFFFFF), (255, 255, 255, 255)) + self.assertEqual(put(0xFFFFFFFF), (255, 255, 255, 255)) + self.assertEqual(put(-1), (255, 255, 255, 255)) + self.assertEqual(put(-1), (255, 255, 255, 255)) + if sys.maxsize > 2**32: + self.assertEqual(put(sys.maxsize), (255, 255, 255, 255)) + else: + self.assertEqual(put(sys.maxsize), (255, 255, 255, 127)) -def test_long_integers(): - # see bug-200802-systemerror - def put(value): - im = Image.new("RGBA", (1, 1)) - im.putdata([value]) - return im.getpixel((0, 0)) - assert_equal(put(0xFFFFFFFF), (255, 255, 255, 255)) - assert_equal(put(0xFFFFFFFF), (255, 255, 255, 255)) - assert_equal(put(-1), (255, 255, 255, 255)) - assert_equal(put(-1), (255, 255, 255, 255)) - if sys.maxsize > 2**32: - assert_equal(put(sys.maxsize), (255, 255, 255, 255)) - else: - assert_equal(put(sys.maxsize), (255, 255, 255, 127)) +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_image_putpalette.py b/Tests/test_image_putpalette.py index b7ebb8853..26ad09800 100644 --- a/Tests/test_image_putpalette.py +++ b/Tests/test_image_putpalette.py @@ -1,28 +1,36 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule, lena -from PIL import Image from PIL import ImagePalette -def test_putpalette(): - def palette(mode): - im = lena(mode).copy() - im.putpalette(list(range(256))*3) - p = im.getpalette() - if p: - return im.mode, p[:10] - return im.mode - assert_exception(ValueError, lambda: palette("1")) - assert_equal(palette("L"), ("P", [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])) - assert_equal(palette("P"), ("P", [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])) - assert_exception(ValueError, lambda: palette("I")) - assert_exception(ValueError, lambda: palette("F")) - assert_exception(ValueError, lambda: palette("RGB")) - assert_exception(ValueError, lambda: palette("RGBA")) - assert_exception(ValueError, lambda: palette("YCbCr")) -def test_imagepalette(): - im = lena("P") - assert_no_exception(lambda: im.putpalette(ImagePalette.negative())) - assert_no_exception(lambda: im.putpalette(ImagePalette.random())) - assert_no_exception(lambda: im.putpalette(ImagePalette.sepia())) - assert_no_exception(lambda: im.putpalette(ImagePalette.wedge())) +class TestImagePutPalette(PillowTestCase): + + def test_putpalette(self): + def palette(mode): + im = lena(mode).copy() + im.putpalette(list(range(256))*3) + p = im.getpalette() + if p: + return im.mode, p[:10] + return im.mode + self.assertRaises(ValueError, lambda: palette("1")) + self.assertEqual(palette("L"), ("P", [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])) + self.assertEqual(palette("P"), ("P", [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])) + self.assertRaises(ValueError, lambda: palette("I")) + self.assertRaises(ValueError, lambda: palette("F")) + self.assertRaises(ValueError, lambda: palette("RGB")) + self.assertRaises(ValueError, lambda: palette("RGBA")) + self.assertRaises(ValueError, lambda: palette("YCbCr")) + + def test_imagepalette(self): + im = lena("P") + im.putpalette(ImagePalette.negative()) + im.putpalette(ImagePalette.random()) + im.putpalette(ImagePalette.sepia()) + im.putpalette(ImagePalette.wedge()) + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_image_putpixel.py b/Tests/test_image_putpixel.py index 5f19237cb..1afc013c0 100644 --- a/Tests/test_image_putpixel.py +++ b/Tests/test_image_putpixel.py @@ -1,45 +1,50 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule, lena from PIL import Image -Image.USE_CFFI_ACCESS=False - -def test_sanity(): - - im1 = lena() - im2 = Image.new(im1.mode, im1.size, 0) - - for y in range(im1.size[1]): - for x in range(im1.size[0]): - pos = x, y - im2.putpixel(pos, im1.getpixel(pos)) - - assert_image_equal(im1, im2) - - im2 = Image.new(im1.mode, im1.size, 0) - im2.readonly = 1 - - for y in range(im1.size[1]): - for x in range(im1.size[0]): - pos = x, y - im2.putpixel(pos, im1.getpixel(pos)) - - assert_false(im2.readonly) - assert_image_equal(im1, im2) - - im2 = Image.new(im1.mode, im1.size, 0) - - pix1 = im1.load() - pix2 = im2.load() - - for y in range(im1.size[1]): - for x in range(im1.size[0]): - pix2[x, y] = pix1[x, y] - - assert_image_equal(im1, im2) +Image.USE_CFFI_ACCESS = False +class TestImagePutPixel(PillowTestCase): + + def test_sanity(self): + + im1 = lena() + im2 = Image.new(im1.mode, im1.size, 0) + + for y in range(im1.size[1]): + for x in range(im1.size[0]): + pos = x, y + im2.putpixel(pos, im1.getpixel(pos)) + + self.assert_image_equal(im1, im2) + + im2 = Image.new(im1.mode, im1.size, 0) + im2.readonly = 1 + + for y in range(im1.size[1]): + for x in range(im1.size[0]): + pos = x, y + im2.putpixel(pos, im1.getpixel(pos)) + + self.assertFalse(im2.readonly) + self.assert_image_equal(im1, im2) + + im2 = Image.new(im1.mode, im1.size, 0) + + pix1 = im1.load() + pix2 = im2.load() + + for y in range(im1.size[1]): + for x in range(im1.size[0]): + pix2[x, y] = pix1[x, y] + + self.assert_image_equal(im1, im2) + + # see test_image_getpixel for more tests -# see test_image_getpixel for more tests +if __name__ == '__main__': + unittest.main() +# End of file diff --git a/Tests/test_image_quantize.py b/Tests/test_image_quantize.py index dbf68a25e..63fe0cb21 100644 --- a/Tests/test_image_quantize.py +++ b/Tests/test_image_quantize.py @@ -1,27 +1,35 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule, lena from PIL import Image -def test_sanity(): - im = lena() +class TestImageQuantize(PillowTestCase): - im = im.quantize() - assert_image(im, "P", im.size) + def test_sanity(self): + im = lena() - im = lena() - im = im.quantize(palette=lena("P")) - assert_image(im, "P", im.size) + im = im.quantize() + self.assert_image(im, "P", im.size) -def test_octree_quantize(): - im = lena() + im = lena() + im = im.quantize(palette=lena("P")) + self.assert_image(im, "P", im.size) - im = im.quantize(100, Image.FASTOCTREE) - assert_image(im, "P", im.size) + def test_octree_quantize(self): + im = lena() - assert len(im.getcolors()) == 100 + im = im.quantize(100, Image.FASTOCTREE) + self.assert_image(im, "P", im.size) -def test_rgba_quantize(): - im = lena('RGBA') - assert_no_exception(lambda: im.quantize()) - assert_exception(Exception, lambda: im.quantize(method=0)) + assert len(im.getcolors()) == 100 + + def test_rgba_quantize(self): + im = lena('RGBA') + im.quantize() + self.assertRaises(Exception, lambda: im.quantize(method=0)) + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_image_resize.py b/Tests/test_image_resize.py index 4e228a396..a200b17b4 100644 --- a/Tests/test_image_resize.py +++ b/Tests/test_image_resize.py @@ -1,12 +1,19 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule, lena -from PIL import Image -def test_resize(): - def resize(mode, size): - out = lena(mode).resize(size) - assert_equal(out.mode, mode) - assert_equal(out.size, size) - for mode in "1", "P", "L", "RGB", "I", "F": - yield_test(resize, mode, (100, 100)) - yield_test(resize, mode, (200, 200)) +class TestImageResize(PillowTestCase): + + def test_resize(self): + def resize(mode, size): + out = lena(mode).resize(size) + self.assertEqual(out.mode, mode) + self.assertEqual(out.size, size) + for mode in "1", "P", "L", "RGB", "I", "F": + resize(mode, (100, 100)) + resize(mode, (200, 200)) + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_image_rotate.py b/Tests/test_image_rotate.py index 5e4782c87..bb24ddf4f 100644 --- a/Tests/test_image_rotate.py +++ b/Tests/test_image_rotate.py @@ -1,15 +1,22 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule, lena -from PIL import Image -def test_rotate(): - def rotate(mode): - im = lena(mode) - out = im.rotate(45) - assert_equal(out.mode, mode) - assert_equal(out.size, im.size) # default rotate clips output - out = im.rotate(45, expand=1) - assert_equal(out.mode, mode) - assert_true(out.size != im.size) - for mode in "1", "P", "L", "RGB", "I", "F": - yield_test(rotate, mode) +class TestImageRotate(PillowTestCase): + + def test_rotate(self): + def rotate(mode): + im = lena(mode) + out = im.rotate(45) + self.assertEqual(out.mode, mode) + self.assertEqual(out.size, im.size) # default rotate clips output + out = im.rotate(45, expand=1) + self.assertEqual(out.mode, mode) + self.assertNotEqual(out.size, im.size) + for mode in "1", "P", "L", "RGB", "I", "F": + rotate(mode) + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_image_save.py b/Tests/test_image_save.py deleted file mode 100644 index 7d4b6d9b3..000000000 --- a/Tests/test_image_save.py +++ /dev/null @@ -1,5 +0,0 @@ -from tester import * - -from PIL import Image - -success() diff --git a/Tests/test_image_seek.py b/Tests/test_image_seek.py deleted file mode 100644 index 7d4b6d9b3..000000000 --- a/Tests/test_image_seek.py +++ /dev/null @@ -1,5 +0,0 @@ -from tester import * - -from PIL import Image - -success() diff --git a/Tests/test_image_show.py b/Tests/test_image_show.py deleted file mode 100644 index 7d4b6d9b3..000000000 --- a/Tests/test_image_show.py +++ /dev/null @@ -1,5 +0,0 @@ -from tester import * - -from PIL import Image - -success() diff --git a/Tests/test_image_split.py b/Tests/test_image_split.py index 07a779664..284acd87c 100644 --- a/Tests/test_image_split.py +++ b/Tests/test_image_split.py @@ -1,49 +1,67 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule, lena from PIL import Image -def test_split(): - def split(mode): - layers = lena(mode).split() - return [(i.mode, i.size[0], i.size[1]) for i in layers] - assert_equal(split("1"), [('1', 128, 128)]) - assert_equal(split("L"), [('L', 128, 128)]) - assert_equal(split("I"), [('I', 128, 128)]) - assert_equal(split("F"), [('F', 128, 128)]) - assert_equal(split("P"), [('P', 128, 128)]) - assert_equal(split("RGB"), [('L', 128, 128), ('L', 128, 128), ('L', 128, 128)]) - assert_equal(split("RGBA"), [('L', 128, 128), ('L', 128, 128), ('L', 128, 128), ('L', 128, 128)]) - assert_equal(split("CMYK"), [('L', 128, 128), ('L', 128, 128), ('L', 128, 128), ('L', 128, 128)]) - assert_equal(split("YCbCr"), [('L', 128, 128), ('L', 128, 128), ('L', 128, 128)]) -def test_split_merge(): - def split_merge(mode): - return Image.merge(mode, lena(mode).split()) - assert_image_equal(lena("1"), split_merge("1")) - assert_image_equal(lena("L"), split_merge("L")) - assert_image_equal(lena("I"), split_merge("I")) - assert_image_equal(lena("F"), split_merge("F")) - assert_image_equal(lena("P"), split_merge("P")) - assert_image_equal(lena("RGB"), split_merge("RGB")) - assert_image_equal(lena("RGBA"), split_merge("RGBA")) - assert_image_equal(lena("CMYK"), split_merge("CMYK")) - assert_image_equal(lena("YCbCr"), split_merge("YCbCr")) +class TestImageSplit(PillowTestCase): -def test_split_open(): - codecs = dir(Image.core) + def test_split(self): + def split(mode): + layers = lena(mode).split() + return [(i.mode, i.size[0], i.size[1]) for i in layers] + self.assertEqual(split("1"), [('1', 128, 128)]) + self.assertEqual(split("L"), [('L', 128, 128)]) + self.assertEqual(split("I"), [('I', 128, 128)]) + self.assertEqual(split("F"), [('F', 128, 128)]) + self.assertEqual(split("P"), [('P', 128, 128)]) + self.assertEqual( + split("RGB"), [('L', 128, 128), ('L', 128, 128), ('L', 128, 128)]) + self.assertEqual( + split("RGBA"), + [('L', 128, 128), ('L', 128, 128), + ('L', 128, 128), ('L', 128, 128)]) + self.assertEqual( + split("CMYK"), + [('L', 128, 128), ('L', 128, 128), + ('L', 128, 128), ('L', 128, 128)]) + self.assertEqual( + split("YCbCr"), + [('L', 128, 128), ('L', 128, 128), ('L', 128, 128)]) - if 'zip_encoder' in codecs: - file = tempfile("temp.png") - else: - file = tempfile("temp.pcx") + def test_split_merge(self): + def split_merge(mode): + return Image.merge(mode, lena(mode).split()) + self.assert_image_equal(lena("1"), split_merge("1")) + self.assert_image_equal(lena("L"), split_merge("L")) + self.assert_image_equal(lena("I"), split_merge("I")) + self.assert_image_equal(lena("F"), split_merge("F")) + self.assert_image_equal(lena("P"), split_merge("P")) + self.assert_image_equal(lena("RGB"), split_merge("RGB")) + self.assert_image_equal(lena("RGBA"), split_merge("RGBA")) + self.assert_image_equal(lena("CMYK"), split_merge("CMYK")) + self.assert_image_equal(lena("YCbCr"), split_merge("YCbCr")) - def split_open(mode): - lena(mode).save(file) - im = Image.open(file) - return len(im.split()) - assert_equal(split_open("1"), 1) - assert_equal(split_open("L"), 1) - assert_equal(split_open("P"), 1) - assert_equal(split_open("RGB"), 3) - if 'zip_encoder' in codecs: - assert_equal(split_open("RGBA"), 4) + def test_split_open(self): + codecs = dir(Image.core) + + if 'zip_encoder' in codecs: + file = self.tempfile("temp.png") + else: + file = self.tempfile("temp.pcx") + + def split_open(mode): + lena(mode).save(file) + im = Image.open(file) + return len(im.split()) + self.assertEqual(split_open("1"), 1) + self.assertEqual(split_open("L"), 1) + self.assertEqual(split_open("P"), 1) + self.assertEqual(split_open("RGB"), 3) + if 'zip_encoder' in codecs: + self.assertEqual(split_open("RGBA"), 4) + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_image_tell.py b/Tests/test_image_tell.py deleted file mode 100644 index 7d4b6d9b3..000000000 --- a/Tests/test_image_tell.py +++ /dev/null @@ -1,5 +0,0 @@ -from tester import * - -from PIL import Image - -success() diff --git a/Tests/test_image_thumbnail.py b/Tests/test_image_thumbnail.py index 871dd1f54..6b33da318 100644 --- a/Tests/test_image_thumbnail.py +++ b/Tests/test_image_thumbnail.py @@ -1,36 +1,43 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule, lena -from PIL import Image -def test_sanity(): +class TestImageThumbnail(PillowTestCase): - im = lena() - im.thumbnail((100, 100)) + def test_sanity(self): - assert_image(im, im.mode, (100, 100)) + im = lena() + im.thumbnail((100, 100)) -def test_aspect(): + self.assert_image(im, im.mode, (100, 100)) - im = lena() - im.thumbnail((100, 100)) - assert_image(im, im.mode, (100, 100)) + def test_aspect(self): - im = lena().resize((128, 256)) - im.thumbnail((100, 100)) - assert_image(im, im.mode, (50, 100)) + im = lena() + im.thumbnail((100, 100)) + self.assert_image(im, im.mode, (100, 100)) - im = lena().resize((128, 256)) - im.thumbnail((50, 100)) - assert_image(im, im.mode, (50, 100)) + im = lena().resize((128, 256)) + im.thumbnail((100, 100)) + self.assert_image(im, im.mode, (50, 100)) - im = lena().resize((256, 128)) - im.thumbnail((100, 100)) - assert_image(im, im.mode, (100, 50)) + im = lena().resize((128, 256)) + im.thumbnail((50, 100)) + self.assert_image(im, im.mode, (50, 100)) - im = lena().resize((256, 128)) - im.thumbnail((100, 50)) - assert_image(im, im.mode, (100, 50)) + im = lena().resize((256, 128)) + im.thumbnail((100, 100)) + self.assert_image(im, im.mode, (100, 50)) - im = lena().resize((128, 128)) - im.thumbnail((100, 100)) - assert_image(im, im.mode, (100, 100)) + im = lena().resize((256, 128)) + im.thumbnail((100, 50)) + self.assert_image(im, im.mode, (100, 50)) + + im = lena().resize((128, 128)) + im.thumbnail((100, 100)) + self.assert_image(im, im.mode, (100, 100)) + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_image_tobitmap.py b/Tests/test_image_tobitmap.py index 6fb10dd53..93f01c9de 100644 --- a/Tests/test_image_tobitmap.py +++ b/Tests/test_image_tobitmap.py @@ -1,15 +1,22 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule, lena, fromstring -from PIL import Image -def test_sanity(): +class TestImageToBitmap(PillowTestCase): - assert_exception(ValueError, lambda: lena().tobitmap()) - assert_no_exception(lambda: lena().convert("1").tobitmap()) + def test_sanity(self): - im1 = lena().convert("1") + self.assertRaises(ValueError, lambda: lena().tobitmap()) + lena().convert("1").tobitmap() - bitmap = im1.tobitmap() + im1 = lena().convert("1") - assert_true(isinstance(bitmap, bytes)) - assert_image_equal(im1, fromstring(bitmap)) + bitmap = im1.tobitmap() + + self.assertIsInstance(bitmap, bytes) + self.assert_image_equal(im1, fromstring(bitmap)) + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_image_tobytes.py b/Tests/test_image_tobytes.py index d42399993..3be9128c1 100644 --- a/Tests/test_image_tobytes.py +++ b/Tests/test_image_tobytes.py @@ -1,7 +1,13 @@ -from tester import * +from helper import unittest, lena -from PIL import Image -def test_sanity(): - data = lena().tobytes() - assert_true(isinstance(data, bytes)) +class TestImageToBytes(unittest.TestCase): + + def test_sanity(self): + data = lena().tobytes() + self.assertTrue(isinstance(data, bytes)) + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_image_transform.py b/Tests/test_image_transform.py index fdee6072f..3f257fef2 100644 --- a/Tests/test_image_transform.py +++ b/Tests/test_image_transform.py @@ -1,116 +1,125 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule, lena from PIL import Image -def test_extent(): - im = lena('RGB') - (w,h) = im.size - transformed = im.transform(im.size, Image.EXTENT, - (0,0, - w//2,h//2), # ul -> lr - Image.BILINEAR) - - scaled = im.resize((w*2, h*2), Image.BILINEAR).crop((0,0,w,h)) - - assert_image_similar(transformed, scaled, 10) # undone -- precision? +class TestImageTransform(PillowTestCase): -def test_quad(): - # one simple quad transform, equivalent to scale & crop upper left quad - im = lena('RGB') - (w,h) = im.size - transformed = im.transform(im.size, Image.QUAD, - (0,0,0,h//2, - w//2,h//2,w//2,0), # ul -> ccw around quad - Image.BILINEAR) - - scaled = im.resize((w*2, h*2), Image.BILINEAR).crop((0,0,w,h)) - - assert_image_equal(transformed, scaled) + def test_extent(self): + im = lena('RGB') + (w, h) = im.size + transformed = im.transform(im.size, Image.EXTENT, + (0, 0, + w//2, h//2), # ul -> lr + Image.BILINEAR) -def test_mesh(): - # this should be a checkerboard of halfsized lenas in ul, lr - im = lena('RGBA') - (w,h) = im.size - transformed = im.transform(im.size, Image.MESH, - [((0,0,w//2,h//2), # box - (0,0,0,h, - w,h,w,0)), # ul -> ccw around quad - ((w//2,h//2,w,h), # box - (0,0,0,h, - w,h,w,0))], # ul -> ccw around quad - Image.BILINEAR) + scaled = im.resize((w*2, h*2), Image.BILINEAR).crop((0, 0, w, h)) - #transformed.save('transformed.png') + # undone -- precision? + self.assert_image_similar(transformed, scaled, 10) - scaled = im.resize((w//2, h//2), Image.BILINEAR) + def test_quad(self): + # one simple quad transform, equivalent to scale & crop upper left quad + im = lena('RGB') + (w, h) = im.size + transformed = im.transform(im.size, Image.QUAD, + (0, 0, 0, h//2, + # ul -> ccw around quad: + w//2, h//2, w//2, 0), + Image.BILINEAR) - checker = Image.new('RGBA', im.size) - checker.paste(scaled, (0,0)) - checker.paste(scaled, (w//2,h//2)) - - assert_image_equal(transformed, checker) + scaled = im.resize((w*2, h*2), Image.BILINEAR).crop((0, 0, w, h)) - # now, check to see that the extra area is (0,0,0,0) - blank = Image.new('RGBA', (w//2,h//2), (0,0,0,0)) + self.assert_image_equal(transformed, scaled) - assert_image_equal(blank, transformed.crop((w//2,0,w,h//2))) - assert_image_equal(blank, transformed.crop((0,h//2,w//2,h))) + def test_mesh(self): + # this should be a checkerboard of halfsized lenas in ul, lr + im = lena('RGBA') + (w, h) = im.size + transformed = im.transform(im.size, Image.MESH, + [((0, 0, w//2, h//2), # box + (0, 0, 0, h, + w, h, w, 0)), # ul -> ccw around quad + ((w//2, h//2, w, h), # box + (0, 0, 0, h, + w, h, w, 0))], # ul -> ccw around quad + Image.BILINEAR) -def _test_alpha_premult(op): - # create image with half white, half black, with the black half transparent. - # do op, - # there should be no darkness in the white section. - im = Image.new('RGBA', (10,10), (0,0,0,0)); - im2 = Image.new('RGBA', (5,10), (255,255,255,255)); - im.paste(im2, (0,0)) - - im = op(im, (40,10)) - im_background = Image.new('RGB', (40,10), (255,255,255)) - im_background.paste(im, (0,0), im) - - hist = im_background.histogram() - assert_equal(40*10, hist[-1]) + # transformed.save('transformed.png') - -def test_alpha_premult_resize(): + scaled = im.resize((w//2, h//2), Image.BILINEAR) - def op (im, sz): - return im.resize(sz, Image.LINEAR) - - _test_alpha_premult(op) - -def test_alpha_premult_transform(): - - def op(im, sz): - (w,h) = im.size - return im.transform(sz, Image.EXTENT, - (0,0, - w,h), - Image.BILINEAR) + checker = Image.new('RGBA', im.size) + checker.paste(scaled, (0, 0)) + checker.paste(scaled, (w//2, h//2)) - _test_alpha_premult(op) + self.assert_image_equal(transformed, checker) + + # now, check to see that the extra area is (0, 0, 0, 0) + blank = Image.new('RGBA', (w//2, h//2), (0, 0, 0, 0)) + + self.assert_image_equal(blank, transformed.crop((w//2, 0, w, h//2))) + self.assert_image_equal(blank, transformed.crop((0, h//2, w//2, h))) + + def _test_alpha_premult(self, op): + # create image with half white, half black, + # with the black half transparent. + # do op, + # there should be no darkness in the white section. + im = Image.new('RGBA', (10, 10), (0, 0, 0, 0)) + im2 = Image.new('RGBA', (5, 10), (255, 255, 255, 255)) + im.paste(im2, (0, 0)) + + im = op(im, (40, 10)) + im_background = Image.new('RGB', (40, 10), (255, 255, 255)) + im_background.paste(im, (0, 0), im) + + hist = im_background.histogram() + self.assertEqual(40*10, hist[-1]) + + def test_alpha_premult_resize(self): + + def op(im, sz): + return im.resize(sz, Image.LINEAR) + + self._test_alpha_premult(op) + + def test_alpha_premult_transform(self): + + def op(im, sz): + (w, h) = im.size + return im.transform(sz, Image.EXTENT, + (0, 0, + w, h), + Image.BILINEAR) + + self._test_alpha_premult(op) + + def test_blank_fill(self): + # attempting to hit + # https://github.com/python-pillow/Pillow/issues/254 reported + # + # issue is that transforms with transparent overflow area + # contained junk from previous images, especially on systems with + # constrained memory. So, attempt to fill up memory with a + # pattern, free it, and then run the mesh test again. Using a 1Mp + # image with 4 bands, for 4 megs of data allocated, x 64. OMM (64 + # bit 12.04 VM with 512 megs available, this fails with Pillow < + # a0eaf06cc5f62a6fb6de556989ac1014ff3348ea + # + # Running by default, but I'd totally understand not doing it in + # the future + + foo = [Image.new('RGBA', (1024, 1024), (a, a, a, a)) + for a in range(1, 65)] + + # Yeah. Watch some JIT optimize this out. + foo = None + + self.test_mesh() -def test_blank_fill(): - # attempting to hit - # https://github.com/python-imaging/Pillow/issues/254 reported - # - # issue is that transforms with transparent overflow area - # contained junk from previous images, especially on systems with - # constrained memory. So, attempt to fill up memory with a - # pattern, free it, and then run the mesh test again. Using a 1Mp - # image with 4 bands, for 4 megs of data allocated, x 64. OMM (64 - # bit 12.04 VM with 512 megs available, this fails with Pillow < - # a0eaf06cc5f62a6fb6de556989ac1014ff3348ea - # - # Running by default, but I'd totally understand not doing it in - # the future - - foo = [Image.new('RGBA',(1024,1024), (a,a,a,a)) - for a in range(1,65)] +if __name__ == '__main__': + unittest.main() - # Yeah. Watch some JIT optimize this out. - foo = None - - test_mesh() +# End of file diff --git a/Tests/test_image_transpose.py b/Tests/test_image_transpose.py index 43b3ef9d3..ec83aa3a6 100644 --- a/Tests/test_image_transpose.py +++ b/Tests/test_image_transpose.py @@ -1,4 +1,4 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule, lena from PIL import Image @@ -8,27 +8,37 @@ ROTATE_90 = Image.ROTATE_90 ROTATE_180 = Image.ROTATE_180 ROTATE_270 = Image.ROTATE_270 -def test_sanity(): - im = lena() +class TestImageTranspose(PillowTestCase): - assert_no_exception(lambda: im.transpose(FLIP_LEFT_RIGHT)) - assert_no_exception(lambda: im.transpose(FLIP_TOP_BOTTOM)) + def test_sanity(self): - assert_no_exception(lambda: im.transpose(ROTATE_90)) - assert_no_exception(lambda: im.transpose(ROTATE_180)) - assert_no_exception(lambda: im.transpose(ROTATE_270)) + im = lena() -def test_roundtrip(): + im.transpose(FLIP_LEFT_RIGHT) + im.transpose(FLIP_TOP_BOTTOM) - im = lena() + im.transpose(ROTATE_90) + im.transpose(ROTATE_180) + im.transpose(ROTATE_270) - def transpose(first, second): - return im.transpose(first).transpose(second) + def test_roundtrip(self): - assert_image_equal(im, transpose(FLIP_LEFT_RIGHT, FLIP_LEFT_RIGHT)) - assert_image_equal(im, transpose(FLIP_TOP_BOTTOM, FLIP_TOP_BOTTOM)) + im = lena() - assert_image_equal(im, transpose(ROTATE_90, ROTATE_270)) - assert_image_equal(im, transpose(ROTATE_180, ROTATE_180)) + def transpose(first, second): + return im.transpose(first).transpose(second) + self.assert_image_equal( + im, transpose(FLIP_LEFT_RIGHT, FLIP_LEFT_RIGHT)) + self.assert_image_equal( + im, transpose(FLIP_TOP_BOTTOM, FLIP_TOP_BOTTOM)) + + self.assert_image_equal(im, transpose(ROTATE_90, ROTATE_270)) + self.assert_image_equal(im, transpose(ROTATE_180, ROTATE_180)) + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_image_verify.py b/Tests/test_image_verify.py deleted file mode 100644 index 7d4b6d9b3..000000000 --- a/Tests/test_image_verify.py +++ /dev/null @@ -1,5 +0,0 @@ -from tester import * - -from PIL import Image - -success() diff --git a/Tests/test_imagechops.py b/Tests/test_imagechops.py index 16eaaf55e..fe377f864 100644 --- a/Tests/test_imagechops.py +++ b/Tests/test_imagechops.py @@ -1,56 +1,74 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule, lena from PIL import Image from PIL import ImageChops -def test_sanity(): - im = lena("L") +class TestImageChops(PillowTestCase): - ImageChops.constant(im, 128) - ImageChops.duplicate(im) - ImageChops.invert(im) - ImageChops.lighter(im, im) - ImageChops.darker(im, im) - ImageChops.difference(im, im) - ImageChops.multiply(im, im) - ImageChops.screen(im, im) + def test_sanity(self): - ImageChops.add(im, im) - ImageChops.add(im, im, 2.0) - ImageChops.add(im, im, 2.0, 128) - ImageChops.subtract(im, im) - ImageChops.subtract(im, im, 2.0) - ImageChops.subtract(im, im, 2.0, 128) + im = lena("L") - ImageChops.add_modulo(im, im) - ImageChops.subtract_modulo(im, im) + ImageChops.constant(im, 128) + ImageChops.duplicate(im) + ImageChops.invert(im) + ImageChops.lighter(im, im) + ImageChops.darker(im, im) + ImageChops.difference(im, im) + ImageChops.multiply(im, im) + ImageChops.screen(im, im) - ImageChops.blend(im, im, 0.5) - ImageChops.composite(im, im, im) + ImageChops.add(im, im) + ImageChops.add(im, im, 2.0) + ImageChops.add(im, im, 2.0, 128) + ImageChops.subtract(im, im) + ImageChops.subtract(im, im, 2.0) + ImageChops.subtract(im, im, 2.0, 128) - ImageChops.offset(im, 10) - ImageChops.offset(im, 10, 20) + ImageChops.add_modulo(im, im) + ImageChops.subtract_modulo(im, im) -def test_logical(): + ImageChops.blend(im, im, 0.5) + ImageChops.composite(im, im, im) - def table(op, a, b): - out = [] - for x in (a, b): - imx = Image.new("1", (1, 1), x) - for y in (a, b): - imy = Image.new("1", (1, 1), y) - out.append(op(imx, imy).getpixel((0, 0))) - return tuple(out) + ImageChops.offset(im, 10) + ImageChops.offset(im, 10, 20) - assert_equal(table(ImageChops.logical_and, 0, 1), (0, 0, 0, 255)) - assert_equal(table(ImageChops.logical_or, 0, 1), (0, 255, 255, 255)) - assert_equal(table(ImageChops.logical_xor, 0, 1), (0, 255, 255, 0)) + def test_logical(self): - assert_equal(table(ImageChops.logical_and, 0, 128), (0, 0, 0, 255)) - assert_equal(table(ImageChops.logical_or, 0, 128), (0, 255, 255, 255)) - assert_equal(table(ImageChops.logical_xor, 0, 128), (0, 255, 255, 0)) + def table(op, a, b): + out = [] + for x in (a, b): + imx = Image.new("1", (1, 1), x) + for y in (a, b): + imy = Image.new("1", (1, 1), y) + out.append(op(imx, imy).getpixel((0, 0))) + return tuple(out) - assert_equal(table(ImageChops.logical_and, 0, 255), (0, 0, 0, 255)) - assert_equal(table(ImageChops.logical_or, 0, 255), (0, 255, 255, 255)) - assert_equal(table(ImageChops.logical_xor, 0, 255), (0, 255, 255, 0)) + self.assertEqual( + table(ImageChops.logical_and, 0, 1), (0, 0, 0, 255)) + self.assertEqual( + table(ImageChops.logical_or, 0, 1), (0, 255, 255, 255)) + self.assertEqual( + table(ImageChops.logical_xor, 0, 1), (0, 255, 255, 0)) + + self.assertEqual( + table(ImageChops.logical_and, 0, 128), (0, 0, 0, 255)) + self.assertEqual( + table(ImageChops.logical_or, 0, 128), (0, 255, 255, 255)) + self.assertEqual( + table(ImageChops.logical_xor, 0, 128), (0, 255, 255, 0)) + + self.assertEqual( + table(ImageChops.logical_and, 0, 255), (0, 0, 0, 255)) + self.assertEqual( + table(ImageChops.logical_or, 0, 255), (0, 255, 255, 255)) + self.assertEqual( + table(ImageChops.logical_xor, 0, 255), (0, 255, 255, 0)) + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_imagecms.py b/Tests/test_imagecms.py index dcb445c9f..d4432d9be 100644 --- a/Tests/test_imagecms.py +++ b/Tests/test_imagecms.py @@ -1,160 +1,214 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule, lena from PIL import Image + try: from PIL import ImageCms ImageCms.core.profile_open -except ImportError: - skip() +except ImportError as v: + # Skipped via setUp() + pass + SRGB = "Tests/icc/sRGB.icm" -def test_sanity(): - # basic smoke test. - # this mostly follows the cms_test outline. +class TestImageCms(PillowTestCase): - v = ImageCms.versions() # should return four strings - assert_equal(v[0], '1.0.0 pil') - assert_equal(list(map(type, v)), [str, str, str, str]) + def setUp(self): + try: + from PIL import ImageCms + except ImportError as v: + self.skipTest(v) - # internal version number - assert_match(ImageCms.core.littlecms_version, "\d+\.\d+$") + def test_sanity(self): - i = ImageCms.profileToProfile(lena(), SRGB, SRGB) - assert_image(i, "RGB", (128, 128)) + # basic smoke test. + # this mostly follows the cms_test outline. - t = ImageCms.buildTransform(SRGB, SRGB, "RGB", "RGB") - i = ImageCms.applyTransform(lena(), t) - assert_image(i, "RGB", (128, 128)) + v = ImageCms.versions() # should return four strings + self.assertEqual(v[0], '1.0.0 pil') + self.assertEqual(list(map(type, v)), [str, str, str, str]) - p = ImageCms.createProfile("sRGB") - o = ImageCms.getOpenProfile(SRGB) - t = ImageCms.buildTransformFromOpenProfiles(p, o, "RGB", "RGB") - i = ImageCms.applyTransform(lena(), t) - assert_image(i, "RGB", (128, 128)) + # internal version number + self.assertRegexpMatches(ImageCms.core.littlecms_version, "\d+\.\d+$") - t = ImageCms.buildProofTransform(SRGB, SRGB, SRGB, "RGB", "RGB") - assert_equal(t.inputMode, "RGB") - assert_equal(t.outputMode, "RGB") - i = ImageCms.applyTransform(lena(), t) - assert_image(i, "RGB", (128, 128)) + i = ImageCms.profileToProfile(lena(), SRGB, SRGB) + self.assert_image(i, "RGB", (128, 128)) - # test PointTransform convenience API - im = lena().point(t) + i = lena() + ImageCms.profileToProfile(i, SRGB, SRGB, inPlace=True) + self.assert_image(i, "RGB", (128, 128)) -def test_name(): - # get profile information for file - assert_equal(ImageCms.getProfileName(SRGB).strip(), - 'IEC 61966-2.1 Default RGB colour space - sRGB') -def x_test_info(): - assert_equal(ImageCms.getProfileInfo(SRGB).splitlines(), - ['sRGB IEC61966-2.1', '', - 'Copyright (c) 1998 Hewlett-Packard Company', '', - 'WhitePoint : D65 (daylight)', '', - 'Tests/icc/sRGB.icm']) + t = ImageCms.buildTransform(SRGB, SRGB, "RGB", "RGB") + i = ImageCms.applyTransform(lena(), t) + self.assert_image(i, "RGB", (128, 128)) -def test_intent(): - assert_equal(ImageCms.getDefaultIntent(SRGB), 0) - assert_equal(ImageCms.isIntentSupported( + i = lena() + t = ImageCms.buildTransform(SRGB, SRGB, "RGB", "RGB") + ImageCms.applyTransform(lena(), t, inPlace=True) + self.assert_image(i, "RGB", (128, 128)) + + p = ImageCms.createProfile("sRGB") + o = ImageCms.getOpenProfile(SRGB) + t = ImageCms.buildTransformFromOpenProfiles(p, o, "RGB", "RGB") + i = ImageCms.applyTransform(lena(), t) + self.assert_image(i, "RGB", (128, 128)) + + t = ImageCms.buildProofTransform(SRGB, SRGB, SRGB, "RGB", "RGB") + self.assertEqual(t.inputMode, "RGB") + self.assertEqual(t.outputMode, "RGB") + i = ImageCms.applyTransform(lena(), t) + self.assert_image(i, "RGB", (128, 128)) + + # test PointTransform convenience API + lena().point(t) + + def test_name(self): + # get profile information for file + self.assertEqual( + ImageCms.getProfileName(SRGB).strip(), + 'IEC 61966-2.1 Default RGB colour space - sRGB') + + def test_info(self): + self.assertEqual( + ImageCms.getProfileInfo(SRGB).splitlines(), [ + 'sRGB IEC61966-2.1', '', + 'Copyright (c) 1998 Hewlett-Packard Company', '']) + + def test_copyright(self): + self.assertEqual( + ImageCms.getProfileCopyright(SRGB).strip(), + 'Copyright (c) 1998 Hewlett-Packard Company') + + def test_manufacturer(self): + self.assertEqual( + ImageCms.getProfileManufacturer(SRGB).strip(), + 'IEC http://www.iec.ch') + + def test_model(self): + self.assertEqual( + ImageCms.getProfileModel(SRGB).strip(), + 'IEC 61966-2.1 Default RGB colour space - sRGB') + + def test_description(self): + self.assertEqual( + ImageCms.getProfileDescription(SRGB).strip(), + 'sRGB IEC61966-2.1') + + def test_intent(self): + self.assertEqual(ImageCms.getDefaultIntent(SRGB), 0) + self.assertEqual(ImageCms.isIntentSupported( SRGB, ImageCms.INTENT_ABSOLUTE_COLORIMETRIC, ImageCms.DIRECTION_INPUT), 1) -def test_profile_object(): - # same, using profile object - p = ImageCms.createProfile("sRGB") -# assert_equal(ImageCms.getProfileName(p).strip(), -# 'sRGB built-in - (lcms internal)') -# assert_equal(ImageCms.getProfileInfo(p).splitlines(), -# ['sRGB built-in', '', 'WhitePoint : D65 (daylight)', '', '']) - assert_equal(ImageCms.getDefaultIntent(p), 0) - assert_equal(ImageCms.isIntentSupported( + def test_profile_object(self): + # same, using profile object + p = ImageCms.createProfile("sRGB") + # self.assertEqual(ImageCms.getProfileName(p).strip(), + # 'sRGB built-in - (lcms internal)') + # self.assertEqual(ImageCms.getProfileInfo(p).splitlines(), + # ['sRGB built-in', '', 'WhitePoint : D65 (daylight)', '', '']) + self.assertEqual(ImageCms.getDefaultIntent(p), 0) + self.assertEqual(ImageCms.isIntentSupported( p, ImageCms.INTENT_ABSOLUTE_COLORIMETRIC, ImageCms.DIRECTION_INPUT), 1) -def test_extensions(): - # extensions - i = Image.open("Tests/images/rgb.jpg") - p = ImageCms.getOpenProfile(BytesIO(i.info["icc_profile"])) - assert_equal(ImageCms.getProfileName(p).strip(), - 'IEC 61966-2.1 Default RGB colour space - sRGB') + def test_extensions(self): + # extensions + from io import BytesIO + i = Image.open("Tests/images/rgb.jpg") + p = ImageCms.getOpenProfile(BytesIO(i.info["icc_profile"])) + self.assertEqual( + ImageCms.getProfileName(p).strip(), + 'IEC 61966-2.1 Default RGB colour space - sRGB') -def test_exceptions(): - # the procedural pyCMS API uses PyCMSError for all sorts of errors - assert_exception(ImageCms.PyCMSError, lambda: ImageCms.profileToProfile(lena(), "foo", "bar")) - assert_exception(ImageCms.PyCMSError, lambda: ImageCms.buildTransform("foo", "bar", "RGB", "RGB")) - assert_exception(ImageCms.PyCMSError, lambda: ImageCms.getProfileName(None)) - assert_exception(ImageCms.PyCMSError, lambda: ImageCms.isIntentSupported(SRGB, None, None)) + def test_exceptions(self): + # the procedural pyCMS API uses PyCMSError for all sorts of errors + self.assertRaises( + ImageCms.PyCMSError, + lambda: ImageCms.profileToProfile(lena(), "foo", "bar")) + self.assertRaises( + ImageCms.PyCMSError, + lambda: ImageCms.buildTransform("foo", "bar", "RGB", "RGB")) + self.assertRaises( + ImageCms.PyCMSError, + lambda: ImageCms.getProfileName(None)) + self.assertRaises( + ImageCms.PyCMSError, + lambda: ImageCms.isIntentSupported(SRGB, None, None)) + + def test_display_profile(self): + # try fetching the profile for the current display device + ImageCms.get_display_profile() + + def test_lab_color_profile(self): + ImageCms.createProfile("LAB", 5000) + ImageCms.createProfile("LAB", 6500) + + def test_simple_lab(self): + i = Image.new('RGB', (10, 10), (128, 128, 128)) + + pLab = ImageCms.createProfile("LAB") + t = ImageCms.buildTransform(SRGB, pLab, "RGB", "LAB") + + i_lab = ImageCms.applyTransform(i, t) + + self.assertEqual(i_lab.mode, 'LAB') + + k = i_lab.getpixel((0, 0)) + # not a linear luminance map. so L != 128: + self.assertEqual(k, (137, 128, 128)) + + L = i_lab.getdata(0) + a = i_lab.getdata(1) + b = i_lab.getdata(2) + + self.assertEqual(list(L), [137] * 100) + self.assertEqual(list(a), [128] * 100) + self.assertEqual(list(b), [128] * 100) + + def test_lab_color(self): + pLab = ImageCms.createProfile("LAB") + t = ImageCms.buildTransform(SRGB, pLab, "RGB", "LAB") + # Need to add a type mapping for some PIL type to TYPE_Lab_8 in + # findLCMSType, and have that mapping work back to a PIL mode + # (likely RGB). + i = ImageCms.applyTransform(lena(), t) + self.assert_image(i, "LAB", (128, 128)) + + # i.save('temp.lab.tif') # visually verified vs PS. + + target = Image.open('Tests/images/lena.Lab.tif') + + self.assert_image_similar(i, target, 30) + + def test_lab_srgb(self): + pLab = ImageCms.createProfile("LAB") + t = ImageCms.buildTransform(pLab, SRGB, "LAB", "RGB") + + img = Image.open('Tests/images/lena.Lab.tif') + + img_srgb = ImageCms.applyTransform(img, t) + + # img_srgb.save('temp.srgb.tif') # visually verified vs ps. + + self.assert_image_similar(lena(), img_srgb, 30) + + def test_lab_roundtrip(self): + # check to see if we're at least internally consistent. + pLab = ImageCms.createProfile("LAB") + t = ImageCms.buildTransform(SRGB, pLab, "RGB", "LAB") + + t2 = ImageCms.buildTransform(pLab, SRGB, "LAB", "RGB") + + i = ImageCms.applyTransform(lena(), t) + out = ImageCms.applyTransform(i, t2) + + self.assert_image_similar(lena(), out, 2) -def test_display_profile(): - # try fetching the profile for the current display device - assert_no_exception(lambda: ImageCms.get_display_profile()) - - -def test_lab_color_profile(): - pLab = ImageCms.createProfile("LAB", 5000) - pLab = ImageCms.createProfile("LAB", 6500) - -def test_simple_lab(): - i = Image.new('RGB', (10,10), (128,128,128)) - - pLab = ImageCms.createProfile("LAB") - t = ImageCms.buildTransform(SRGB, pLab, "RGB", "LAB") - - i_lab = ImageCms.applyTransform(i, t) - - - assert_equal(i_lab.mode, 'LAB') - - k = i_lab.getpixel((0,0)) - assert_equal(k, (137,128,128)) # not a linear luminance map. so L != 128 - - L = i_lab.getdata(0) - a = i_lab.getdata(1) - b = i_lab.getdata(2) - - assert_equal(list(L), [137]*100) - assert_equal(list(a), [128]*100) - assert_equal(list(b), [128]*100) - - -def test_lab_color(): - pLab = ImageCms.createProfile("LAB") - t = ImageCms.buildTransform(SRGB, pLab, "RGB", "LAB") - # need to add a type mapping for some PIL type to TYPE_Lab_8 in findLCMSType, - # and have that mapping work back to a PIL mode. (likely RGB) - i = ImageCms.applyTransform(lena(), t) - assert_image(i, "LAB", (128, 128)) - - # i.save('temp.lab.tif') # visually verified vs PS. - - target = Image.open('Tests/images/lena.Lab.tif') - - assert_image_similar(i, target, 30) - -def test_lab_srgb(): - pLab = ImageCms.createProfile("LAB") - t = ImageCms.buildTransform(pLab, SRGB, "LAB", "RGB") - - img = Image.open('Tests/images/lena.Lab.tif') - - img_srgb = ImageCms.applyTransform(img, t) - - # img_srgb.save('temp.srgb.tif') # visually verified vs ps. - - assert_image_similar(lena(), img_srgb, 30) - -def test_lab_roundtrip(): - # check to see if we're at least internally consistent. - pLab = ImageCms.createProfile("LAB") - t = ImageCms.buildTransform(SRGB, pLab, "RGB", "LAB") - - t2 = ImageCms.buildTransform(pLab, SRGB, "LAB", "RGB") - - i = ImageCms.applyTransform(lena(), t) - out = ImageCms.applyTransform(i, t2) - - assert_image_similar(lena(), out, 2) - +if __name__ == '__main__': + unittest.main() +# End of file diff --git a/Tests/test_imagecolor.py b/Tests/test_imagecolor.py index c67c20255..fce64876b 100644 --- a/Tests/test_imagecolor.py +++ b/Tests/test_imagecolor.py @@ -1,54 +1,71 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule from PIL import Image from PIL import ImageColor -# -------------------------------------------------------------------- -# sanity -assert_equal((255, 0, 0), ImageColor.getrgb("#f00")) -assert_equal((255, 0, 0), ImageColor.getrgb("#ff0000")) -assert_equal((255, 0, 0), ImageColor.getrgb("rgb(255,0,0)")) -assert_equal((255, 0, 0), ImageColor.getrgb("rgb(255, 0, 0)")) -assert_equal((255, 0, 0), ImageColor.getrgb("rgb(100%,0%,0%)")) -assert_equal((255, 0, 0), ImageColor.getrgb("hsl(0, 100%, 50%)")) -assert_equal((255, 0, 0, 0), ImageColor.getrgb("rgba(255,0,0,0)")) -assert_equal((255, 0, 0, 0), ImageColor.getrgb("rgba(255, 0, 0, 0)")) -assert_equal((255, 0, 0), ImageColor.getrgb("red")) +class TestImageColor(PillowTestCase): -# -------------------------------------------------------------------- -# look for rounding errors (based on code by Tim Hatch) + def test_sanity(self): + self.assertEqual((255, 0, 0), ImageColor.getrgb("#f00")) + self.assertEqual((255, 0, 0), ImageColor.getrgb("#ff0000")) + self.assertEqual((255, 0, 0), ImageColor.getrgb("rgb(255,0,0)")) + self.assertEqual((255, 0, 0), ImageColor.getrgb("rgb(255, 0, 0)")) + self.assertEqual((255, 0, 0), ImageColor.getrgb("rgb(100%,0%,0%)")) + self.assertEqual((255, 0, 0), ImageColor.getrgb("hsl(0, 100%, 50%)")) + self.assertEqual((255, 0, 0, 0), ImageColor.getrgb("rgba(255,0,0,0)")) + self.assertEqual( + (255, 0, 0, 0), ImageColor.getrgb("rgba(255, 0, 0, 0)")) + self.assertEqual((255, 0, 0), ImageColor.getrgb("red")) -for color in list(ImageColor.colormap.keys()): - expected = Image.new("RGB", (1, 1), color).convert("L").getpixel((0, 0)) - actual = Image.new("L", (1, 1), color).getpixel((0, 0)) - assert_equal(expected, actual) + # look for rounding errors (based on code by Tim Hatch) + def test_rounding_errors(self): -assert_equal((0, 0, 0), ImageColor.getcolor("black", "RGB")) -assert_equal((255, 255, 255), ImageColor.getcolor("white", "RGB")) -assert_equal((0, 255, 115), ImageColor.getcolor("rgba(0, 255, 115, 33)", "RGB")) -Image.new("RGB", (1, 1), "white") + for color in list(ImageColor.colormap.keys()): + expected = Image.new( + "RGB", (1, 1), color).convert("L").getpixel((0, 0)) + actual = Image.new("L", (1, 1), color).getpixel((0, 0)) + self.assertEqual(expected, actual) -assert_equal((0, 0, 0, 255), ImageColor.getcolor("black", "RGBA")) -assert_equal((255, 255, 255, 255), ImageColor.getcolor("white", "RGBA")) -assert_equal((0, 255, 115, 33), ImageColor.getcolor("rgba(0, 255, 115, 33)", "RGBA")) -Image.new("RGBA", (1, 1), "white") + self.assertEqual((0, 0, 0), ImageColor.getcolor("black", "RGB")) + self.assertEqual((255, 255, 255), ImageColor.getcolor("white", "RGB")) + self.assertEqual( + (0, 255, 115), ImageColor.getcolor("rgba(0, 255, 115, 33)", "RGB")) + Image.new("RGB", (1, 1), "white") -assert_equal(0, ImageColor.getcolor("black", "L")) -assert_equal(255, ImageColor.getcolor("white", "L")) -assert_equal(162, ImageColor.getcolor("rgba(0, 255, 115, 33)", "L")) -Image.new("L", (1, 1), "white") + self.assertEqual((0, 0, 0, 255), ImageColor.getcolor("black", "RGBA")) + self.assertEqual( + (255, 255, 255, 255), ImageColor.getcolor("white", "RGBA")) + self.assertEqual( + (0, 255, 115, 33), + ImageColor.getcolor("rgba(0, 255, 115, 33)", "RGBA")) + Image.new("RGBA", (1, 1), "white") -assert_equal(0, ImageColor.getcolor("black", "1")) -assert_equal(255, ImageColor.getcolor("white", "1")) -# The following test is wrong, but is current behavior -# The correct result should be 255 due to the mode 1 -assert_equal(162, ImageColor.getcolor("rgba(0, 255, 115, 33)", "1")) -# Correct behavior -# assert_equal(255, ImageColor.getcolor("rgba(0, 255, 115, 33)", "1")) -Image.new("1", (1, 1), "white") + self.assertEqual(0, ImageColor.getcolor("black", "L")) + self.assertEqual(255, ImageColor.getcolor("white", "L")) + self.assertEqual( + 162, ImageColor.getcolor("rgba(0, 255, 115, 33)", "L")) + Image.new("L", (1, 1), "white") -assert_equal((0, 255), ImageColor.getcolor("black", "LA")) -assert_equal((255, 255), ImageColor.getcolor("white", "LA")) -assert_equal((162, 33), ImageColor.getcolor("rgba(0, 255, 115, 33)", "LA")) -Image.new("LA", (1, 1), "white") + self.assertEqual(0, ImageColor.getcolor("black", "1")) + self.assertEqual(255, ImageColor.getcolor("white", "1")) + # The following test is wrong, but is current behavior + # The correct result should be 255 due to the mode 1 + self.assertEqual( + 162, ImageColor.getcolor("rgba(0, 255, 115, 33)", "1")) + # Correct behavior + # self.assertEqual( + # 255, ImageColor.getcolor("rgba(0, 255, 115, 33)", "1")) + Image.new("1", (1, 1), "white") + + self.assertEqual((0, 255), ImageColor.getcolor("black", "LA")) + self.assertEqual((255, 255), ImageColor.getcolor("white", "LA")) + self.assertEqual( + (162, 33), ImageColor.getcolor("rgba(0, 255, 115, 33)", "LA")) + Image.new("LA", (1, 1), "white") + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_imagedraw.py b/Tests/test_imagedraw.py index f8b5c3c5c..a19ba78f8 100644 --- a/Tests/test_imagedraw.py +++ b/Tests/test_imagedraw.py @@ -1,28 +1,255 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule, lena from PIL import Image +from PIL import ImageColor from PIL import ImageDraw -def test_sanity(): +import sys - im = lena("RGB").copy() +# Image size +w, h = 100, 100 - draw = ImageDraw.ImageDraw(im) - draw = ImageDraw.Draw(im) +# Bounding box points +x0 = int(w / 4) +x1 = int(x0 * 3) +y0 = int(h / 4) +y1 = int(x0 * 3) - draw.ellipse(list(range(4))) - draw.line(list(range(10))) - draw.polygon(list(range(100))) - draw.rectangle(list(range(4))) +# Two kinds of bounding box +bbox1 = [(x0, y0), (x1, y1)] +bbox2 = [x0, y0, x1, y1] - success() +# Two kinds of coordinate sequences +points1 = [(10, 10), (20, 40), (30, 30)] +points2 = [10, 10, 20, 40, 30, 30] -def test_deprecated(): - im = lena().copy() +class TestImageDraw(PillowTestCase): - draw = ImageDraw.Draw(im) + def test_sanity(self): + im = lena("RGB").copy() - assert_warning(DeprecationWarning, lambda: draw.setink(0)) - assert_warning(DeprecationWarning, lambda: draw.setfill(0)) + draw = ImageDraw.ImageDraw(im) + draw = ImageDraw.Draw(im) + draw.ellipse(list(range(4))) + draw.line(list(range(10))) + draw.polygon(list(range(100))) + draw.rectangle(list(range(4))) + + def test_deprecated(self): + im = lena().copy() + + draw = ImageDraw.Draw(im) + + self.assert_warning(DeprecationWarning, lambda: draw.setink(0)) + self.assert_warning(DeprecationWarning, lambda: draw.setfill(0)) + + def helper_arc(self, bbox): + # Arrange + im = Image.new("RGB", (w, h)) + draw = ImageDraw.Draw(im) + + # Act + # FIXME Fill param should be named outline. + draw.arc(bbox, 0, 180) + del draw + + # Assert + self.assert_image_equal( + im, Image.open("Tests/images/imagedraw_arc.png")) + + def test_arc1(self): + self.helper_arc(bbox1) + + def test_arc2(self): + 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)) + draw = ImageDraw.Draw(im) + + # Act + draw.bitmap((10, 10), small) + del draw + + # Assert + self.assert_image_equal( + im, Image.open("Tests/images/imagedraw_bitmap.png")) + + def helper_chord(self, bbox): + # Arrange + im = Image.new("RGB", (w, h)) + draw = ImageDraw.Draw(im) + + # Act + draw.chord(bbox, 0, 180, fill="red", outline="yellow") + del draw + + # Assert + self.assert_image_equal( + im, Image.open("Tests/images/imagedraw_chord.png")) + + def test_chord1(self): + self.helper_chord(bbox1) + + def test_chord2(self): + self.helper_chord(bbox2) + + def helper_ellipse(self, bbox): + # Arrange + im = Image.new("RGB", (w, h)) + draw = ImageDraw.Draw(im) + + # Act + draw.ellipse(bbox, fill="green", outline="blue") + del draw + + # Assert + self.assert_image_equal( + im, Image.open("Tests/images/imagedraw_ellipse.png")) + + def test_ellipse1(self): + self.helper_ellipse(bbox1) + + def test_ellipse2(self): + self.helper_ellipse(bbox2) + + def helper_line(self, points): + # Arrange + im = Image.new("RGB", (w, h)) + draw = ImageDraw.Draw(im) + + # Act + draw.line(points1, fill="yellow", width=2) + del draw + + # Assert + self.assert_image_equal( + im, Image.open("Tests/images/imagedraw_line.png")) + + def test_line1(self): + self.helper_line(points1) + + def test_line2(self): + self.helper_line(points2) + + def helper_pieslice(self, bbox): + # Arrange + im = Image.new("RGB", (w, h)) + draw = ImageDraw.Draw(im) + + # Act + draw.pieslice(bbox, -90, 45, fill="white", outline="blue") + del draw + + # Assert + self.assert_image_equal( + im, Image.open("Tests/images/imagedraw_pieslice.png")) + + def test_pieslice1(self): + self.helper_pieslice(bbox1) + + def test_pieslice2(self): + self.helper_pieslice(bbox2) + + def helper_point(self, points): + # Arrange + im = Image.new("RGB", (w, h)) + draw = ImageDraw.Draw(im) + + # Act + draw.point(points1, fill="yellow") + del draw + + # Assert + self.assert_image_equal( + im, Image.open("Tests/images/imagedraw_point.png")) + + def test_point1(self): + self.helper_point(points1) + + def test_point2(self): + self.helper_point(points2) + + def helper_polygon(self, points): + # Arrange + im = Image.new("RGB", (w, h)) + draw = ImageDraw.Draw(im) + + # Act + draw.polygon(points1, fill="red", outline="blue") + del draw + + # Assert + self.assert_image_equal( + im, Image.open("Tests/images/imagedraw_polygon.png")) + + def test_polygon1(self): + self.helper_polygon(points1) + + def test_polygon2(self): + self.helper_polygon(points2) + + def helper_rectangle(self, bbox): + # Arrange + im = Image.new("RGB", (w, h)) + draw = ImageDraw.Draw(im) + + # Act + draw.rectangle(bbox, fill="black", outline="green") + del draw + + # Assert + self.assert_image_equal( + im, Image.open("Tests/images/imagedraw_rectangle.png")) + + def test_rectangle1(self): + self.helper_rectangle(bbox1) + + def test_rectangle2(self): + self.helper_rectangle(bbox2) + + def test_floodfill(self): + # Arrange + 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)) + + # Act + ImageDraw.floodfill(im, centre_point, ImageColor.getrgb("red")) + del draw + + # Assert + self.assert_image_equal( + im, Image.open("Tests/images/imagedraw_floodfill.png")) + + @unittest.skipIf(hasattr(sys, 'pypy_version_info'), + "Causes fatal RPython error on PyPy") + def test_floodfill_border(self): + # floodfill() is experimental + + # Arrange + 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)) + + # Act + ImageDraw.floodfill( + im, centre_point, ImageColor.getrgb("red"), + border=ImageColor.getrgb("black")) + del draw + + # Assert + self.assert_image_equal( + im, Image.open("Tests/images/imagedraw_floodfill2.png")) + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_imageenhance.py b/Tests/test_imageenhance.py index 04f16bfa5..eec26d768 100644 --- a/Tests/test_imageenhance.py +++ b/Tests/test_imageenhance.py @@ -1,19 +1,28 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule, lena from PIL import Image from PIL import ImageEnhance -def test_sanity(): - # FIXME: assert_image - assert_no_exception(lambda: ImageEnhance.Color(lena()).enhance(0.5)) - assert_no_exception(lambda: ImageEnhance.Contrast(lena()).enhance(0.5)) - assert_no_exception(lambda: ImageEnhance.Brightness(lena()).enhance(0.5)) - assert_no_exception(lambda: ImageEnhance.Sharpness(lena()).enhance(0.5)) +class TestImageEnhance(PillowTestCase): -def test_crash(): + def test_sanity(self): - # crashes on small images - im = Image.new("RGB", (1, 1)) - assert_no_exception(lambda: ImageEnhance.Sharpness(im).enhance(0.5)) + # FIXME: assert_image + # Implicit asserts no exception: + ImageEnhance.Color(lena()).enhance(0.5) + ImageEnhance.Contrast(lena()).enhance(0.5) + ImageEnhance.Brightness(lena()).enhance(0.5) + ImageEnhance.Sharpness(lena()).enhance(0.5) + def test_crash(self): + + # crashes on small images + im = Image.new("RGB", (1, 1)) + ImageEnhance.Sharpness(im).enhance(0.5) + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_imagefile.py b/Tests/test_imagefile.py index adf282b03..849767195 100644 --- a/Tests/test_imagefile.py +++ b/Tests/test_imagefile.py @@ -1,82 +1,93 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule, lena, fromstring, tostring + +from io import BytesIO from PIL import Image from PIL import ImageFile from PIL import EpsImagePlugin + codecs = dir(Image.core) # save original block sizes MAXBLOCK = ImageFile.MAXBLOCK SAFEBLOCK = ImageFile.SAFEBLOCK -def test_parser(): - def roundtrip(format): +class TestImagePutData(PillowTestCase): - im = lena("L").resize((1000, 1000)) - if format in ("MSP", "XBM"): - im = im.convert("1") + def test_parser(self): - file = BytesIO() + def roundtrip(format): - im.save(file, format) + im = lena("L").resize((1000, 1000)) + if format in ("MSP", "XBM"): + im = im.convert("1") - data = file.getvalue() + file = BytesIO() - parser = ImageFile.Parser() - parser.feed(data) - imOut = parser.close() + im.save(file, format) - return im, imOut + data = file.getvalue() + + parser = ImageFile.Parser() + parser.feed(data) + imOut = parser.close() + + return im, imOut + + self.assert_image_equal(*roundtrip("BMP")) + self.assert_image_equal(*roundtrip("GIF")) + self.assert_image_equal(*roundtrip("IM")) + self.assert_image_equal(*roundtrip("MSP")) + if "zip_encoder" in codecs: + try: + # force multiple blocks in PNG driver + ImageFile.MAXBLOCK = 8192 + self.assert_image_equal(*roundtrip("PNG")) + finally: + ImageFile.MAXBLOCK = MAXBLOCK + self.assert_image_equal(*roundtrip("PPM")) + self.assert_image_equal(*roundtrip("TIFF")) + self.assert_image_equal(*roundtrip("XBM")) + self.assert_image_equal(*roundtrip("TGA")) + self.assert_image_equal(*roundtrip("PCX")) + + if EpsImagePlugin.has_ghostscript(): + im1, im2 = roundtrip("EPS") + # EPS comes back in RGB: + self.assert_image_similar(im1, im2.convert('L'), 20) + + if "jpeg_encoder" in codecs: + im1, im2 = roundtrip("JPEG") # lossy compression + self.assert_image(im1, im2.mode, im2.size) + + self.assertRaises(IOError, lambda: roundtrip("PDF")) + + def test_ico(self): + with open('Tests/images/python.ico', 'rb') as f: + data = f.read() + p = ImageFile.Parser() + p.feed(data) + self.assertEqual((48, 48), p.image.size) + + def test_safeblock(self): + + im1 = lena() + + if "zip_encoder" not in codecs: + self.skipTest("PNG (zlib) encoder not available") - assert_image_equal(*roundtrip("BMP")) - assert_image_equal(*roundtrip("GIF")) - assert_image_equal(*roundtrip("IM")) - assert_image_equal(*roundtrip("MSP")) - if "zip_encoder" in codecs: try: - # force multiple blocks in PNG driver - ImageFile.MAXBLOCK = 8192 - assert_image_equal(*roundtrip("PNG")) + ImageFile.SAFEBLOCK = 1 + im2 = fromstring(tostring(im1, "PNG")) finally: - ImageFile.MAXBLOCK = MAXBLOCK - assert_image_equal(*roundtrip("PPM")) - assert_image_equal(*roundtrip("TIFF")) - assert_image_equal(*roundtrip("XBM")) - assert_image_equal(*roundtrip("TGA")) - assert_image_equal(*roundtrip("PCX")) + ImageFile.SAFEBLOCK = SAFEBLOCK - if EpsImagePlugin.has_ghostscript(): - im1, im2 = roundtrip("EPS") - assert_image_similar(im1, im2.convert('L'),20) # EPS comes back in RGB - - if "jpeg_encoder" in codecs: - im1, im2 = roundtrip("JPEG") # lossy compression - assert_image(im1, im2.mode, im2.size) + self.assert_image_equal(im1, im2) - # XXX Why assert exception and why does it fail? - # https://github.com/python-imaging/Pillow/issues/78 - #assert_exception(IOError, lambda: roundtrip("PDF")) -def test_ico(): - with open('Tests/images/python.ico', 'rb') as f: - data = f.read() - p = ImageFile.Parser() - p.feed(data) - assert_equal((48,48), p.image.size) +if __name__ == '__main__': + unittest.main() -def test_safeblock(): - - im1 = lena() - - if "zip_encoder" not in codecs: - skip("PNG (zlib) encoder not available") - - try: - ImageFile.SAFEBLOCK = 1 - im2 = fromstring(tostring(im1, "PNG")) - finally: - ImageFile.SAFEBLOCK = SAFEBLOCK - - assert_image_equal(im1, im2) +# End of file diff --git a/Tests/test_imagefileio.py b/Tests/test_imagefileio.py index c63f07bb0..791207dca 100644 --- a/Tests/test_imagefileio.py +++ b/Tests/test_imagefileio.py @@ -1,24 +1,33 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule, lena, tostring from PIL import Image from PIL import ImageFileIO -def test_fileio(): - class DumbFile: - def __init__(self, data): - self.data = data - def read(self, bytes=None): - assert_equal(bytes, None) - return self.data - def close(self): - pass +class TestImageFileIo(PillowTestCase): - im1 = lena() + def test_fileio(self): - io = ImageFileIO.ImageFileIO(DumbFile(tostring(im1, "PPM"))) + class DumbFile: + def __init__(self, data): + self.data = data - im2 = Image.open(io) - assert_image_equal(im1, im2) + def read(self, bytes=None): + assert(bytes is None) + return self.data + + def close(self): + pass + + im1 = lena() + + io = ImageFileIO.ImageFileIO(DumbFile(tostring(im1, "PPM"))) + + im2 = Image.open(io) + self.assert_image_equal(im1, im2) +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_imagefilter.py b/Tests/test_imagefilter.py index 214f88024..3dcb1d14f 100644 --- a/Tests/test_imagefilter.py +++ b/Tests/test_imagefilter.py @@ -1,31 +1,37 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule -from PIL import Image from PIL import ImageFilter -def test_sanity(): - # see test_image_filter for more tests - assert_no_exception(lambda: ImageFilter.MaxFilter) - assert_no_exception(lambda: ImageFilter.MedianFilter) - assert_no_exception(lambda: ImageFilter.MinFilter) - assert_no_exception(lambda: ImageFilter.ModeFilter) - assert_no_exception(lambda: ImageFilter.Kernel((3, 3), list(range(9)))) - assert_no_exception(lambda: ImageFilter.GaussianBlur) - assert_no_exception(lambda: ImageFilter.GaussianBlur(5)) - assert_no_exception(lambda: ImageFilter.UnsharpMask) - assert_no_exception(lambda: ImageFilter.UnsharpMask(10)) +class TestImageFilter(PillowTestCase): - assert_no_exception(lambda: ImageFilter.BLUR) - assert_no_exception(lambda: ImageFilter.CONTOUR) - assert_no_exception(lambda: ImageFilter.DETAIL) - assert_no_exception(lambda: ImageFilter.EDGE_ENHANCE) - assert_no_exception(lambda: ImageFilter.EDGE_ENHANCE_MORE) - assert_no_exception(lambda: ImageFilter.EMBOSS) - assert_no_exception(lambda: ImageFilter.FIND_EDGES) - assert_no_exception(lambda: ImageFilter.SMOOTH) - assert_no_exception(lambda: ImageFilter.SMOOTH_MORE) - assert_no_exception(lambda: ImageFilter.SHARPEN) + def test_sanity(self): + # see test_image_filter for more tests + + # Check these run. Exceptions cause failures. + ImageFilter.MaxFilter + ImageFilter.MedianFilter + ImageFilter.MinFilter + ImageFilter.ModeFilter + ImageFilter.Kernel((3, 3), list(range(9))) + ImageFilter.GaussianBlur + ImageFilter.GaussianBlur(5) + ImageFilter.UnsharpMask + ImageFilter.UnsharpMask(10) + + ImageFilter.BLUR + ImageFilter.CONTOUR + ImageFilter.DETAIL + ImageFilter.EDGE_ENHANCE + ImageFilter.EDGE_ENHANCE_MORE + ImageFilter.EMBOSS + ImageFilter.FIND_EDGES + ImageFilter.SMOOTH + ImageFilter.SMOOTH_MORE + ImageFilter.SHARPEN +if __name__ == '__main__': + unittest.main() +# End of file diff --git a/Tests/test_imagefont.py b/Tests/test_imagefont.py index 9ac2cdd89..927c80bee 100644 --- a/Tests/test_imagefont.py +++ b/Tests/test_imagefont.py @@ -1,135 +1,145 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule from PIL import Image +from PIL import ImageDraw from io import BytesIO import os +font_path = "Tests/fonts/FreeMono.ttf" +font_size = 20 + + try: from PIL import ImageFont - ImageFont.core.getfont # check if freetype is available + ImageFont.core.getfont # check if freetype is available + + class TestImageFont(PillowTestCase): + + def test_sanity(self): + self.assertRegexpMatches( + ImageFont.core.freetype2_version, "\d+\.\d+\.\d+$") + + def test_font_with_name(self): + ImageFont.truetype(font_path, font_size) + self._render(font_path) + self._clean() + + def _font_as_bytes(self): + with open(font_path, 'rb') as f: + font_bytes = BytesIO(f.read()) + return font_bytes + + def test_font_with_filelike(self): + ImageFont.truetype(self._font_as_bytes(), font_size) + self._render(self._font_as_bytes()) + # Usage note: making two fonts from the same buffer fails. + # shared_bytes = self._font_as_bytes() + # self._render(shared_bytes) + # self.assertRaises(Exception, lambda: _render(shared_bytes)) + self._clean() + + def test_font_with_open_file(self): + with open(font_path, 'rb') as f: + self._render(f) + self._clean() + + def test_font_old_parameters(self): + self.assert_warning( + DeprecationWarning, + lambda: ImageFont.truetype(filename=font_path, size=font_size)) + + def _render(self, font): + txt = "Hello World!" + ttf = ImageFont.truetype(font, font_size) + w, h = ttf.getsize(txt) + img = Image.new("RGB", (256, 64), "white") + d = ImageDraw.Draw(img) + d.text((10, 10), txt, font=ttf, fill='black') + + img.save('font.png') + return img + + def _clean(self): + os.unlink('font.png') + + def test_render_equal(self): + img_path = self._render(font_path) + with open(font_path, 'rb') as f: + font_filelike = BytesIO(f.read()) + img_filelike = self._render(font_filelike) + + self.assert_image_equal(img_path, img_filelike) + self._clean() + + def test_render_multiline(self): + im = Image.new(mode='RGB', size=(300, 100)) + draw = ImageDraw.Draw(im) + ttf = ImageFont.truetype(font_path, font_size) + line_spacing = draw.textsize('A', font=ttf)[1] + 8 + lines = ['hey you', 'you are awesome', 'this looks awkward'] + y = 0 + for line in lines: + draw.text((0, y), line, font=ttf) + y += line_spacing + + target = 'Tests/images/multiline_text.png' + target_img = Image.open(target) + + # some versions of freetype have different horizontal spacing. + # setting a tight epsilon, I'm showing the original test failure + # at epsilon = ~38. + self.assert_image_similar(im, target_img, .5) + + def test_rotated_transposed_font(self): + img_grey = Image.new("L", (100, 100)) + draw = ImageDraw.Draw(img_grey) + word = "testing" + font = ImageFont.truetype(font_path, font_size) + + orientation = Image.ROTATE_90 + transposed_font = ImageFont.TransposedFont( + font, orientation=orientation) + + # Original font + draw.setfont(font) + box_size_a = draw.textsize(word) + + # Rotated font + draw.setfont(transposed_font) + box_size_b = draw.textsize(word) + + # Check (w,h) of box a is (h,w) of box b + self.assertEqual(box_size_a[0], box_size_b[1]) + self.assertEqual(box_size_a[1], box_size_b[0]) + + def test_unrotated_transposed_font(self): + img_grey = Image.new("L", (100, 100)) + draw = ImageDraw.Draw(img_grey) + word = "testing" + font = ImageFont.truetype(font_path, font_size) + + orientation = None + transposed_font = ImageFont.TransposedFont( + font, orientation=orientation) + + # Original font + draw.setfont(font) + box_size_a = draw.textsize(word) + + # Rotated font + draw.setfont(transposed_font) + box_size_b = draw.textsize(word) + + # Check boxes a and b are same size + self.assertEqual(box_size_a, box_size_b) + except ImportError: - skip() - -from PIL import ImageDraw - -font_path = "Tests/fonts/FreeMono.ttf" -font_size=20 - -def test_sanity(): - assert_match(ImageFont.core.freetype2_version, "\d+\.\d+\.\d+$") - -def test_font_with_name(): - assert_no_exception(lambda: ImageFont.truetype(font_path, font_size)) - assert_no_exception(lambda: _render(font_path)) - _clean() - -def _font_as_bytes(): - with open(font_path, 'rb') as f: - font_bytes = BytesIO(f.read()) - return font_bytes - -def test_font_with_filelike(): - assert_no_exception(lambda: ImageFont.truetype(_font_as_bytes(), font_size)) - assert_no_exception(lambda: _render(_font_as_bytes())) - # Usage note: making two fonts from the same buffer fails. - #shared_bytes = _font_as_bytes() - #assert_no_exception(lambda: _render(shared_bytes)) - #assert_exception(Exception, lambda: _render(shared_bytes)) - _clean() - -def test_font_with_open_file(): - with open(font_path, 'rb') as f: - assert_no_exception(lambda: _render(f)) - _clean() - -def test_font_old_parameters(): - assert_warning(DeprecationWarning, lambda: ImageFont.truetype(filename=font_path, size=font_size)) - -def _render(font): - txt = "Hello World!" - ttf = ImageFont.truetype(font, font_size) - w, h = ttf.getsize(txt) - img = Image.new("RGB", (256, 64), "white") - d = ImageDraw.Draw(img) - d.text((10, 10), txt, font=ttf, fill='black') - - img.save('font.png') - return img - -def _clean(): - os.unlink('font.png') - -def test_render_equal(): - img_path = _render(font_path) - with open(font_path, 'rb') as f: - font_filelike = BytesIO(f.read()) - img_filelike = _render(font_filelike) - - assert_image_equal(img_path, img_filelike) - _clean() + class TestImageFont(PillowTestCase): + def test_skip(self): + self.skipTest("ImportError") -def test_render_multiline(): - im = Image.new(mode='RGB', size=(300,100)) - draw = ImageDraw.Draw(im) - ttf = ImageFont.truetype(font_path, font_size) - line_spacing = draw.textsize('A', font=ttf)[1] + 8 - lines = ['hey you', 'you are awesome', 'this looks awkward'] - y = 0 - for line in lines: - draw.text((0, y), line, font=ttf) - y += line_spacing - - - target = 'Tests/images/multiline_text.png' - target_img = Image.open(target) - - # some versions of freetype have different horizontal spacing. - # setting a tight epsilon, I'm showing the original test failure - # at epsilon = ~38. - assert_image_similar(im, target_img,.5) - - -def test_rotated_transposed_font(): - img_grey = Image.new("L", (100, 100)) - draw = ImageDraw.Draw(img_grey) - word = "testing" - font = ImageFont.truetype(font_path, font_size) - - orientation = Image.ROTATE_90 - transposed_font = ImageFont.TransposedFont(font, orientation=orientation) - - # Original font - draw.setfont(font) - box_size_a = draw.textsize(word) - - # Rotated font - draw.setfont(transposed_font) - box_size_b = draw.textsize(word) - - # Check (w,h) of box a is (h,w) of box b - assert_equal(box_size_a[0], box_size_b[1]) - assert_equal(box_size_a[1], box_size_b[0]) - - -def test_unrotated_transposed_font(): - img_grey = Image.new("L", (100, 100)) - draw = ImageDraw.Draw(img_grey) - word = "testing" - font = ImageFont.truetype(font_path, font_size) - - orientation = None - transposed_font = ImageFont.TransposedFont(font, orientation=orientation) - - # Original font - draw.setfont(font) - box_size_a = draw.textsize(word) - - # Rotated font - draw.setfont(transposed_font) - box_size_b = draw.textsize(word) - - # Check boxes a and b are same size - assert_equal(box_size_a, box_size_b) - +if __name__ == '__main__': + unittest.main() +# End of file diff --git a/Tests/test_imagegrab.py b/Tests/test_imagegrab.py index 67ff71960..a6c50fb31 100644 --- a/Tests/test_imagegrab.py +++ b/Tests/test_imagegrab.py @@ -1,13 +1,25 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule -from PIL import Image try: from PIL import ImageGrab -except ImportError as v: - skip(v) -def test_grab(): - im = ImageGrab.grab() - assert_image(im, im.mode, im.size) + class TestImageCopy(PillowTestCase): + + def test_grab(self): + im = ImageGrab.grab() + self.assert_image(im, im.mode, im.size) + + def test_grab2(self): + im = ImageGrab.grab() + self.assert_image(im, im.mode, im.size) + +except ImportError: + class TestImageCopy(PillowTestCase): + def test_skip(self): + self.skipTest("ImportError") +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_imagemath.py b/Tests/test_imagemath.py index eaeb711ba..35d75dbbd 100644 --- a/Tests/test_imagemath.py +++ b/Tests/test_imagemath.py @@ -1,14 +1,15 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule from PIL import Image from PIL import ImageMath + def pixel(im): if hasattr(im, "im"): return "%s %r" % (im.mode, im.getpixel((0, 0))) else: if isinstance(im, type(0)): - return int(im) # hack to deal with booleans + return int(im) # hack to deal with booleans print(im) A = Image.new("L", (1, 1), 1) @@ -18,45 +19,60 @@ I = Image.new("I", (1, 1), 4) images = {"A": A, "B": B, "F": F, "I": I} -def test_sanity(): - assert_equal(ImageMath.eval("1"), 1) - assert_equal(ImageMath.eval("1+A", A=2), 3) - assert_equal(pixel(ImageMath.eval("A+B", A=A, B=B)), "I 3") - assert_equal(pixel(ImageMath.eval("A+B", images)), "I 3") - assert_equal(pixel(ImageMath.eval("float(A)+B", images)), "F 3.0") - assert_equal(pixel(ImageMath.eval("int(float(A)+B)", images)), "I 3") -def test_ops(): +class TestImageMath(PillowTestCase): - assert_equal(pixel(ImageMath.eval("-A", images)), "I -1") - assert_equal(pixel(ImageMath.eval("+B", images)), "L 2") + def test_sanity(self): + self.assertEqual(ImageMath.eval("1"), 1) + self.assertEqual(ImageMath.eval("1+A", A=2), 3) + self.assertEqual(pixel(ImageMath.eval("A+B", A=A, B=B)), "I 3") + self.assertEqual(pixel(ImageMath.eval("A+B", images)), "I 3") + self.assertEqual(pixel(ImageMath.eval("float(A)+B", images)), "F 3.0") + self.assertEqual(pixel( + ImageMath.eval("int(float(A)+B)", images)), "I 3") - assert_equal(pixel(ImageMath.eval("A+B", images)), "I 3") - assert_equal(pixel(ImageMath.eval("A-B", images)), "I -1") - assert_equal(pixel(ImageMath.eval("A*B", images)), "I 2") - assert_equal(pixel(ImageMath.eval("A/B", images)), "I 0") - assert_equal(pixel(ImageMath.eval("B**2", images)), "I 4") - assert_equal(pixel(ImageMath.eval("B**33", images)), "I 2147483647") + def test_ops(self): - assert_equal(pixel(ImageMath.eval("float(A)+B", images)), "F 3.0") - assert_equal(pixel(ImageMath.eval("float(A)-B", images)), "F -1.0") - assert_equal(pixel(ImageMath.eval("float(A)*B", images)), "F 2.0") - assert_equal(pixel(ImageMath.eval("float(A)/B", images)), "F 0.5") - assert_equal(pixel(ImageMath.eval("float(B)**2", images)), "F 4.0") - assert_equal(pixel(ImageMath.eval("float(B)**33", images)), "F 8589934592.0") + self.assertEqual(pixel(ImageMath.eval("-A", images)), "I -1") + self.assertEqual(pixel(ImageMath.eval("+B", images)), "L 2") -def test_logical(): - assert_equal(pixel(ImageMath.eval("not A", images)), 0) - assert_equal(pixel(ImageMath.eval("A and B", images)), "L 2") - assert_equal(pixel(ImageMath.eval("A or B", images)), "L 1") + self.assertEqual(pixel(ImageMath.eval("A+B", images)), "I 3") + self.assertEqual(pixel(ImageMath.eval("A-B", images)), "I -1") + self.assertEqual(pixel(ImageMath.eval("A*B", images)), "I 2") + self.assertEqual(pixel(ImageMath.eval("A/B", images)), "I 0") + self.assertEqual(pixel(ImageMath.eval("B**2", images)), "I 4") + self.assertEqual(pixel( + ImageMath.eval("B**33", images)), "I 2147483647") -def test_convert(): - assert_equal(pixel(ImageMath.eval("convert(A+B, 'L')", images)), "L 3") - assert_equal(pixel(ImageMath.eval("convert(A+B, '1')", images)), "1 0") - assert_equal(pixel(ImageMath.eval("convert(A+B, 'RGB')", images)), "RGB (3, 3, 3)") + self.assertEqual(pixel(ImageMath.eval("float(A)+B", images)), "F 3.0") + self.assertEqual(pixel(ImageMath.eval("float(A)-B", images)), "F -1.0") + self.assertEqual(pixel(ImageMath.eval("float(A)*B", images)), "F 2.0") + self.assertEqual(pixel(ImageMath.eval("float(A)/B", images)), "F 0.5") + self.assertEqual(pixel(ImageMath.eval("float(B)**2", images)), "F 4.0") + self.assertEqual(pixel( + ImageMath.eval("float(B)**33", images)), "F 8589934592.0") -def test_compare(): - assert_equal(pixel(ImageMath.eval("min(A, B)", images)), "I 1") - assert_equal(pixel(ImageMath.eval("max(A, B)", images)), "I 2") - assert_equal(pixel(ImageMath.eval("A == 1", images)), "I 1") - assert_equal(pixel(ImageMath.eval("A == 2", images)), "I 0") + def test_logical(self): + self.assertEqual(pixel(ImageMath.eval("not A", images)), 0) + self.assertEqual(pixel(ImageMath.eval("A and B", images)), "L 2") + self.assertEqual(pixel(ImageMath.eval("A or B", images)), "L 1") + + def test_convert(self): + self.assertEqual(pixel( + ImageMath.eval("convert(A+B, 'L')", images)), "L 3") + self.assertEqual(pixel( + ImageMath.eval("convert(A+B, '1')", images)), "1 0") + self.assertEqual(pixel( + ImageMath.eval("convert(A+B, 'RGB')", images)), "RGB (3, 3, 3)") + + def test_compare(self): + self.assertEqual(pixel(ImageMath.eval("min(A, B)", images)), "I 1") + self.assertEqual(pixel(ImageMath.eval("max(A, B)", images)), "I 2") + self.assertEqual(pixel(ImageMath.eval("A == 1", images)), "I 1") + self.assertEqual(pixel(ImageMath.eval("A == 2", images)), "I 0") + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_imagemode.py b/Tests/test_imagemode.py index 54b04435f..7febc697e 100644 --- a/Tests/test_imagemode.py +++ b/Tests/test_imagemode.py @@ -1,23 +1,32 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule -from PIL import Image from PIL import ImageMode -ImageMode.getmode("1") -ImageMode.getmode("L") -ImageMode.getmode("P") -ImageMode.getmode("RGB") -ImageMode.getmode("I") -ImageMode.getmode("F") -m = ImageMode.getmode("1") -assert_equal(m.mode, "1") -assert_equal(m.bands, ("1",)) -assert_equal(m.basemode, "L") -assert_equal(m.basetype, "L") +class TestImageMode(PillowTestCase): -m = ImageMode.getmode("RGB") -assert_equal(m.mode, "RGB") -assert_equal(m.bands, ("R", "G", "B")) -assert_equal(m.basemode, "RGB") -assert_equal(m.basetype, "L") + def test_sanity(self): + ImageMode.getmode("1") + ImageMode.getmode("L") + ImageMode.getmode("P") + ImageMode.getmode("RGB") + ImageMode.getmode("I") + ImageMode.getmode("F") + + m = ImageMode.getmode("1") + self.assertEqual(m.mode, "1") + self.assertEqual(m.bands, ("1",)) + self.assertEqual(m.basemode, "L") + self.assertEqual(m.basetype, "L") + + m = ImageMode.getmode("RGB") + self.assertEqual(m.mode, "RGB") + self.assertEqual(m.bands, ("R", "G", "B")) + self.assertEqual(m.basemode, "RGB") + self.assertEqual(m.basetype, "L") + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_imageops.py b/Tests/test_imageops.py index 8ed5ccefa..299a7c618 100644 --- a/Tests/test_imageops.py +++ b/Tests/test_imageops.py @@ -1,81 +1,85 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule, lena -from PIL import Image from PIL import ImageOps -class Deformer: - def getmesh(self, im): - x, y = im.size - return [((0, 0, x, y), (0, 0, x, 0, x, y, y, 0))] -deformer = Deformer() +class TestImageOps(PillowTestCase): -def test_sanity(): + class Deformer: + def getmesh(self, im): + x, y = im.size + return [((0, 0, x, y), (0, 0, x, 0, x, y, y, 0))] - ImageOps.autocontrast(lena("L")) - ImageOps.autocontrast(lena("RGB")) + deformer = Deformer() - ImageOps.autocontrast(lena("L"), cutoff=10) - ImageOps.autocontrast(lena("L"), ignore=[0, 255]) + def test_sanity(self): - ImageOps.colorize(lena("L"), (0, 0, 0), (255, 255, 255)) - ImageOps.colorize(lena("L"), "black", "white") + ImageOps.autocontrast(lena("L")) + ImageOps.autocontrast(lena("RGB")) - ImageOps.crop(lena("L"), 1) - ImageOps.crop(lena("RGB"), 1) + ImageOps.autocontrast(lena("L"), cutoff=10) + ImageOps.autocontrast(lena("L"), ignore=[0, 255]) - ImageOps.deform(lena("L"), deformer) - ImageOps.deform(lena("RGB"), deformer) + ImageOps.colorize(lena("L"), (0, 0, 0), (255, 255, 255)) + ImageOps.colorize(lena("L"), "black", "white") - ImageOps.equalize(lena("L")) - ImageOps.equalize(lena("RGB")) + ImageOps.crop(lena("L"), 1) + ImageOps.crop(lena("RGB"), 1) - ImageOps.expand(lena("L"), 1) - ImageOps.expand(lena("RGB"), 1) - ImageOps.expand(lena("L"), 2, "blue") - ImageOps.expand(lena("RGB"), 2, "blue") + ImageOps.deform(lena("L"), self.deformer) + ImageOps.deform(lena("RGB"), self.deformer) - ImageOps.fit(lena("L"), (128, 128)) - ImageOps.fit(lena("RGB"), (128, 128)) + ImageOps.equalize(lena("L")) + ImageOps.equalize(lena("RGB")) - ImageOps.flip(lena("L")) - ImageOps.flip(lena("RGB")) + ImageOps.expand(lena("L"), 1) + ImageOps.expand(lena("RGB"), 1) + ImageOps.expand(lena("L"), 2, "blue") + ImageOps.expand(lena("RGB"), 2, "blue") - ImageOps.grayscale(lena("L")) - ImageOps.grayscale(lena("RGB")) + ImageOps.fit(lena("L"), (128, 128)) + ImageOps.fit(lena("RGB"), (128, 128)) - ImageOps.invert(lena("L")) - ImageOps.invert(lena("RGB")) + ImageOps.flip(lena("L")) + ImageOps.flip(lena("RGB")) - ImageOps.mirror(lena("L")) - ImageOps.mirror(lena("RGB")) + ImageOps.grayscale(lena("L")) + ImageOps.grayscale(lena("RGB")) - ImageOps.posterize(lena("L"), 4) - ImageOps.posterize(lena("RGB"), 4) + ImageOps.invert(lena("L")) + ImageOps.invert(lena("RGB")) - ImageOps.solarize(lena("L")) - ImageOps.solarize(lena("RGB")) + ImageOps.mirror(lena("L")) + ImageOps.mirror(lena("RGB")) - success() + ImageOps.posterize(lena("L"), 4) + ImageOps.posterize(lena("RGB"), 4) -def test_1pxfit(): - # Division by zero in equalize if image is 1 pixel high - newimg = ImageOps.fit(lena("RGB").resize((1,1)), (35,35)) - assert_equal(newimg.size,(35,35)) - - newimg = ImageOps.fit(lena("RGB").resize((1,100)), (35,35)) - assert_equal(newimg.size,(35,35)) + ImageOps.solarize(lena("L")) + ImageOps.solarize(lena("RGB")) - newimg = ImageOps.fit(lena("RGB").resize((100,1)), (35,35)) - assert_equal(newimg.size,(35,35)) + def test_1pxfit(self): + # Division by zero in equalize if image is 1 pixel high + newimg = ImageOps.fit(lena("RGB").resize((1, 1)), (35, 35)) + self.assertEqual(newimg.size, (35, 35)) -def test_pil163(): - # Division by zero in equalize if < 255 pixels in image (@PIL163) + newimg = ImageOps.fit(lena("RGB").resize((1, 100)), (35, 35)) + self.assertEqual(newimg.size, (35, 35)) - i = lena("RGB").resize((15, 16)) + newimg = ImageOps.fit(lena("RGB").resize((100, 1)), (35, 35)) + self.assertEqual(newimg.size, (35, 35)) - ImageOps.equalize(i.convert("L")) - ImageOps.equalize(i.convert("P")) - ImageOps.equalize(i.convert("RGB")) + def test_pil163(self): + # Division by zero in equalize if < 255 pixels in image (@PIL163) - success() + i = lena("RGB").resize((15, 16)) + + ImageOps.equalize(i.convert("L")) + ImageOps.equalize(i.convert("P")) + ImageOps.equalize(i.convert("RGB")) + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_imageops_usm.py b/Tests/test_imageops_usm.py index 83a93b8e0..2f81eebce 100644 --- a/Tests/test_imageops_usm.py +++ b/Tests/test_imageops_usm.py @@ -1,4 +1,4 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule from PIL import Image from PIL import ImageOps @@ -6,50 +6,59 @@ from PIL import ImageFilter im = Image.open("Images/lena.ppm") -def test_ops_api(): - i = ImageOps.gaussian_blur(im, 2.0) - assert_equal(i.mode, "RGB") - assert_equal(i.size, (128, 128)) - # i.save("blur.bmp") +class TestImageOpsUsm(PillowTestCase): - i = ImageOps.usm(im, 2.0, 125, 8) - assert_equal(i.mode, "RGB") - assert_equal(i.size, (128, 128)) - # i.save("usm.bmp") + def test_ops_api(self): -def test_filter_api(): + i = ImageOps.gaussian_blur(im, 2.0) + self.assertEqual(i.mode, "RGB") + self.assertEqual(i.size, (128, 128)) + # i.save("blur.bmp") - filter = ImageFilter.GaussianBlur(2.0) - i = im.filter(filter) - assert_equal(i.mode, "RGB") - assert_equal(i.size, (128, 128)) + i = ImageOps.usm(im, 2.0, 125, 8) + self.assertEqual(i.mode, "RGB") + self.assertEqual(i.size, (128, 128)) + # i.save("usm.bmp") - filter = ImageFilter.UnsharpMask(2.0, 125, 8) - i = im.filter(filter) - assert_equal(i.mode, "RGB") - assert_equal(i.size, (128, 128)) + def test_filter_api(self): -def test_usm(): + filter = ImageFilter.GaussianBlur(2.0) + i = im.filter(filter) + self.assertEqual(i.mode, "RGB") + self.assertEqual(i.size, (128, 128)) - usm = ImageOps.unsharp_mask - assert_exception(ValueError, lambda: usm(im.convert("1"))) - assert_no_exception(lambda: usm(im.convert("L"))) - assert_exception(ValueError, lambda: usm(im.convert("I"))) - assert_exception(ValueError, lambda: usm(im.convert("F"))) - assert_no_exception(lambda: usm(im.convert("RGB"))) - assert_no_exception(lambda: usm(im.convert("RGBA"))) - assert_no_exception(lambda: usm(im.convert("CMYK"))) - assert_exception(ValueError, lambda: usm(im.convert("YCbCr"))) + filter = ImageFilter.UnsharpMask(2.0, 125, 8) + i = im.filter(filter) + self.assertEqual(i.mode, "RGB") + self.assertEqual(i.size, (128, 128)) -def test_blur(): + def test_usm(self): - blur = ImageOps.gaussian_blur - assert_exception(ValueError, lambda: blur(im.convert("1"))) - assert_no_exception(lambda: blur(im.convert("L"))) - assert_exception(ValueError, lambda: blur(im.convert("I"))) - assert_exception(ValueError, lambda: blur(im.convert("F"))) - assert_no_exception(lambda: blur(im.convert("RGB"))) - assert_no_exception(lambda: blur(im.convert("RGBA"))) - assert_no_exception(lambda: blur(im.convert("CMYK"))) - assert_exception(ValueError, lambda: blur(im.convert("YCbCr"))) + usm = ImageOps.unsharp_mask + self.assertRaises(ValueError, lambda: usm(im.convert("1"))) + usm(im.convert("L")) + self.assertRaises(ValueError, lambda: usm(im.convert("I"))) + self.assertRaises(ValueError, lambda: usm(im.convert("F"))) + usm(im.convert("RGB")) + usm(im.convert("RGBA")) + usm(im.convert("CMYK")) + self.assertRaises(ValueError, lambda: usm(im.convert("YCbCr"))) + + def test_blur(self): + + blur = ImageOps.gaussian_blur + self.assertRaises(ValueError, lambda: blur(im.convert("1"))) + blur(im.convert("L")) + self.assertRaises(ValueError, lambda: blur(im.convert("I"))) + self.assertRaises(ValueError, lambda: blur(im.convert("F"))) + blur(im.convert("RGB")) + blur(im.convert("RGBA")) + blur(im.convert("CMYK")) + self.assertRaises(ValueError, lambda: blur(im.convert("YCbCr"))) + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_imagepalette.py b/Tests/test_imagepalette.py index a22addda9..4d7e067f4 100644 --- a/Tests/test_imagepalette.py +++ b/Tests/test_imagepalette.py @@ -1,44 +1,50 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule -from PIL import Image from PIL import ImagePalette ImagePalette = ImagePalette.ImagePalette -def test_sanity(): - assert_no_exception(lambda: ImagePalette("RGB", list(range(256))*3)) - assert_exception(ValueError, lambda: ImagePalette("RGB", list(range(256))*2)) +class TestImagePalette(PillowTestCase): -def test_getcolor(): + def test_sanity(self): - palette = ImagePalette() + ImagePalette("RGB", list(range(256))*3) + self.assertRaises( + ValueError, lambda: ImagePalette("RGB", list(range(256))*2)) - map = {} - for i in range(256): - map[palette.getcolor((i, i, i))] = i + def test_getcolor(self): - assert_equal(len(map), 256) - assert_exception(ValueError, lambda: palette.getcolor((1, 2, 3))) + palette = ImagePalette() -def test_file(): + map = {} + for i in range(256): + map[palette.getcolor((i, i, i))] = i - palette = ImagePalette() + self.assertEqual(len(map), 256) + self.assertRaises(ValueError, lambda: palette.getcolor((1, 2, 3))) - file = tempfile("temp.lut") + def test_file(self): - palette.save(file) + palette = ImagePalette() - from PIL.ImagePalette import load, raw + file = self.tempfile("temp.lut") - p = load(file) + palette.save(file) - # load returns raw palette information - assert_equal(len(p[0]), 768) - assert_equal(p[1], "RGB") + from PIL.ImagePalette import load, raw - p = raw(p[1], p[0]) - assert_true(isinstance(p, ImagePalette)) + p = load(file) + + # load returns raw palette information + self.assertEqual(len(p[0]), 768) + self.assertEqual(p[1], "RGB") + + p = raw(p[1], p[0]) + self.assertIsInstance(p, ImagePalette) +if __name__ == '__main__': + unittest.main() +# End of file diff --git a/Tests/test_imagepath.py b/Tests/test_imagepath.py index 9e9e63c3a..c293e4225 100644 --- a/Tests/test_imagepath.py +++ b/Tests/test_imagepath.py @@ -1,54 +1,68 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule -from PIL import Image from PIL import ImagePath import array -def test_path(): - p = ImagePath.Path(list(range(10))) +class TestImagePath(PillowTestCase): - # sequence interface - assert_equal(len(p), 5) - assert_equal(p[0], (0.0, 1.0)) - assert_equal(p[-1], (8.0, 9.0)) - assert_equal(list(p[:1]), [(0.0, 1.0)]) - assert_equal(list(p), [(0.0, 1.0), (2.0, 3.0), (4.0, 5.0), (6.0, 7.0), (8.0, 9.0)]) + def test_path(self): - # method sanity check - assert_equal(p.tolist(), [(0.0, 1.0), (2.0, 3.0), (4.0, 5.0), (6.0, 7.0), (8.0, 9.0)]) - assert_equal(p.tolist(1), [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]) + p = ImagePath.Path(list(range(10))) - assert_equal(p.getbbox(), (0.0, 1.0, 8.0, 9.0)) + # sequence interface + self.assertEqual(len(p), 5) + self.assertEqual(p[0], (0.0, 1.0)) + self.assertEqual(p[-1], (8.0, 9.0)) + self.assertEqual(list(p[:1]), [(0.0, 1.0)]) + self.assertEqual( + list(p), + [(0.0, 1.0), (2.0, 3.0), (4.0, 5.0), (6.0, 7.0), (8.0, 9.0)]) - assert_equal(p.compact(5), 2) - assert_equal(list(p), [(0.0, 1.0), (4.0, 5.0), (8.0, 9.0)]) + # method sanity check + self.assertEqual( + p.tolist(), + [(0.0, 1.0), (2.0, 3.0), (4.0, 5.0), (6.0, 7.0), (8.0, 9.0)]) + self.assertEqual( + p.tolist(1), + [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]) - p.transform((1,0,1,0,1,1)) - assert_equal(list(p), [(1.0, 2.0), (5.0, 6.0), (9.0, 10.0)]) + self.assertEqual(p.getbbox(), (0.0, 1.0, 8.0, 9.0)) - # alternative constructors - p = ImagePath.Path([0, 1]) - assert_equal(list(p), [(0.0, 1.0)]) - p = ImagePath.Path([0.0, 1.0]) - assert_equal(list(p), [(0.0, 1.0)]) - p = ImagePath.Path([0, 1]) - assert_equal(list(p), [(0.0, 1.0)]) - p = ImagePath.Path([(0, 1)]) - assert_equal(list(p), [(0.0, 1.0)]) - p = ImagePath.Path(p) - assert_equal(list(p), [(0.0, 1.0)]) - p = ImagePath.Path(p.tolist(0)) - assert_equal(list(p), [(0.0, 1.0)]) - p = ImagePath.Path(p.tolist(1)) - assert_equal(list(p), [(0.0, 1.0)]) - p = ImagePath.Path(array.array("f", [0, 1])) - assert_equal(list(p), [(0.0, 1.0)]) + self.assertEqual(p.compact(5), 2) + self.assertEqual(list(p), [(0.0, 1.0), (4.0, 5.0), (8.0, 9.0)]) - arr = array.array("f", [0, 1]) - if hasattr(arr, 'tobytes'): - p = ImagePath.Path(arr.tobytes()) - else: - p = ImagePath.Path(arr.tostring()) - assert_equal(list(p), [(0.0, 1.0)]) + p.transform((1, 0, 1, 0, 1, 1)) + self.assertEqual(list(p), [(1.0, 2.0), (5.0, 6.0), (9.0, 10.0)]) + + # alternative constructors + p = ImagePath.Path([0, 1]) + self.assertEqual(list(p), [(0.0, 1.0)]) + p = ImagePath.Path([0.0, 1.0]) + self.assertEqual(list(p), [(0.0, 1.0)]) + p = ImagePath.Path([0, 1]) + self.assertEqual(list(p), [(0.0, 1.0)]) + p = ImagePath.Path([(0, 1)]) + self.assertEqual(list(p), [(0.0, 1.0)]) + p = ImagePath.Path(p) + self.assertEqual(list(p), [(0.0, 1.0)]) + p = ImagePath.Path(p.tolist(0)) + self.assertEqual(list(p), [(0.0, 1.0)]) + p = ImagePath.Path(p.tolist(1)) + self.assertEqual(list(p), [(0.0, 1.0)]) + p = ImagePath.Path(array.array("f", [0, 1])) + self.assertEqual(list(p), [(0.0, 1.0)]) + + arr = array.array("f", [0, 1]) + if hasattr(arr, 'tobytes'): + p = ImagePath.Path(arr.tobytes()) + else: + p = ImagePath.Path(arr.tostring()) + self.assertEqual(list(p), [(0.0, 1.0)]) + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_imageqt.py b/Tests/test_imageqt.py index 73d1f4b1c..549fc7fd6 100644 --- a/Tests/test_imageqt.py +++ b/Tests/test_imageqt.py @@ -1,37 +1,53 @@ -from tester import * - -from PIL import Image +from helper import unittest, PillowTestCase, tearDownModule, lena try: + from PIL import ImageQt from PyQt5.QtGui import QImage, qRgb, qRgba except: try: from PyQt4.QtGui import QImage, qRgb, qRgba except: - skip('PyQT4 or 5 not installed') - -from PIL import ImageQt - -def test_rgb(): - # from https://qt-project.org/doc/qt-4.8/qcolor.html - # typedef QRgb - # An ARGB quadruplet on the format #AARRGGBB, equivalent to an unsigned int. - - assert_equal(qRgb(0,0,0), qRgba(0,0,0,255)) - - def checkrgb(r,g,b): - val = ImageQt.rgb(r,g,b) - val = val % 2**24 # drop the alpha - assert_equal(val >> 16, r) - assert_equal(((val >> 8 ) % 2**8), g) - assert_equal(val % 2**8, b) - - checkrgb(0,0,0) - checkrgb(255,0,0) - checkrgb(0,255,0) - checkrgb(0,0,255) + # Will be skipped in setUp + pass -def test_image(): - for mode in ('1', 'RGB', 'RGBA', 'L', 'P'): - assert_no_exception(lambda: ImageQt.ImageQt(lena(mode))) +class TestImageQt(PillowTestCase): + + def setUp(self): + try: + from PyQt5.QtGui import QImage, qRgb, qRgba + except: + try: + from PyQt4.QtGui import QImage, qRgb, qRgba + except: + self.skipTest('PyQt4 or 5 not installed') + + def test_rgb(self): + # from https://qt-project.org/doc/qt-4.8/qcolor.html + # typedef QRgb + # An ARGB quadruplet on the format #AARRGGBB, + # equivalent to an unsigned int. + + self.assertEqual(qRgb(0, 0, 0), qRgba(0, 0, 0, 255)) + + def checkrgb(r, g, b): + val = ImageQt.rgb(r, g, b) + val = val % 2**24 # drop the alpha + self.assertEqual(val >> 16, r) + self.assertEqual(((val >> 8) % 2**8), g) + self.assertEqual(val % 2**8, b) + + checkrgb(0, 0, 0) + checkrgb(255, 0, 0) + checkrgb(0, 255, 0) + checkrgb(0, 0, 255) + + def test_image(self): + for mode in ('1', 'RGB', 'RGBA', 'L', 'P'): + ImageQt.ImageQt(lena(mode)) + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_imagesequence.py b/Tests/test_imagesequence.py index 3329b1a05..9001502ac 100644 --- a/Tests/test_imagesequence.py +++ b/Tests/test_imagesequence.py @@ -1,22 +1,29 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule, lena -from PIL import Image from PIL import ImageSequence -def test_sanity(): - file = tempfile("temp.im") +class TestImageSequence(PillowTestCase): - im = lena("RGB") - im.save(file) + def test_sanity(self): - seq = ImageSequence.Iterator(im) + file = self.tempfile("temp.im") - index = 0 - for frame in seq: - assert_image_equal(im, frame) - assert_equal(im.tell(), index) - index = index + 1 + im = lena("RGB") + im.save(file) - assert_equal(index, 1) + seq = ImageSequence.Iterator(im) + index = 0 + for frame in seq: + self.assert_image_equal(im, frame) + self.assertEqual(im.tell(), index) + index = index + 1 + + self.assertEqual(index, 1) + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_imageshow.py b/Tests/test_imageshow.py index 99ec005c8..08b3ff183 100644 --- a/Tests/test_imageshow.py +++ b/Tests/test_imageshow.py @@ -1,6 +1,18 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule from PIL import Image from PIL import ImageShow -success() + +class TestImageShow(PillowTestCase): + + def test_sanity(self): + dir(Image) + dir(ImageShow) + pass + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_imagestat.py b/Tests/test_imagestat.py index 02a461e22..7eded56cf 100644 --- a/Tests/test_imagestat.py +++ b/Tests/test_imagestat.py @@ -1,52 +1,63 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule, lena from PIL import Image from PIL import ImageStat -def test_sanity(): - im = lena() +class TestImageStat(PillowTestCase): - st = ImageStat.Stat(im) - st = ImageStat.Stat(im.histogram()) - st = ImageStat.Stat(im, Image.new("1", im.size, 1)) + def test_sanity(self): - assert_no_exception(lambda: st.extrema) - assert_no_exception(lambda: st.sum) - assert_no_exception(lambda: st.mean) - assert_no_exception(lambda: st.median) - assert_no_exception(lambda: st.rms) - assert_no_exception(lambda: st.sum2) - assert_no_exception(lambda: st.var) - assert_no_exception(lambda: st.stddev) - assert_exception(AttributeError, lambda: st.spam) + im = lena() - assert_exception(TypeError, lambda: ImageStat.Stat(1)) + st = ImageStat.Stat(im) + st = ImageStat.Stat(im.histogram()) + st = ImageStat.Stat(im, Image.new("1", im.size, 1)) -def test_lena(): + # Check these run. Exceptions will cause failures. + st.extrema + st.sum + st.mean + st.median + st.rms + st.sum2 + st.var + st.stddev - im = lena() + self.assertRaises(AttributeError, lambda: st.spam) - st = ImageStat.Stat(im) + self.assertRaises(TypeError, lambda: ImageStat.Stat(1)) - # verify a few values - assert_equal(st.extrema[0], (61, 255)) - assert_equal(st.median[0], 197) - assert_equal(st.sum[0], 2954416) - assert_equal(st.sum[1], 2027250) - assert_equal(st.sum[2], 1727331) + def test_lena(self): -def test_constant(): + im = lena() - im = Image.new("L", (128, 128), 128) + st = ImageStat.Stat(im) - st = ImageStat.Stat(im) + # verify a few values + self.assertEqual(st.extrema[0], (61, 255)) + self.assertEqual(st.median[0], 197) + self.assertEqual(st.sum[0], 2954416) + self.assertEqual(st.sum[1], 2027250) + self.assertEqual(st.sum[2], 1727331) - assert_equal(st.extrema[0], (128, 128)) - assert_equal(st.sum[0], 128**3) - assert_equal(st.sum2[0], 128**4) - assert_equal(st.mean[0], 128) - assert_equal(st.median[0], 128) - assert_equal(st.rms[0], 128) - assert_equal(st.var[0], 0) - assert_equal(st.stddev[0], 0) + def test_constant(self): + + im = Image.new("L", (128, 128), 128) + + st = ImageStat.Stat(im) + + self.assertEqual(st.extrema[0], (128, 128)) + self.assertEqual(st.sum[0], 128**3) + self.assertEqual(st.sum2[0], 128**4) + self.assertEqual(st.mean[0], 128) + self.assertEqual(st.median[0], 128) + self.assertEqual(st.rms[0], 128) + self.assertEqual(st.var[0], 0) + self.assertEqual(st.stddev[0], 0) + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_imagetk.py b/Tests/test_imagetk.py index b30971e8f..b868096b2 100644 --- a/Tests/test_imagetk.py +++ b/Tests/test_imagetk.py @@ -1,9 +1,17 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule -from PIL import Image -try: - from PIL import ImageTk -except (OSError, ImportError) as v: - skip(v) -success() +class TestImageTk(PillowTestCase): + + def test_import(self): + try: + from PIL import ImageTk + dir(ImageTk) + except (OSError, ImportError) as v: + self.skipTest(v) + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_imagetransform.py b/Tests/test_imagetransform.py index 884e6bb1c..dfffafe54 100644 --- a/Tests/test_imagetransform.py +++ b/Tests/test_imagetransform.py @@ -1,18 +1,27 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule from PIL import Image from PIL import ImageTransform -im = Image.new("L", (100, 100)) -seq = tuple(range(10)) +class TestImageTransform(PillowTestCase): -def test_sanity(): - transform = ImageTransform.AffineTransform(seq[:6]) - assert_no_exception(lambda: im.transform((100, 100), transform)) - transform = ImageTransform.ExtentTransform(seq[:4]) - assert_no_exception(lambda: im.transform((100, 100), transform)) - transform = ImageTransform.QuadTransform(seq[:8]) - assert_no_exception(lambda: im.transform((100, 100), transform)) - transform = ImageTransform.MeshTransform([(seq[:4], seq[:8])]) - assert_no_exception(lambda: im.transform((100, 100), transform)) + def test_sanity(self): + im = Image.new("L", (100, 100)) + + seq = tuple(range(10)) + + transform = ImageTransform.AffineTransform(seq[:6]) + im.transform((100, 100), transform) + transform = ImageTransform.ExtentTransform(seq[:4]) + im.transform((100, 100), transform) + transform = ImageTransform.QuadTransform(seq[:8]) + im.transform((100, 100), transform) + transform = ImageTransform.MeshTransform([(seq[:4], seq[:8])]) + im.transform((100, 100), transform) + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_imagewin.py b/Tests/test_imagewin.py index 268a75b6f..f22babbb3 100644 --- a/Tests/test_imagewin.py +++ b/Tests/test_imagewin.py @@ -1,6 +1,18 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule, lena from PIL import Image from PIL import ImageWin -success() + +class TestImageWin(PillowTestCase): + + def test_sanity(self): + dir(Image) + dir(ImageWin) + pass + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_lib_image.py b/Tests/test_lib_image.py index 93aa694d8..c7ea4c701 100644 --- a/Tests/test_lib_image.py +++ b/Tests/test_lib_image.py @@ -1,30 +1,39 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule from PIL import Image -def test_setmode(): - im = Image.new("L", (1, 1), 255) - im.im.setmode("1") - assert_equal(im.im.getpixel((0, 0)), 255) - im.im.setmode("L") - assert_equal(im.im.getpixel((0, 0)), 255) +class TestSanity(PillowTestCase): - im = Image.new("1", (1, 1), 1) - im.im.setmode("L") - assert_equal(im.im.getpixel((0, 0)), 255) - im.im.setmode("1") - assert_equal(im.im.getpixel((0, 0)), 255) + def test_setmode(self): - im = Image.new("RGB", (1, 1), (1, 2, 3)) - im.im.setmode("RGB") - assert_equal(im.im.getpixel((0, 0)), (1, 2, 3)) - im.im.setmode("RGBA") - assert_equal(im.im.getpixel((0, 0)), (1, 2, 3, 255)) - im.im.setmode("RGBX") - assert_equal(im.im.getpixel((0, 0)), (1, 2, 3, 255)) - im.im.setmode("RGB") - assert_equal(im.im.getpixel((0, 0)), (1, 2, 3)) + im = Image.new("L", (1, 1), 255) + im.im.setmode("1") + self.assertEqual(im.im.getpixel((0, 0)), 255) + im.im.setmode("L") + self.assertEqual(im.im.getpixel((0, 0)), 255) - assert_exception(ValueError, lambda: im.im.setmode("L")) - assert_exception(ValueError, lambda: im.im.setmode("RGBABCDE")) + im = Image.new("1", (1, 1), 1) + im.im.setmode("L") + self.assertEqual(im.im.getpixel((0, 0)), 255) + im.im.setmode("1") + self.assertEqual(im.im.getpixel((0, 0)), 255) + + im = Image.new("RGB", (1, 1), (1, 2, 3)) + im.im.setmode("RGB") + self.assertEqual(im.im.getpixel((0, 0)), (1, 2, 3)) + im.im.setmode("RGBA") + self.assertEqual(im.im.getpixel((0, 0)), (1, 2, 3, 255)) + im.im.setmode("RGBX") + self.assertEqual(im.im.getpixel((0, 0)), (1, 2, 3, 255)) + im.im.setmode("RGB") + self.assertEqual(im.im.getpixel((0, 0)), (1, 2, 3)) + + self.assertRaises(ValueError, lambda: im.im.setmode("L")) + self.assertRaises(ValueError, lambda: im.im.setmode("RGBABCDE")) + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_lib_pack.py b/Tests/test_lib_pack.py index 7675348b3..c8ed39c40 100644 --- a/Tests/test_lib_pack.py +++ b/Tests/test_lib_pack.py @@ -1,138 +1,147 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule, py3 from PIL import Image -def pack(): - pass # not yet -def test_pack(): +class TestLibPack(PillowTestCase): - def pack(mode, rawmode): - if len(mode) == 1: - im = Image.new(mode, (1, 1), 1) - else: - im = Image.new(mode, (1, 1), (1, 2, 3, 4)[:len(mode)]) + def pack(self): + pass # not yet - if py3: - return list(im.tobytes("raw", rawmode)) - else: - return [ord(c) for c in im.tobytes("raw", rawmode)] + def test_pack(self): - order = 1 if Image._ENDIAN == '<' else -1 + def pack(mode, rawmode): + if len(mode) == 1: + im = Image.new(mode, (1, 1), 1) + else: + im = Image.new(mode, (1, 1), (1, 2, 3, 4)[:len(mode)]) - assert_equal(pack("1", "1"), [128]) - assert_equal(pack("1", "1;I"), [0]) - assert_equal(pack("1", "1;R"), [1]) - assert_equal(pack("1", "1;IR"), [0]) + if py3: + return list(im.tobytes("raw", rawmode)) + else: + return [ord(c) for c in im.tobytes("raw", rawmode)] - assert_equal(pack("L", "L"), [1]) + order = 1 if Image._ENDIAN == '<' else -1 - assert_equal(pack("I", "I"), [1, 0, 0, 0][::order]) + self.assertEqual(pack("1", "1"), [128]) + self.assertEqual(pack("1", "1;I"), [0]) + self.assertEqual(pack("1", "1;R"), [1]) + self.assertEqual(pack("1", "1;IR"), [0]) - assert_equal(pack("F", "F"), [0, 0, 128, 63][::order]) + self.assertEqual(pack("L", "L"), [1]) - assert_equal(pack("LA", "LA"), [1, 2]) + self.assertEqual(pack("I", "I"), [1, 0, 0, 0][::order]) - assert_equal(pack("RGB", "RGB"), [1, 2, 3]) - assert_equal(pack("RGB", "RGB;L"), [1, 2, 3]) - assert_equal(pack("RGB", "BGR"), [3, 2, 1]) - assert_equal(pack("RGB", "RGBX"), [1, 2, 3, 255]) # 255? - assert_equal(pack("RGB", "BGRX"), [3, 2, 1, 0]) - assert_equal(pack("RGB", "XRGB"), [0, 1, 2, 3]) - assert_equal(pack("RGB", "XBGR"), [0, 3, 2, 1]) + self.assertEqual(pack("F", "F"), [0, 0, 128, 63][::order]) - assert_equal(pack("RGBX", "RGBX"), [1, 2, 3, 4]) # 4->255? + self.assertEqual(pack("LA", "LA"), [1, 2]) - assert_equal(pack("RGBA", "RGBA"), [1, 2, 3, 4]) + self.assertEqual(pack("RGB", "RGB"), [1, 2, 3]) + self.assertEqual(pack("RGB", "RGB;L"), [1, 2, 3]) + self.assertEqual(pack("RGB", "BGR"), [3, 2, 1]) + self.assertEqual(pack("RGB", "RGBX"), [1, 2, 3, 255]) # 255? + self.assertEqual(pack("RGB", "BGRX"), [3, 2, 1, 0]) + self.assertEqual(pack("RGB", "XRGB"), [0, 1, 2, 3]) + self.assertEqual(pack("RGB", "XBGR"), [0, 3, 2, 1]) - assert_equal(pack("CMYK", "CMYK"), [1, 2, 3, 4]) - assert_equal(pack("YCbCr", "YCbCr"), [1, 2, 3]) + self.assertEqual(pack("RGBX", "RGBX"), [1, 2, 3, 4]) # 4->255? -def test_unpack(): + self.assertEqual(pack("RGBA", "RGBA"), [1, 2, 3, 4]) - def unpack(mode, rawmode, bytes_): - im = None + self.assertEqual(pack("CMYK", "CMYK"), [1, 2, 3, 4]) + self.assertEqual(pack("YCbCr", "YCbCr"), [1, 2, 3]) - if py3: - data = bytes(range(1,bytes_+1)) - else: - data = ''.join(chr(i) for i in range(1,bytes_+1)) + def test_unpack(self): - im = Image.frombytes(mode, (1, 1), data, "raw", rawmode, 0, 1) + def unpack(mode, rawmode, bytes_): + im = None - return im.getpixel((0, 0)) + if py3: + data = bytes(range(1, bytes_+1)) + else: + data = ''.join(chr(i) for i in range(1, bytes_+1)) - def unpack_1(mode, rawmode, value): - assert mode == "1" - im = None + im = Image.frombytes(mode, (1, 1), data, "raw", rawmode, 0, 1) - if py3: - im = Image.frombytes(mode, (8, 1), bytes([value]), "raw", rawmode, 0, 1) - else: - im = Image.frombytes(mode, (8, 1), chr(value), "raw", rawmode, 0, 1) + return im.getpixel((0, 0)) - return tuple(im.getdata()) + def unpack_1(mode, rawmode, value): + assert mode == "1" + im = None - X = 255 + if py3: + im = Image.frombytes( + mode, (8, 1), bytes([value]), "raw", rawmode, 0, 1) + else: + im = Image.frombytes( + mode, (8, 1), chr(value), "raw", rawmode, 0, 1) - assert_equal(unpack_1("1", "1", 1), (0,0,0,0,0,0,0,X)) - assert_equal(unpack_1("1", "1;I", 1), (X,X,X,X,X,X,X,0)) - assert_equal(unpack_1("1", "1;R", 1), (X,0,0,0,0,0,0,0)) - assert_equal(unpack_1("1", "1;IR", 1), (0,X,X,X,X,X,X,X)) + return tuple(im.getdata()) - assert_equal(unpack_1("1", "1", 170), (X,0,X,0,X,0,X,0)) - assert_equal(unpack_1("1", "1;I", 170), (0,X,0,X,0,X,0,X)) - assert_equal(unpack_1("1", "1;R", 170), (0,X,0,X,0,X,0,X)) - assert_equal(unpack_1("1", "1;IR", 170), (X,0,X,0,X,0,X,0)) + X = 255 - assert_equal(unpack("L", "L;2", 1), 0) - assert_equal(unpack("L", "L;4", 1), 0) - assert_equal(unpack("L", "L", 1), 1) - assert_equal(unpack("L", "L;I", 1), 254) - assert_equal(unpack("L", "L;R", 1), 128) - assert_equal(unpack("L", "L;16", 2), 2) # little endian - assert_equal(unpack("L", "L;16B", 2), 1) # big endian + self.assertEqual(unpack_1("1", "1", 1), (0, 0, 0, 0, 0, 0, 0, X)) + self.assertEqual(unpack_1("1", "1;I", 1), (X, X, X, X, X, X, X, 0)) + self.assertEqual(unpack_1("1", "1;R", 1), (X, 0, 0, 0, 0, 0, 0, 0)) + self.assertEqual(unpack_1("1", "1;IR", 1), (0, X, X, X, X, X, X, X)) - assert_equal(unpack("LA", "LA", 2), (1, 2)) - assert_equal(unpack("LA", "LA;L", 2), (1, 2)) + self.assertEqual(unpack_1("1", "1", 170), (X, 0, X, 0, X, 0, X, 0)) + self.assertEqual(unpack_1("1", "1;I", 170), (0, X, 0, X, 0, X, 0, X)) + self.assertEqual(unpack_1("1", "1;R", 170), (0, X, 0, X, 0, X, 0, X)) + self.assertEqual(unpack_1("1", "1;IR", 170), (X, 0, X, 0, X, 0, X, 0)) - assert_equal(unpack("RGB", "RGB", 3), (1, 2, 3)) - assert_equal(unpack("RGB", "RGB;L", 3), (1, 2, 3)) - assert_equal(unpack("RGB", "RGB;R", 3), (128, 64, 192)) - assert_equal(unpack("RGB", "RGB;16B", 6), (1, 3, 5)) # ? - assert_equal(unpack("RGB", "BGR", 3), (3, 2, 1)) - assert_equal(unpack("RGB", "RGB;15", 2), (8, 131, 0)) - assert_equal(unpack("RGB", "BGR;15", 2), (0, 131, 8)) - assert_equal(unpack("RGB", "RGB;16", 2), (8, 64, 0)) - assert_equal(unpack("RGB", "BGR;16", 2), (0, 64, 8)) - assert_equal(unpack("RGB", "RGB;4B", 2), (17, 0, 34)) + self.assertEqual(unpack("L", "L;2", 1), 0) + self.assertEqual(unpack("L", "L;4", 1), 0) + self.assertEqual(unpack("L", "L", 1), 1) + self.assertEqual(unpack("L", "L;I", 1), 254) + self.assertEqual(unpack("L", "L;R", 1), 128) + self.assertEqual(unpack("L", "L;16", 2), 2) # little endian + self.assertEqual(unpack("L", "L;16B", 2), 1) # big endian - assert_equal(unpack("RGB", "RGBX", 4), (1, 2, 3)) - assert_equal(unpack("RGB", "BGRX", 4), (3, 2, 1)) - assert_equal(unpack("RGB", "XRGB", 4), (2, 3, 4)) - assert_equal(unpack("RGB", "XBGR", 4), (4, 3, 2)) + self.assertEqual(unpack("LA", "LA", 2), (1, 2)) + self.assertEqual(unpack("LA", "LA;L", 2), (1, 2)) - assert_equal(unpack("RGBA", "RGBA", 4), (1, 2, 3, 4)) - assert_equal(unpack("RGBA", "BGRA", 4), (3, 2, 1, 4)) - assert_equal(unpack("RGBA", "ARGB", 4), (2, 3, 4, 1)) - assert_equal(unpack("RGBA", "ABGR", 4), (4, 3, 2, 1)) - assert_equal(unpack("RGBA", "RGBA;15", 2), (8, 131, 0, 0)) - assert_equal(unpack("RGBA", "BGRA;15", 2), (0, 131, 8, 0)) - assert_equal(unpack("RGBA", "RGBA;4B", 2), (17, 0, 34, 0)) + self.assertEqual(unpack("RGB", "RGB", 3), (1, 2, 3)) + self.assertEqual(unpack("RGB", "RGB;L", 3), (1, 2, 3)) + self.assertEqual(unpack("RGB", "RGB;R", 3), (128, 64, 192)) + self.assertEqual(unpack("RGB", "RGB;16B", 6), (1, 3, 5)) # ? + self.assertEqual(unpack("RGB", "BGR", 3), (3, 2, 1)) + self.assertEqual(unpack("RGB", "RGB;15", 2), (8, 131, 0)) + self.assertEqual(unpack("RGB", "BGR;15", 2), (0, 131, 8)) + self.assertEqual(unpack("RGB", "RGB;16", 2), (8, 64, 0)) + self.assertEqual(unpack("RGB", "BGR;16", 2), (0, 64, 8)) + self.assertEqual(unpack("RGB", "RGB;4B", 2), (17, 0, 34)) - assert_equal(unpack("RGBX", "RGBX", 4), (1, 2, 3, 4)) # 4->255? - assert_equal(unpack("RGBX", "BGRX", 4), (3, 2, 1, 255)) - assert_equal(unpack("RGBX", "XRGB", 4), (2, 3, 4, 255)) - assert_equal(unpack("RGBX", "XBGR", 4), (4, 3, 2, 255)) - assert_equal(unpack("RGBX", "RGB;15", 2), (8, 131, 0, 255)) - assert_equal(unpack("RGBX", "BGR;15", 2), (0, 131, 8, 255)) - assert_equal(unpack("RGBX", "RGB;4B", 2), (17, 0, 34, 255)) + self.assertEqual(unpack("RGB", "RGBX", 4), (1, 2, 3)) + self.assertEqual(unpack("RGB", "BGRX", 4), (3, 2, 1)) + self.assertEqual(unpack("RGB", "XRGB", 4), (2, 3, 4)) + self.assertEqual(unpack("RGB", "XBGR", 4), (4, 3, 2)) - assert_equal(unpack("CMYK", "CMYK", 4), (1, 2, 3, 4)) - assert_equal(unpack("CMYK", "CMYK;I", 4), (254, 253, 252, 251)) + self.assertEqual(unpack("RGBA", "RGBA", 4), (1, 2, 3, 4)) + self.assertEqual(unpack("RGBA", "BGRA", 4), (3, 2, 1, 4)) + self.assertEqual(unpack("RGBA", "ARGB", 4), (2, 3, 4, 1)) + self.assertEqual(unpack("RGBA", "ABGR", 4), (4, 3, 2, 1)) + self.assertEqual(unpack("RGBA", "RGBA;15", 2), (8, 131, 0, 0)) + self.assertEqual(unpack("RGBA", "BGRA;15", 2), (0, 131, 8, 0)) + self.assertEqual(unpack("RGBA", "RGBA;4B", 2), (17, 0, 34, 0)) - assert_exception(ValueError, lambda: unpack("L", "L", 0)) - assert_exception(ValueError, lambda: unpack("RGB", "RGB", 2)) - assert_exception(ValueError, lambda: unpack("CMYK", "CMYK", 2)) + self.assertEqual(unpack("RGBX", "RGBX", 4), (1, 2, 3, 4)) # 4->255? + self.assertEqual(unpack("RGBX", "BGRX", 4), (3, 2, 1, 255)) + self.assertEqual(unpack("RGBX", "XRGB", 4), (2, 3, 4, 255)) + self.assertEqual(unpack("RGBX", "XBGR", 4), (4, 3, 2, 255)) + self.assertEqual(unpack("RGBX", "RGB;15", 2), (8, 131, 0, 255)) + self.assertEqual(unpack("RGBX", "BGR;15", 2), (0, 131, 8, 255)) + self.assertEqual(unpack("RGBX", "RGB;4B", 2), (17, 0, 34, 255)) -run() + self.assertEqual(unpack("CMYK", "CMYK", 4), (1, 2, 3, 4)) + self.assertEqual(unpack("CMYK", "CMYK;I", 4), (254, 253, 252, 251)) + + self.assertRaises(ValueError, lambda: unpack("L", "L", 0)) + self.assertRaises(ValueError, lambda: unpack("RGB", "RGB", 2)) + self.assertRaises(ValueError, lambda: unpack("CMYK", "CMYK", 2)) + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_locale.py b/Tests/test_locale.py index 2683c561b..7ef63634b 100644 --- a/Tests/test_locale.py +++ b/Tests/test_locale.py @@ -1,31 +1,39 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule, lena + from PIL import Image import locale -# ref https://github.com/python-imaging/Pillow/issues/272 -## on windows, in polish locale: +# ref https://github.com/python-pillow/Pillow/issues/272 +# on windows, in polish locale: -## import locale -## print locale.setlocale(locale.LC_ALL, 'polish') -## import string -## print len(string.whitespace) -## print ord(string.whitespace[6]) +# import locale +# print locale.setlocale(locale.LC_ALL, 'polish') +# import string +# print len(string.whitespace) +# print ord(string.whitespace[6]) -## Polish_Poland.1250 -## 7 -## 160 +# Polish_Poland.1250 +# 7 +# 160 -# one of string.whitespace is not freely convertable into ascii. +# one of string.whitespace is not freely convertable into ascii. path = "Images/lena.jpg" -def test_sanity(): - assert_no_exception(lambda: Image.open(path)) - try: - locale.setlocale(locale.LC_ALL, "polish") - except: - skip('polish locale not available') - import string - assert_no_exception(lambda: Image.open(path)) +class TestLocale(PillowTestCase): + + def test_sanity(self): + Image.open(path) + try: + locale.setlocale(locale.LC_ALL, "polish") + except: + unittest.skip('Polish locale not available') + Image.open(path) + + +if __name__ == '__main__': + unittest.main() + +# End of file diff --git a/Tests/test_mode_i16.py b/Tests/test_mode_i16.py index 782a26623..d8e205b66 100644 --- a/Tests/test_mode_i16.py +++ b/Tests/test_mode_i16.py @@ -1,107 +1,109 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule, lena from PIL import Image -def verify(im1): - im2 = lena("I") - assert_equal(im1.size, im2.size) - pix1 = im1.load() - pix2 = im2.load() - for y in range(im1.size[1]): - for x in range(im1.size[0]): - xy = x, y - if pix1[xy] != pix2[xy]: - failure( - "got %r from mode %s at %s, expected %r" % - (pix1[xy], im1.mode, xy, pix2[xy]) - ) - return - success() +class TestModeI16(PillowTestCase): + + def verify(self, im1): + im2 = lena("I") + self.assertEqual(im1.size, im2.size) + pix1 = im1.load() + pix2 = im2.load() + for y in range(im1.size[1]): + for x in range(im1.size[0]): + xy = x, y + self.assertEqual( + pix1[xy], pix2[xy], + ("got %r from mode %s at %s, expected %r" % + (pix1[xy], im1.mode, xy, pix2[xy]))) + + def test_basic(self): + # PIL 1.1 has limited support for 16-bit image data. Check that + # create/copy/transform and save works as expected. + + def basic(mode): + + imIn = lena("I").convert(mode) + self.verify(imIn) + + w, h = imIn.size + + imOut = imIn.copy() + self.verify(imOut) # copy + + imOut = imIn.transform((w, h), Image.EXTENT, (0, 0, w, h)) + self.verify(imOut) # transform + + filename = self.tempfile("temp.im") + imIn.save(filename) + + imOut = Image.open(filename) + + self.verify(imIn) + self.verify(imOut) + + imOut = imIn.crop((0, 0, w, h)) + self.verify(imOut) + + imOut = Image.new(mode, (w, h), None) + imOut.paste(imIn.crop((0, 0, w//2, h)), (0, 0)) + imOut.paste(imIn.crop((w//2, 0, w, h)), (w//2, 0)) + + self.verify(imIn) + self.verify(imOut) + + imIn = Image.new(mode, (1, 1), 1) + self.assertEqual(imIn.getpixel((0, 0)), 1) + + imIn.putpixel((0, 0), 2) + self.assertEqual(imIn.getpixel((0, 0)), 2) + + if mode == "L": + max = 255 + else: + max = 32767 + + imIn = Image.new(mode, (1, 1), 256) + self.assertEqual(imIn.getpixel((0, 0)), min(256, max)) + + imIn.putpixel((0, 0), 512) + self.assertEqual(imIn.getpixel((0, 0)), min(512, max)) + + basic("L") + + basic("I;16") + basic("I;16B") + basic("I;16L") + + basic("I") + + def test_tobytes(self): + + def tobytes(mode): + return Image.new(mode, (1, 1), 1).tobytes() + + order = 1 if Image._ENDIAN == '<' else -1 + + self.assertEqual(tobytes("L"), b"\x01") + self.assertEqual(tobytes("I;16"), b"\x01\x00") + self.assertEqual(tobytes("I;16B"), b"\x00\x01") + self.assertEqual(tobytes("I"), b"\x01\x00\x00\x00"[::order]) + + def test_convert(self): + + im = lena("I") + + self.verify(im.convert("I;16")) + self.verify(im.convert("I;16").convert("L")) + self.verify(im.convert("I;16").convert("I")) + + self.verify(im.convert("I;16B")) + self.verify(im.convert("I;16B").convert("L")) + self.verify(im.convert("I;16B").convert("I")) -def test_basic(): - # PIL 1.1 has limited support for 16-bit image data. Check that - # create/copy/transform and save works as expected. +if __name__ == '__main__': + unittest.main() - def basic(mode): - - imIn = lena("I").convert(mode) - verify(imIn) - - w, h = imIn.size - - imOut = imIn.copy() - verify(imOut) # copy - - imOut = imIn.transform((w, h), Image.EXTENT, (0, 0, w, h)) - verify(imOut) # transform - - filename = tempfile("temp.im") - imIn.save(filename) - - imOut = Image.open(filename) - - verify(imIn) - verify(imOut) - - imOut = imIn.crop((0, 0, w, h)) - verify(imOut) - - imOut = Image.new(mode, (w, h), None) - imOut.paste(imIn.crop((0, 0, w//2, h)), (0, 0)) - imOut.paste(imIn.crop((w//2, 0, w, h)), (w//2, 0)) - - verify(imIn) - verify(imOut) - - imIn = Image.new(mode, (1, 1), 1) - assert_equal(imIn.getpixel((0, 0)), 1) - - imIn.putpixel((0, 0), 2) - assert_equal(imIn.getpixel((0, 0)), 2) - - if mode == "L": - max = 255 - else: - max = 32767 - - imIn = Image.new(mode, (1, 1), 256) - assert_equal(imIn.getpixel((0, 0)), min(256, max)) - - imIn.putpixel((0, 0), 512) - assert_equal(imIn.getpixel((0, 0)), min(512, max)) - - basic("L") - - basic("I;16") - basic("I;16B") - basic("I;16L") - - basic("I") - - -def test_tobytes(): - - def tobytes(mode): - return Image.new(mode, (1, 1), 1).tobytes() - - order = 1 if Image._ENDIAN == '<' else -1 - - assert_equal(tobytes("L"), b"\x01") - assert_equal(tobytes("I;16"), b"\x01\x00") - assert_equal(tobytes("I;16B"), b"\x00\x01") - assert_equal(tobytes("I"), b"\x01\x00\x00\x00"[::order]) - - -def test_convert(): - - im = lena("I") - - verify(im.convert("I;16")) - verify(im.convert("I;16").convert("L")) - verify(im.convert("I;16").convert("I")) - - verify(im.convert("I;16B")) - verify(im.convert("I;16B").convert("L")) - verify(im.convert("I;16B").convert("I")) +# End of file diff --git a/Tests/test_numpy.py b/Tests/test_numpy.py index 4833cabb2..c3c0f7e90 100644 --- a/Tests/test_numpy.py +++ b/Tests/test_numpy.py @@ -1,120 +1,128 @@ -from tester import * +from helper import unittest, PillowTestCase, tearDownModule, lena from PIL import Image -import struct try: import site import numpy except ImportError: - skip() + # Skip via setUp() + pass -def test_numpy_to_image(): - def to_image(dtype, bands=1, bool=0): - if bands == 1: - if bool: - data = [0, 1] * 50 +class TestNumpy(PillowTestCase): + + def setUp(self): + try: + import site + import numpy + except ImportError: + self.skipTest("ImportError") + + def test_numpy_to_image(self): + + def to_image(dtype, bands=1, bool=0): + if bands == 1: + if bool: + data = [0, 1] * 50 + else: + data = list(range(100)) + a = numpy.array(data, dtype=dtype) + a.shape = 10, 10 + i = Image.fromarray(a) + if list(i.getdata()) != data: + print("data mismatch for", dtype) else: data = list(range(100)) - a = numpy.array(data, dtype=dtype) - a.shape = 10, 10 - i = Image.fromarray(a) - if list(i.getdata()) != data: - print("data mismatch for", dtype) + a = numpy.array([[x]*bands for x in data], dtype=dtype) + a.shape = 10, 10, bands + i = Image.fromarray(a) + if list(i.split()[0].getdata()) != list(range(100)): + print("data mismatch for", dtype) + # print dtype, list(i.getdata()) + return i + + # self.assert_image(to_image(numpy.bool, bool=1), "1", (10, 10)) + # self.assert_image(to_image(numpy.bool8, bool=1), "1", (10, 10)) + + self.assertRaises(TypeError, lambda: to_image(numpy.uint)) + self.assert_image(to_image(numpy.uint8), "L", (10, 10)) + self.assertRaises(TypeError, lambda: to_image(numpy.uint16)) + self.assertRaises(TypeError, lambda: to_image(numpy.uint32)) + self.assertRaises(TypeError, lambda: to_image(numpy.uint64)) + + self.assert_image(to_image(numpy.int8), "I", (10, 10)) + if Image._ENDIAN == '<': # Little endian + self.assert_image(to_image(numpy.int16), "I;16", (10, 10)) else: - data = list(range(100)) - a = numpy.array([[x]*bands for x in data], dtype=dtype) - a.shape = 10, 10, bands - i = Image.fromarray(a) - if list(i.split()[0].getdata()) != list(range(100)): - print("data mismatch for", dtype) - # print dtype, list(i.getdata()) - return i + self.assert_image(to_image(numpy.int16), "I;16B", (10, 10)) + self.assert_image(to_image(numpy.int32), "I", (10, 10)) + self.assertRaises(TypeError, lambda: to_image(numpy.int64)) - # assert_image(to_image(numpy.bool, bool=1), "1", (10, 10)) - # assert_image(to_image(numpy.bool8, bool=1), "1", (10, 10)) + self.assert_image(to_image(numpy.float), "F", (10, 10)) + self.assert_image(to_image(numpy.float32), "F", (10, 10)) + self.assert_image(to_image(numpy.float64), "F", (10, 10)) - assert_exception(TypeError, lambda: to_image(numpy.uint)) - assert_image(to_image(numpy.uint8), "L", (10, 10)) - assert_exception(TypeError, lambda: to_image(numpy.uint16)) - assert_exception(TypeError, lambda: to_image(numpy.uint32)) - assert_exception(TypeError, lambda: to_image(numpy.uint64)) + self.assert_image(to_image(numpy.uint8, 3), "RGB", (10, 10)) + self.assert_image(to_image(numpy.uint8, 4), "RGBA", (10, 10)) - assert_image(to_image(numpy.int8), "I", (10, 10)) - if Image._ENDIAN == '<': # Little endian - assert_image(to_image(numpy.int16), "I;16", (10, 10)) - else: - assert_image(to_image(numpy.int16), "I;16B", (10, 10)) - assert_image(to_image(numpy.int32), "I", (10, 10)) - assert_exception(TypeError, lambda: to_image(numpy.int64)) + # based on an erring example at http://is.gd/6F0esS (which resolves to) + # http://stackoverflow.com/questions/10854903/what-is-causing-dimension-dependent-attributeerror-in-pil-fromarray-function + def test_3d_array(self): + a = numpy.ones((10, 10, 10), dtype=numpy.uint8) + self.assert_image(Image.fromarray(a[1, :, :]), "L", (10, 10)) + self.assert_image(Image.fromarray(a[:, 1, :]), "L", (10, 10)) + self.assert_image(Image.fromarray(a[:, :, 1]), "L", (10, 10)) - assert_image(to_image(numpy.float), "F", (10, 10)) - assert_image(to_image(numpy.float32), "F", (10, 10)) - assert_image(to_image(numpy.float64), "F", (10, 10)) + def _test_img_equals_nparray(self, img, np): + self.assertEqual(img.size, np.shape[0:2]) + px = img.load() + for x in range(0, img.size[0], int(img.size[0]/10)): + for y in range(0, img.size[1], int(img.size[1]/10)): + self.assert_deep_equal(px[x, y], np[y, x]) - assert_image(to_image(numpy.uint8, 3), "RGB", (10, 10)) - assert_image(to_image(numpy.uint8, 4), "RGBA", (10, 10)) - - -# based on an erring example at http://is.gd/6F0esS (which resolves to) -# http://stackoverflow.com/questions/10854903/what-is-causing-dimension-dependent-attributeerror-in-pil-fromarray-function -def test_3d_array(): - a = numpy.ones((10, 10, 10), dtype=numpy.uint8) - assert_image(Image.fromarray(a[1, :, :]), "L", (10, 10)) - assert_image(Image.fromarray(a[:, 1, :]), "L", (10, 10)) - assert_image(Image.fromarray(a[:, :, 1]), "L", (10, 10)) - - -def _test_img_equals_nparray(img, np): - assert_equal(img.size, np.shape[0:2]) - px = img.load() - for x in range(0, img.size[0], int(img.size[0]/10)): - for y in range(0, img.size[1], int(img.size[1]/10)): - assert_deep_equal(px[x,y], np[y,x]) - - -def test_16bit(): - img = Image.open('Tests/images/16bit.cropped.tif') - np_img = numpy.array(img) - _test_img_equals_nparray(img, np_img) - assert_equal(np_img.dtype, numpy.dtype('u2'), - ("I;16L", 'u2'), + ("I;16L", 'ysize); + return Py_BuildValue("ii", textwidth(self, text), self->ysize); } static struct PyMethodDef _font_methods[] = { @@ -2399,17 +2399,35 @@ _draw_ink(ImagingDrawObject* self, PyObject* args) static PyObject* _draw_arc(ImagingDrawObject* self, PyObject* args) { - int x0, y0, x1, y1; + double* xy; + int n; + + PyObject* data; int ink; int start, end; int op = 0; - if (!PyArg_ParseTuple(args, "(iiii)iii|i", - &x0, &y0, &x1, &y1, - &start, &end, &ink)) + if (!PyArg_ParseTuple(args, "Oiii|i", &data, &start, &end, &ink)) return NULL; - if (ImagingDrawArc(self->image->image, x0, y0, x1, y1, start, end, - &ink, op) < 0) + n = PyPath_Flatten(data, &xy); + if (n < 0) + return NULL; + if (n != 2) { + PyErr_SetString(PyExc_TypeError, + "coordinate list must contain exactly 2 coordinates" + ); + return NULL; + } + + n = ImagingDrawArc(self->image->image, + (int) xy[0], (int) xy[1], + (int) xy[2], (int) xy[3], + start, end, &ink, op + ); + + free(xy); + + if (n < 0) return NULL; Py_INCREF(Py_None); @@ -2455,15 +2473,35 @@ _draw_bitmap(ImagingDrawObject* self, PyObject* args) static PyObject* _draw_chord(ImagingDrawObject* self, PyObject* args) { - int x0, y0, x1, y1; + double* xy; + int n; + + PyObject* data; int ink, fill; int start, end; - if (!PyArg_ParseTuple(args, "(iiii)iiii", - &x0, &y0, &x1, &y1, &start, &end, &ink, &fill)) + if (!PyArg_ParseTuple(args, "Oiiii", + &data, &start, &end, &ink, &fill)) return NULL; - if (ImagingDrawChord(self->image->image, x0, y0, x1, y1, - start, end, &ink, fill, self->blend) < 0) + n = PyPath_Flatten(data, &xy); + if (n < 0) + return NULL; + if (n != 2) { + PyErr_SetString(PyExc_TypeError, + "coordinate list must contain exactly 2 coordinates" + ); + return NULL; + } + + n = ImagingDrawChord(self->image->image, + (int) xy[0], (int) xy[1], + (int) xy[2], (int) xy[3], + start, end, &ink, fill, self->blend + ); + + free(xy); + + if (n < 0) return NULL; Py_INCREF(Py_None); @@ -2492,8 +2530,8 @@ _draw_ellipse(ImagingDrawObject* self, PyObject* args) return NULL; } - n = ImagingDrawEllipse(self->image->image, - (int) xy[0], (int) xy[1], + n = ImagingDrawEllipse(self->image->image, + (int) xy[0], (int) xy[1], (int) xy[2], (int) xy[3], &ink, fill, self->blend ); @@ -2656,15 +2694,34 @@ _draw_outline(ImagingDrawObject* self, PyObject* args) static PyObject* _draw_pieslice(ImagingDrawObject* self, PyObject* args) { - int x0, y0, x1, y1; + double* xy; + int n; + + PyObject* data; int ink, fill; int start, end; - if (!PyArg_ParseTuple(args, "(iiii)iiii", - &x0, &y0, &x1, &y1, &start, &end, &ink, &fill)) + if (!PyArg_ParseTuple(args, "Oiiii", &data, &start, &end, &ink, &fill)) return NULL; - if (ImagingDrawPieslice(self->image->image, x0, y0, x1, y1, - start, end, &ink, fill, self->blend) < 0) + n = PyPath_Flatten(data, &xy); + if (n < 0) + return NULL; + if (n != 2) { + PyErr_SetString(PyExc_TypeError, + "coordinate list must contain exactly 2 coordinates" + ); + return NULL; + } + + n = ImagingDrawPieslice(self->image->image, + (int) xy[0], (int) xy[1], + (int) xy[2], (int) xy[3], + start, end, &ink, fill, self->blend + ); + + free(xy); + + if (n < 0) return NULL; Py_INCREF(Py_None); @@ -2738,9 +2795,9 @@ _draw_rectangle(ImagingDrawObject* self, PyObject* args) return NULL; } - n = ImagingDrawRectangle(self->image->image, + n = ImagingDrawRectangle(self->image->image, (int) xy[0], (int) xy[1], - (int) xy[2], (int) xy[3], + (int) xy[2], (int) xy[3], &ink, fill, self->blend ); @@ -3117,8 +3174,8 @@ _getattr_ptr(ImagingObject* self, void* closure) static PyObject* _getattr_unsafe_ptrs(ImagingObject* self, void* closure) { - return Py_BuildValue("(ss)(si)(si)(si)(si)(si)(sn)(sn)(sn)(sn)(sn)(si)(si)(sn)", - "mode", self->image->mode, + return Py_BuildValue("(ss)(si)(si)(si)(si)(si)(sn)(sn)(sn)(sn)(sn)(si)(si)(sn)", + "mode", self->image->mode, "type", self->image->type, "depth", self->image->depth, "bands", self->image->bands, diff --git a/docs/_templates/sidebarhelp.html b/docs/_templates/sidebarhelp.html index 330b3de45..ce36d2e34 100644 --- a/docs/_templates/sidebarhelp.html +++ b/docs/_templates/sidebarhelp.html @@ -12,7 +12,7 @@

If you've discovered a bug, you can - open an issue + open an issue on Github.

diff --git a/docs/about.rst b/docs/about.rst index e8c9356dc..817773610 100644 --- a/docs/about.rst +++ b/docs/about.rst @@ -11,8 +11,8 @@ The fork authors' goal is to foster active development of PIL through: - Regular releases to the `Python Package Index`_ - Solicitation for community contributions and involvement on `Image-SIG`_ -.. _Travis CI: https://travis-ci.org/python-imaging/Pillow -.. _GitHub: https://github.com/python-imaging/Pillow +.. _Travis CI: https://travis-ci.org/python-pillow/Pillow +.. _GitHub: https://github.com/python-pillow/Pillow .. _Python Package Index: https://pypi.python.org/pypi/Pillow .. _Image-SIG: http://mail.python.org/mailman/listinfo/image-sig @@ -60,6 +60,6 @@ announcement. So if you still want to support PIL, please .. _report issues here first: https://bitbucket.org/effbot/pil-2009-raclette/issues -.. _open the corresponding Pillow tickets here: https://github.com/python-imaging/Pillow/issues +.. _open the corresponding Pillow tickets here: https://github.com/python-pillow/Pillow/issues Please provide a link to the PIL ticket so we can track the issue(s) upstream. diff --git a/docs/index.rst b/docs/index.rst index 25e9f6b73..a8c204228 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -4,8 +4,8 @@ Pillow Pillow is the 'friendly' PIL fork by Alex Clark and Contributors. PIL is the Python Imaging Library by Fredrik Lundh and Contributors. -.. image:: https://travis-ci.org/python-imaging/Pillow.svg?branch=master - :target: https://travis-ci.org/python-imaging/Pillow +.. image:: https://travis-ci.org/python-pillow/Pillow.svg?branch=master + :target: https://travis-ci.org/python-pillow/Pillow :alt: Travis CI build status .. image:: https://pypip.in/v/Pillow/badge.png @@ -16,15 +16,15 @@ Python Imaging Library by Fredrik Lundh and Contributors. :target: https://pypi.python.org/pypi/Pillow/ :alt: Number of PyPI downloads -.. image:: https://coveralls.io/repos/python-imaging/Pillow/badge.png?branch=master - :target: https://coveralls.io/r/python-imaging/Pillow?branch=master +.. image:: https://coveralls.io/repos/python-pillow/Pillow/badge.png?branch=master + :target: https://coveralls.io/r/python-pillow/Pillow?branch=master :alt: Test coverage To start using Pillow, please read the :doc:`installation instructions `. You can get the source and contribute at -https://github.com/python-imaging/Pillow. You can download archives +https://github.com/python-pillow/Pillow. You can download archives and old versions from `PyPI `_. .. toctree:: @@ -42,7 +42,7 @@ Support Pillow! PIL needs you! Please help us maintain the Python Imaging Library here: -- `GitHub `_ +- `GitHub `_ - `Freenode `_ - `Image-SIG `_ diff --git a/docs/installation.rst b/docs/installation.rst index 94054df82..76c7d4ef5 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -67,11 +67,11 @@ Many of Pillow's features require external libraries: * Pillow has been tested with version **0.1.3**, which does not read transparent webp files. Versions **0.3.0** and **0.4.0** support - transparency. + transparency. -* **tcl/tk** provides support for tkinter bitmap and photo images. +* **tcl/tk** provides support for tkinter bitmap and photo images. -* **openjpeg** provides JPEG 2000 functionality. +* **openjpeg** provides JPEG 2000 functionality. * Pillow has been tested with openjpeg **2.0.0**. @@ -108,7 +108,7 @@ Or for Python 3:: $ sudo apt-get install python3-dev python3-setuptools In Fedora, the command is:: - + $ sudo yum install python-devel Prerequisites are installed on **Ubuntu 10.04 LTS** with:: @@ -185,6 +185,25 @@ to a specific version: $ pip install --use-wheel Pillow==2.3.0 +FreeBSD installation +--------------------- + +.. Note:: Only FreeBSD 10 tested + + +Make sure you have Python's development libraries installed.:: + + $ sudo pkg install python2 + +Or for Python 3:: + + $ sudo pkg install python3 + +Prerequisites are installed on **FreeBSD 10** with:: + + $ sudo pkg install jpeg tiff webp lcms2 freetype2 + + Platform support ---------------- @@ -199,7 +218,7 @@ current versions of Linux, OS X, and Windows. Contributors please test on your platform, edit this document, and send a pull request. -+----------------------------------+-------------+------------------------------+------------------------------+-----------------------+ ++----------------------------------+-------------+------------------------------+------------------------------+-----------------------+ |**Operating system** |**Supported**|**Tested Python versions** |**Tested Pillow versions** |**Tested processors** | +----------------------------------+-------------+------------------------------+------------------------------+-----------------------+ | Mac OS X 10.8 Mountain Lion |Yes | 2.6,2.7,3.2,3.3 | |x86-64 | @@ -224,6 +243,8 @@ current versions of Linux, OS X, and Windows. +----------------------------------+-------------+------------------------------+------------------------------+-----------------------+ | Gentoo Linux |Yes | 2.7,3.2 | 2.1.0 |x86-64 | +----------------------------------+-------------+------------------------------+------------------------------+-----------------------+ +| FreeBSD 10 |Yes | 2.7,3.4 | 2.4,2.3.1 |x86-64 | ++----------------------------------+-------------+------------------------------+------------------------------+-----------------------+ | Windows 7 Pro |Yes | 2.7,3.2,3.3 | 2.2.1 |x86-64 | +----------------------------------+-------------+------------------------------+------------------------------+-----------------------+ | Windows Server 2008 R2 Enterprise|Yes | 3.3 | |x86-64 | @@ -232,4 +253,3 @@ current versions of Linux, OS X, and Windows. +----------------------------------+-------------+------------------------------+------------------------------+-----------------------+ | Windows 8.1 Pro |Yes | 2.6,2.7,3.2,3.3,3.4 | 2.3.0, 2.4.0 |x86,x86-64 | +----------------------------------+-------------+------------------------------+------------------------------+-----------------------+ - diff --git a/docs/reference/ImageDraw.rst b/docs/reference/ImageDraw.rst index 68855eb5b..30aa15a9b 100644 --- a/docs/reference/ImageDraw.rst +++ b/docs/reference/ImageDraw.rst @@ -91,9 +91,12 @@ Methods Draws an arc (a portion of a circle outline) between the start and end angles, inside the given bounding box. - :param xy: Four points to define the bounding box. Sequence of either + :param xy: Four points to define the bounding box. Sequence of ``[(x0, y0), (x1, y1)]`` or ``[x0, y0, x1, y1]``. - :param outline: Color to use for the outline. + :param start: Starting angle, in degrees. Angles are measured from + 3 o'clock, increasing clockwise. + :param end: Ending angle, in degrees. + :param fill: Color to use for the arc. .. py:method:: PIL.ImageDraw.Draw.bitmap(xy, bitmap, fill=None) @@ -111,7 +114,7 @@ Methods Same as :py:meth:`~PIL.ImageDraw.Draw.arc`, but connects the end points with a straight line. - :param xy: Four points to define the bounding box. Sequence of either + :param xy: Four points to define the bounding box. Sequence of ``[(x0, y0), (x1, y1)]`` or ``[x0, y0, x1, y1]``. :param outline: Color to use for the outline. :param fill: Color to use for the fill. @@ -144,7 +147,7 @@ Methods Same as arc, but also draws straight lines between the end points and the center of the bounding box. - :param xy: Four points to define the bounding box. Sequence of either + :param xy: Four points to define the bounding box. Sequence of ``[(x0, y0), (x1, y1)]`` or ``[x0, y0, x1, y1]``. :param outline: Color to use for the outline. :param fill: Color to use for the fill. diff --git a/setup.py b/setup.py index 50ca985e3..83defd82b 100644 --- a/setup.py +++ b/setup.py @@ -234,7 +234,7 @@ class pil_build_ext(build_ext): elif sys.platform.startswith("linux"): arch_tp = (plat.processor(), plat.architecture()[0]) if arch_tp == ("x86_64","32bit"): - # 32 bit build on 64 bit machine. + # 32 bit build on 64 bit machine. _add_directory(library_dirs, "/usr/lib/i386-linux-gnu") else: for platform_ in arch_tp: @@ -339,7 +339,7 @@ class pil_build_ext(build_ext): # on Windows, look for the OpenJPEG libraries in the location that # the official installed puts them if sys.platform == "win32": - _add_directory(library_dirs, + _add_directory(library_dirs, os.path.join(os.environ.get("ProgramFiles", ""), "OpenJPEG 2.0", "lib")) _add_directory(include_dirs, @@ -378,7 +378,7 @@ class pil_build_ext(build_ext): if _find_include_file(self, "openjpeg-2.0/openjpeg.h"): if _find_library_file(self, "openjp2"): feature.jpeg2000 = "openjp2" - + if feature.want('tiff'): if _find_library_file(self, "tiff"): feature.tiff = "tiff" @@ -660,7 +660,7 @@ setup( _read('CHANGES.rst')).decode('utf-8'), author='Alex Clark (fork author)', author_email='aclark@aclark.net', - url='http://python-imaging.github.io/', + url='http://python-pillow.github.io/', classifiers=[ "Development Status :: 6 - Mature", "Topic :: Multimedia :: Graphics",