pilkit-1.1.13/0000755000076700000240000000000012562721725013021 5ustar mjtstaff00000000000000pilkit-1.1.13/AUTHORS0000644000076700000240000000206312164413072014061 0ustar mjtstaff00000000000000Maintainers ----------- * `Bryan Veloso`_ * `Matthew Tretter`_ * `Chris Drackett`_ * `Greg Newman`_ Contributors ------------ In addition to those listed on the `contributors page`__, the following people have also had a hand in bringing PILKit to life: * `Justin Driscoll`_ * `Timothée Peignier`_ * `Jan Sagemüller`_ * `Alexander Bohn`_ * `Eric Eldredge`_ * `Germán M. Bravo`_ * `Kevin Postal`_ * `Madis Väin`_ __ https://github.com/matthewwithanm/pilkit/graphs/contributors .. _Bryan Veloso: http://github.com/bryanveloso .. _Matthew Tretter: http://github.com/matthewwithanm .. _Chris Drackett: http://github.com/chrisdrackett .. _Greg Newman: http://github.com/gregnewman .. _Justin Driscoll: http://github.com/jdriscoll .. _Timothée Peignier: http://github.com/cyberdelia .. _Jan Sagemüller: https://github.com/version2 .. _Alexander Bohn: http://github.com/fish2000 .. _Eric Eldredge: http://github.com/lettertwo .. _Germán M. Bravo: http://github.com/Kronuz .. _Kevin Postal: https://github.com/kevinpostal .. _Madis Väin: https://github.com/madisvain pilkit-1.1.13/docs/0000755000076700000240000000000012562721725013751 5ustar mjtstaff00000000000000pilkit-1.1.13/docs/make.bat0000644000076700000240000001176112164413072015353 0ustar mjtstaff00000000000000@ECHO OFF REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set BUILDDIR=build set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source set I18NSPHINXOPTS=%SPHINXOPTS% source if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. singlehtml to make a single large HTML file echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. devhelp to make HTML files and a Devhelp project echo. epub to make an epub echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. text to make text files echo. man to make manual pages echo. texinfo to make Texinfo files echo. gettext to make PO message catalogs echo. changes to make an overview over all changed/added/deprecated items echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled goto end ) if "%1" == "clean" ( for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i del /q /s %BUILDDIR%\* goto end ) if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. goto end ) if "%1" == "singlehtml" ( %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in %BUILDDIR%/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: echo.^> qcollectiongenerator %BUILDDIR%\qthelp\PILKit.qhcp echo.To view the help file: echo.^> assistant -collectionFile %BUILDDIR%\qthelp\PILKit.ghc goto end ) if "%1" == "devhelp" ( %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp if errorlevel 1 exit /b 1 echo. echo.Build finished. goto end ) if "%1" == "epub" ( %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub if errorlevel 1 exit /b 1 echo. echo.Build finished. The epub file is in %BUILDDIR%/epub. goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex if errorlevel 1 exit /b 1 echo. echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. goto end ) if "%1" == "text" ( %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text if errorlevel 1 exit /b 1 echo. echo.Build finished. The text files are in %BUILDDIR%/text. goto end ) if "%1" == "man" ( %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man if errorlevel 1 exit /b 1 echo. echo.Build finished. The manual pages are in %BUILDDIR%/man. goto end ) if "%1" == "texinfo" ( %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo if errorlevel 1 exit /b 1 echo. echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. goto end ) if "%1" == "gettext" ( %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale if errorlevel 1 exit /b 1 echo. echo.Build finished. The message catalogs are in %BUILDDIR%/locale. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes if errorlevel 1 exit /b 1 echo. echo.The overview file is in %BUILDDIR%/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck if errorlevel 1 exit /b 1 echo. echo.Link check complete; look for any errors in the above output ^ or in %BUILDDIR%/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest if errorlevel 1 exit /b 1 echo. echo.Testing of doctests in the sources finished, look at the ^ results in %BUILDDIR%/doctest/output.txt. goto end ) :end pilkit-1.1.13/docs/Makefile0000644000076700000240000001270512164413072015405 0ustar mjtstaff00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = build # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: -rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/PILKit.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/PILKit.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/PILKit" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/PILKit" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." pilkit-1.1.13/docs/source/0000755000076700000240000000000012562721725015251 5ustar mjtstaff00000000000000pilkit-1.1.13/docs/source/conf.py0000644000076700000240000001752612175072427016561 0ustar mjtstaff00000000000000# -*- coding: utf-8 -*- # # PILKit documentation build configuration file, created by # sphinx-quickstart on Thu Feb 7 20:01:22 2013. # # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import re, sys, os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. #sys.path.insert(0, os.path.abspath('.')) # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = [] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'PILKit' copyright = u'2013, Matthew Tretter' pkgmeta = {} pkgmeta_file = os.path.join(os.path.dirname(__file__), '..', '..', 'pilkit', 'pkgmeta.py') with open(pkgmeta_file) as f: code = compile(f.read(), 'pkgmeta.py', 'exec') exec(code, pkgmeta) # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = re.match('\d+\.\d+', pkgmeta['__version__']).group() # The full version, including alpha/beta/rc tags. release = pkgmeta['__version__'] # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = [] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'default' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'PILKitdoc' # -- Options for LaTeX output -------------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). #'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). #'pointsize': '10pt', # Additional stuff for the LaTeX preamble. #'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('index', 'PILKit.tex', u'PILKit Documentation', u'Matthew Tretter', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'pilkit', u'PILKit Documentation', [u'Matthew Tretter'], 1) ] # If true, show URL addresses after external links. #man_show_urls = False # -- Options for Texinfo output ------------------------------------------------ # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ('index', 'PILKit', u'PILKit Documentation', u'Matthew Tretter', 'PILKit', 'One line description of project.', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. #texinfo_appendices = [] # If false, no module index is generated. #texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' pilkit-1.1.13/docs/source/index.rst0000644000076700000240000000037412164413072017105 0ustar mjtstaff00000000000000 Welcome to PILKit's documentation! ================================== .. include:: ../../README.rst Authors ======= .. include:: ../../AUTHORS Contents ========= * :ref:`genindex` * :ref:`modindex` * :ref:`search` .. toctree:: :maxdepth: 2 pilkit-1.1.13/LICENSE0000644000076700000240000000276112164413072014023 0ustar mjtstaff00000000000000Copyright (c) 2013 Primary Maintainers All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of PILKit nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. pilkit-1.1.13/MANIFEST.in0000644000076700000240000000014612562721470014555 0ustar mjtstaff00000000000000include AUTHORS include LICENSE include README.rst recursive-include docs * recursive-include tests * pilkit-1.1.13/pilkit/0000755000076700000240000000000012562721725014315 5ustar mjtstaff00000000000000pilkit-1.1.13/pilkit/__init__.py0000644000076700000240000000004712164413072016416 0ustar mjtstaff00000000000000# flake8: noqa from .pkgmeta import * pilkit-1.1.13/pilkit/exceptions.py0000644000076700000240000000012712164413072017037 0ustar mjtstaff00000000000000class UnknownExtension(Exception): pass class UnknownFormat(Exception): pass pilkit-1.1.13/pilkit/lib.py0000644000076700000240000000176612206531161015433 0ustar mjtstaff00000000000000# flake8: noqa # Required PIL classes may or may not be available from the root namespace # depending on the installation method used. try: from PIL import Image, ImageColor, ImageChops, ImageEnhance, ImageFile, \ ImageFilter, ImageDraw, ImageStat except ImportError: try: import Image import ImageColor import ImageChops import ImageEnhance import ImageFile import ImageFilter import ImageDraw import ImageStat except ImportError: raise ImportError('PILKit was unable to import the Python Imaging Library. Please confirm it`s installed and available on your current Python path.') try: from io import BytesIO as StringIO except ImportError as exc: try: from cStringIO import StringIO except ImportError: try: from StringIO import StringIO except ImportError: raise exc try: string_types = [basestring, str] except NameError: string_types = [str] pilkit-1.1.13/pilkit/pkgmeta.py0000644000076700000240000000024312562721642016314 0ustar mjtstaff00000000000000__title__ = 'pilkit' __author__ = 'Matthew Tretter' __version__ = '1.1.13' __license__ = 'BSD' __all__ = ['__title__', '__author__', '__version__', '__license__'] pilkit-1.1.13/pilkit/processors/0000755000076700000240000000000012562721725016517 5ustar mjtstaff00000000000000pilkit-1.1.13/pilkit/processors/__init__.py0000644000076700000240000000055312171376174020633 0ustar mjtstaff00000000000000# flake8: noqa """ PILKit image processors. A processor accepts an image, does some stuff, and returns the result. Processors can do anything with the image you want, but their responsibilities should be limited to image manipulations--they should be completely decoupled from the filesystem. """ from .base import * from .crop import * from .resize import * pilkit-1.1.13/pilkit/processors/base.py0000644000076700000240000001702412412017247017776 0ustar mjtstaff00000000000000from pilkit.lib import Image, ImageColor, ImageEnhance class ProcessorPipeline(list): """ A :class:`list` of other processors. This class allows any object that knows how to deal with a single processor to deal with a list of them. For example:: processed_image = ProcessorPipeline([ProcessorA(), ProcessorB()]).process(image) """ def process(self, img): for proc in self: img = proc.process(img) return img class Adjust(object): """ Performs color, brightness, contrast, and sharpness enhancements on the image. See :mod:`PIL.ImageEnhance` for more imformation. """ def __init__(self, color=1.0, brightness=1.0, contrast=1.0, sharpness=1.0): """ :param color: A number between 0 and 1 that specifies the saturation of the image. 0 corresponds to a completely desaturated image (black and white) and 1 to the original color. See :class:`PIL.ImageEnhance.Color` :param brightness: A number representing the brightness; 0 results in a completely black image whereas 1 corresponds to the brightness of the original. See :class:`PIL.ImageEnhance.Brightness` :param contrast: A number representing the contrast; 0 results in a completely gray image whereas 1 corresponds to the contrast of the original. See :class:`PIL.ImageEnhance.Contrast` :param sharpness: A number representing the sharpness; 0 results in a blurred image; 1 corresponds to the original sharpness; 2 results in a sharpened image. See :class:`PIL.ImageEnhance.Sharpness` """ self.color = color self.brightness = brightness self.contrast = contrast self.sharpness = sharpness def process(self, img): original = img = img.convert('RGBA') for name in ['Color', 'Brightness', 'Contrast', 'Sharpness']: factor = getattr(self, name.lower()) if factor != 1.0: try: img = getattr(ImageEnhance, name)(img).enhance(factor) except ValueError: pass else: # PIL's Color and Contrast filters both convert the image # to L mode, losing transparency info, so we put it back. # See https://github.com/jdriscoll/django-imagekit/issues/64 if name in ('Color', 'Contrast'): img = Image.merge('RGBA', img.split()[:3] + original.split()[3:4]) return img class Reflection(object): """ Creates an image with a reflection. """ def __init__(self, background_color='#FFFFFF', size=0.0, opacity=0.6): self.background_color = background_color self.size = size self.opacity = opacity def process(self, img): # Convert bgcolor string to RGB value. background_color = ImageColor.getrgb(self.background_color) # Handle palleted images. img = img.convert('RGBA') # Copy orignial image and flip the orientation. reflection = img.copy().transpose(Image.FLIP_TOP_BOTTOM) # Create a new image filled with the bgcolor the same size. background = Image.new("RGBA", img.size, background_color) # Calculate our alpha mask. start = int(255 - (255 * self.opacity)) # The start of our gradient. steps = int(255 * self.size) # The number of intermedite values. increment = (255 - start) / float(steps) mask = Image.new('L', (1, 255)) for y in range(255): if y < steps: val = int(y * increment + start) else: val = 255 mask.putpixel((0, y), val) alpha_mask = mask.resize(img.size) # Merge the reflection onto our background color using the alpha mask. reflection = Image.composite(background, reflection, alpha_mask) # Crop the reflection. reflection_height = int(img.size[1] * self.size) reflection = reflection.crop((0, 0, img.size[0], reflection_height)) # Create new image sized to hold both the original image and # the reflection. composite = Image.new("RGBA", (img.size[0], img.size[1] + reflection_height), background_color) # Paste the orignal image and the reflection into the composite image. composite.paste(img, (0, 0)) composite.paste(reflection, (0, img.size[1])) # Return the image complete with reflection effect. return composite class Transpose(object): """ Rotates or flips the image. """ AUTO = 'auto' FLIP_HORIZONTAL = Image.FLIP_LEFT_RIGHT FLIP_VERTICAL = Image.FLIP_TOP_BOTTOM ROTATE_90 = Image.ROTATE_90 ROTATE_180 = Image.ROTATE_180 ROTATE_270 = Image.ROTATE_270 methods = [AUTO] _EXIF_ORIENTATION_STEPS = { 1: [], 2: [FLIP_HORIZONTAL], 3: [ROTATE_180], 4: [FLIP_VERTICAL], 5: [ROTATE_270, FLIP_HORIZONTAL], 6: [ROTATE_270], 7: [ROTATE_90, FLIP_HORIZONTAL], 8: [ROTATE_90], } def __init__(self, *args): """ Possible arguments: - Transpose.AUTO - Transpose.FLIP_HORIZONTAL - Transpose.FLIP_VERTICAL - Transpose.ROTATE_90 - Transpose.ROTATE_180 - Transpose.ROTATE_270 The order of the arguments dictates the order in which the Transposition steps are taken. If Transpose.AUTO is present, all other arguments are ignored, and the processor will attempt to rotate the image according to the EXIF Orientation data. """ super(Transpose, self).__init__() if args: self.methods = args def process(self, img): if self.AUTO in self.methods: try: orientation = img._getexif()[0x0112] ops = self._EXIF_ORIENTATION_STEPS[orientation] except (IndexError, KeyError, TypeError, AttributeError): ops = [] else: ops = self.methods for method in ops: img = img.transpose(method) return img class Anchor(object): """ Defines all the anchor points needed by the various processor classes. """ TOP_LEFT = 'tl' TOP = 't' TOP_RIGHT = 'tr' BOTTOM_LEFT = 'bl' BOTTOM = 'b' BOTTOM_RIGHT = 'br' CENTER = 'c' LEFT = 'l' RIGHT = 'r' _ANCHOR_PTS = { TOP_LEFT: (0, 0), TOP: (0.5, 0), TOP_RIGHT: (1, 0), LEFT: (0, 0.5), CENTER: (0.5, 0.5), RIGHT: (1, 0.5), BOTTOM_LEFT: (0, 1), BOTTOM: (0.5, 1), BOTTOM_RIGHT: (1, 1), } @staticmethod def get_tuple(anchor): """Normalizes anchor values (strings or tuples) to tuples. """ # If the user passed in one of the string values, convert it to a # percentage tuple. if anchor in Anchor._ANCHOR_PTS.keys(): anchor = Anchor._ANCHOR_PTS[anchor] return anchor class MakeOpaque(object): """ Pastes the provided image onto an image of a solid color. Used for when you want to make transparent images opaque. """ def __init__(self, background_color=(255, 255, 255)): self.background_color = background_color def process(self, img): img = img.convert('RGBA') new_img = Image.new('RGBA', img.size, self.background_color) new_img.paste(img, img) return new_img pilkit-1.1.13/pilkit/processors/crop.py0000644000076700000240000001344712164413072020034 0ustar mjtstaff00000000000000from .base import Anchor # noqa from .utils import histogram_entropy from ..lib import Image, ImageChops, ImageDraw, ImageStat class Side(object): TOP = 't' RIGHT = 'r' BOTTOM = 'b' LEFT = 'l' ALL = (TOP, RIGHT, BOTTOM, LEFT) def _crop(img, bbox, sides=Side.ALL): bbox = ( bbox[0] if Side.LEFT in sides else 0, bbox[1] if Side.TOP in sides else 0, bbox[2] if Side.RIGHT in sides else img.size[0], bbox[3] if Side.BOTTOM in sides else img.size[1], ) return img.crop(bbox) def detect_border_color(img): mask = Image.new('1', img.size, 1) w, h = img.size[0] - 2, img.size[1] - 2 if w > 0 and h > 0: draw = ImageDraw.Draw(mask) draw.rectangle([1, 1, w, h], 0) return ImageStat.Stat(img.convert('RGBA').histogram(mask)).median class TrimBorderColor(object): """Trims a color from the sides of an image. """ def __init__(self, color=None, tolerance=0.3, sides=Side.ALL): """ :param color: The color to trim from the image, in a 4-tuple RGBA value, where each component is an integer between 0 and 255, inclusive. If no color is provided, the processor will attempt to detect the border color automatically. :param tolerance: A number between 0 and 1 where 0. Zero is the least tolerant and one is the most. :param sides: A list of sides that should be trimmed. Possible values are provided by the :class:`Side` enum class. """ self.color = color self.sides = sides self.tolerance = tolerance def process(self, img): source = img.convert('RGBA') border_color = self.color or tuple(detect_border_color(source)) bg = Image.new('RGBA', img.size, border_color) diff = ImageChops.difference(source, bg) if self.tolerance not in (0, 1): # If tolerance is zero, we've already done the job. A tolerance of # one would mean to trim EVERY color, and since that would result # in a zero-sized image, we just ignore it. if not 0 <= self.tolerance <= 1: raise ValueError('%s is an invalid tolerance. Acceptable values' ' are between 0 and 1 (inclusive).' % self.tolerance) tmp = ImageChops.constant(diff, int(self.tolerance * 255)) \ .convert('RGBA') diff = ImageChops.subtract(diff, tmp) bbox = diff.getbbox() if bbox: img = _crop(img, bbox, self.sides) return img class Crop(object): """ Crops an image, cropping it to the specified width and height. You may optionally provide either an anchor or x and y coordinates. This processor functions exactly the same as ``ResizeCanvas`` except that it will never enlarge the image. """ def __init__(self, width=None, height=None, anchor=None, x=None, y=None): self.width = width self.height = height self.anchor = anchor self.x = x self.y = y def process(self, img): from .resize import ResizeCanvas original_width, original_height = img.size new_width, new_height = min(original_width, self.width), \ min(original_height, self.height) return ResizeCanvas(new_width, new_height, anchor=self.anchor, x=self.x, y=self.y).process(img) class SmartCrop(object): """ Crop an image to the specified dimensions, whittling away the parts of the image with the least entropy. Based on smart crop implementation from easy-thumbnails: https://github.com/SmileyChris/easy-thumbnails/blob/master/easy_thumbnails/processors.py#L193 """ def __init__(self, width=None, height=None): """ :param width: The target width, in pixels. :param height: The target height, in pixels. """ self.width = width self.height = height def compare_entropy(self, start_slice, end_slice, slice, difference): """ Calculate the entropy of two slices (from the start and end of an axis), returning a tuple containing the amount that should be added to the start and removed from the end of the axis. """ start_entropy = histogram_entropy(start_slice) end_entropy = histogram_entropy(end_slice) if end_entropy and abs(start_entropy / end_entropy - 1) < 0.01: # Less than 1% difference, remove from both sides. if difference >= slice * 2: return slice, slice half_slice = slice // 2 return half_slice, slice - half_slice if start_entropy > end_entropy: return 0, slice else: return slice, 0 def process(self, img): source_x, source_y = img.size diff_x = int(source_x - min(source_x, self.width)) diff_y = int(source_y - min(source_y, self.height)) left = top = 0 right, bottom = source_x, source_y while diff_x: slice = min(diff_x, max(diff_x // 5, 10)) start = img.crop((left, 0, left + slice, source_y)) end = img.crop((right - slice, 0, right, source_y)) add, remove = self.compare_entropy(start, end, slice, diff_x) left += add right -= remove diff_x = diff_x - add - remove while diff_y: slice = min(diff_y, max(diff_y // 5, 10)) start = img.crop((0, top, source_x, top + slice)) end = img.crop((0, bottom - slice, source_x, bottom)) add, remove = self.compare_entropy(start, end, slice, diff_y) top += add bottom -= remove diff_y = diff_y - add - remove box = (left, top, right, bottom) img = img.crop(box) return img pilkit-1.1.13/pilkit/processors/resize.py0000644000076700000240000002314412164413072020365 0ustar mjtstaff00000000000000from .base import Anchor from ..lib import Image class Resize(object): """ Resizes an image to the specified width and height. """ def __init__(self, width, height, upscale=True): """ :param width: The target width, in pixels. :param height: The target height, in pixels. :param upscale: Should the image be enlarged if smaller than the dimensions? """ self.width = width self.height = height self.upscale = upscale def process(self, img): if self.upscale or (self.width < img.size[0] and self.height < img.size[1]): img = img.convert('RGBA') img = img.resize((self.width, self.height), Image.ANTIALIAS) return img class ResizeToCover(object): """ Resizes the image to the smallest possible size that will entirely cover the provided dimensions. You probably won't be using this processor directly, but it's used internally by ``ResizeToFill`` and ``SmartResize``. """ def __init__(self, width, height, upscale=True): """ :param width: The target width, in pixels. :param height: The target height, in pixels. """ self.width, self.height = width, height self.upscale = upscale def process(self, img): original_width, original_height = img.size ratio = max(float(self.width) / original_width, float(self.height) / original_height) new_width, new_height = (int(round(original_width * ratio)), int(round(original_height * ratio))) img = Resize(new_width, new_height, upscale=self.upscale).process(img) return img class ResizeToFill(object): """ Resizes an image, cropping it to the exact specified width and height. """ def __init__(self, width=None, height=None, anchor=None, upscale=True): """ :param width: The target width, in pixels. :param height: The target height, in pixels. :param anchor: Specifies which part of the image should be retained when cropping. :param upscale: Should the image be enlarged if smaller than the dimensions? """ self.width = width self.height = height self.anchor = anchor self.upscale = upscale def process(self, img): from .crop import Crop img = ResizeToCover(self.width, self.height, upscale=self.upscale).process(img) return Crop(self.width, self.height, anchor=self.anchor).process(img) class SmartResize(object): """ The ``SmartResize`` processor is identical to ``ResizeToFill``, except that it uses entropy to crop the image instead of a user-specified anchor point. Internally, it simply runs the ``ResizeToCover`` and ``SmartCrop`` processors in series. """ def __init__(self, width, height, upscale=True): """ :param width: The target width, in pixels. :param height: The target height, in pixels. :param upscale: Should the image be enlarged if smaller than the dimensions? """ self.width, self.height = width, height self.upscale = upscale def process(self, img): from .crop import SmartCrop img = ResizeToCover(self.width, self.height, upscale=self.upscale).process(img) return SmartCrop(self.width, self.height).process(img) class ResizeCanvas(object): """ Resizes the canvas, using the provided background color if the new size is larger than the current image. """ def __init__(self, width, height, color=None, anchor=None, x=None, y=None): """ :param width: The target width, in pixels. :param height: The target height, in pixels. :param color: The background color to use for padding. :param anchor: Specifies the position of the original image on the new canvas. Valid values are: - Anchor.TOP_LEFT - Anchor.TOP - Anchor.TOP_RIGHT - Anchor.LEFT - Anchor.CENTER - Anchor.RIGHT - Anchor.BOTTOM_LEFT - Anchor.BOTTOM - Anchor.BOTTOM_RIGHT You may also pass a tuple that indicates the position in percentages. For example, ``(0, 0)`` corresponds to "top left", ``(0.5, 0.5)`` to "center" and ``(1, 1)`` to "bottom right". This is basically the same as using percentages in CSS background positions. """ if x is not None or y is not None: if anchor: raise Exception('You may provide either an anchor or x and y' ' coordinate, but not both.') else: self.x, self.y = x or 0, y or 0 self.anchor = None else: self.anchor = anchor or Anchor.CENTER self.x = self.y = None self.width = width self.height = height self.color = color or (255, 255, 255, 0) def process(self, img): original_width, original_height = img.size if self.anchor: anchor = Anchor.get_tuple(self.anchor) trim_x, trim_y = self.width - original_width, \ self.height - original_height x = int(float(trim_x) * float(anchor[0])) y = int(float(trim_y) * float(anchor[1])) else: x, y = self.x, self.y new_img = Image.new('RGBA', (self.width, self.height), self.color) new_img.paste(img, (x, y)) return new_img class AddBorder(object): """ Add a border of specific color and size to an image. """ def __init__(self, thickness, color=None): """ :param color: Color to use for the border :param thickness: Thickness of the border. Can be either an int or a 4-tuple of ints of the form (top, right, bottom, left). """ self.color = color if isinstance(thickness, int): self.top = self.right = self.bottom = self.left = thickness else: self.top, self.right, self.bottom, self.left = thickness def process(self, img): new_width = img.size[0] + self.left + self.right new_height = img.size[1] + self.top + self.bottom return ResizeCanvas(new_width, new_height, color=self.color, x=self.left, y=self.top).process(img) class ResizeToFit(object): """ Resizes an image to fit within the specified dimensions. """ def __init__(self, width=None, height=None, upscale=True, mat_color=None, anchor=Anchor.CENTER): """ :param width: The maximum width of the desired image. :param height: The maximum height of the desired image. :param upscale: A boolean value specifying whether the image should be enlarged if its dimensions are smaller than the target dimensions. :param mat_color: If set, the target image size will be enforced and the specified color will be used as a background color to pad the image. """ self.width = width self.height = height self.upscale = upscale self.mat_color = mat_color self.anchor = anchor def process(self, img): cur_width, cur_height = img.size if not self.width is None and not self.height is None: ratio = min(float(self.width) / cur_width, float(self.height) / cur_height) else: if self.width is None: ratio = float(self.height) / cur_height else: ratio = float(self.width) / cur_width new_dimensions = (int(round(cur_width * ratio)), int(round(cur_height * ratio))) img = Resize(new_dimensions[0], new_dimensions[1], upscale=self.upscale).process(img) if self.mat_color is not None: img = ResizeCanvas(self.width, self.height, self.mat_color, anchor=self.anchor).process(img) return img class Thumbnail(object): """ Resize the image for use as a thumbnail. Wraps ``ResizeToFill``, ``ResizeToFit``, and ``SmartResize``. Note: while it doesn't currently, in the future this processor may also sharpen based on the amount of reduction. """ def __init__(self, width=None, height=None, anchor=None, crop=None, upscale=None): self.width = width self.height = height self.upscale = upscale if anchor: if crop is False: raise Exception("You can't specify an anchor point if crop is False.") else: crop = True elif crop is None: # Assume we are cropping if both a width and height are provided. If # only one is, we must be resizing to fit. crop = width is not None and height is not None # A default anchor if cropping. if crop and anchor is None: anchor = 'auto' self.crop = crop self.anchor = anchor def process(self, img): if self.crop: if not self.width or not self.height: raise Exception('You must provide both a width and height when' ' cropping.') if self.anchor == 'auto': processor = SmartResize(width=self.width, height=self.height, upscale=self.upscale) else: processor = ResizeToFill(width=self.width, height=self.height, anchor=self.anchor, upscale=self.upscale) else: processor = ResizeToFit(width=self.width, height=self.height, upscale=self.upscale) return processor.process(img) pilkit-1.1.13/pilkit/processors/utils.py0000644000076700000240000000106712164413072020224 0ustar mjtstaff00000000000000import math from ..lib import Image def histogram_entropy(im): """ Calculate the entropy of an images' histogram. Used for "smart cropping" in easy-thumbnails; see: https://raw.github.com/SmileyChris/easy-thumbnails/master/easy_thumbnails/utils.py """ if not isinstance(im, Image.Image): return 0 # Fall back to a constant entropy. histogram = im.histogram() hist_ceil = float(sum(histogram)) histonorm = [histocol / hist_ceil for histocol in histogram] return -sum([p * math.log(p, 2) for p in histonorm if p != 0]) pilkit-1.1.13/pilkit/utils.py0000644000076700000240000002745012412017267016030 0ustar mjtstaff00000000000000import os import mimetypes import sys from io import UnsupportedOperation from .exceptions import UnknownExtension, UnknownFormat from .lib import Image, ImageFile, StringIO, string_types RGBA_TRANSPARENCY_FORMATS = ['PNG'] PALETTE_TRANSPARENCY_FORMATS = ['PNG', 'GIF'] DEFAULT_EXTENSIONS = { 'JPEG': '.jpg', } def img_to_fobj(img, format, autoconvert=True, **options): return save_image(img, StringIO(), format, options, autoconvert) def open_image(target): target.seek(0) return Image.open(target) _pil_init = 0 def _preinit_pil(): """Loads the standard PIL file format drivers. Returns True if ``preinit()`` was called (and there's a potential that more drivers were loaded) or False if there is no possibility that new drivers were loaded. """ global _pil_init if _pil_init < 1: Image.preinit() _pil_init = 1 return True return False def _init_pil(): """Loads all PIL file format drivers. Returns True if ``init()`` was called (and there's a potential that more drivers were loaded) or False if there is no possibility that new drivers were loaded. """ global _pil_init _preinit_pil() if _pil_init < 2: Image.init() _pil_init = 2 return True return False def _extension_to_format(extension): return Image.EXTENSION.get(extension.lower()) def _format_to_extension(format): if format: format = format.upper() if format in DEFAULT_EXTENSIONS: ext = DEFAULT_EXTENSIONS[format] # It's not enough for an extension to be listed in # ``DEFAULT_EXTENSIONS``, it must also be recognized by PIL. if ext in Image.EXTENSION: return ext for k, v in Image.EXTENSION.items(): if v == format: return k return None def extension_to_mimetype(ext): try: filename = 'a%s' % (ext or '') # guess_type requires a full filename, not just an extension mimetype = mimetypes.guess_type(filename)[0] except IndexError: mimetype = None return mimetype def format_to_mimetype(format): return extension_to_mimetype(format_to_extension(format)) def extension_to_format(extension): """Returns the format that corresponds to the provided extension. """ format = _extension_to_format(extension) if not format and _preinit_pil(): format = _extension_to_format(extension) if not format and _init_pil(): format = _extension_to_format(extension) if not format: raise UnknownExtension(extension) return format def format_to_extension(format): """Returns the first extension that matches the provided format. """ extension = None if format: extension = _format_to_extension(format) if not extension and _preinit_pil(): extension = _format_to_extension(format) if not extension and _init_pil(): extension = _format_to_extension(format) if not extension: raise UnknownFormat(format) return extension def suggest_extension(name, format): original_extension = os.path.splitext(name)[1] try: suggested_extension = format_to_extension(format) except UnknownFormat: extension = original_extension else: if suggested_extension.lower() == original_extension.lower(): extension = original_extension else: try: original_format = extension_to_format(original_extension) except UnknownExtension: extension = suggested_extension else: # If the formats match, give precedence to the original extension. if format.lower() == original_format.lower(): extension = original_extension else: extension = suggested_extension return extension class FileWrapper(object): def __init__(self, wrapped): super(FileWrapper, self).__setattr__('_wrapped', wrapped) def fileno(self): try: return self._wrapped.fileno() except UnsupportedOperation: raise AttributeError def __getattr__(self, name): return getattr(self._wrapped, name) def __setattr__(self, name, value): return setattr(self._wrapped, name, value) def __delattr__(self, key): return delattr(self._wrapped, key) def save_image(img, outfile, format, options=None, autoconvert=True): """ Wraps PIL's ``Image.save()`` method. There are two main benefits of using this function over PIL's: 1. It gracefully handles the infamous "Suspension not allowed here" errors. 2. It prepares the image for saving using ``prepare_image()``, which will do some common-sense processing given the target format. """ options = options or {} if autoconvert: img, save_kwargs = prepare_image(img, format) # Use returned from prepare_image arguments for base # and update them with provided options. Then use the result save_kwargs.update(options) options = save_kwargs # Attempt to reset the file pointer. try: outfile.seek(0) except AttributeError: pass def save(fp): with quiet(): img.save(fp, format, **options) # Some versions of PIL only catch AttributeErrors where they should also # catch UnsupportedOperation exceptions. To work around this, we wrap the # file with an object that will raise the type of error it wants. if any(isinstance(outfile, t) for t in string_types): # ...but don't wrap strings. wrapper = outfile else: wrapper = FileWrapper(outfile) try: save(wrapper) except IOError: # PIL can have problems saving large JPEGs if MAXBLOCK isn't big enough, # So if we have a problem saving, we temporarily increase it. See # http://github.com/matthewwithanm/django-imagekit/issues/50 # https://github.com/matthewwithanm/django-imagekit/issues/134 # https://github.com/python-imaging/Pillow/issues/148 # https://github.com/matthewwithanm/pilkit/commit/0f914e8b40e3d30f28e04ffb759b262aa8a1a082#commitcomment-3885362 # MAXBLOCK must be at least as big as... new_maxblock = max( (len(options['exif']) if 'exif' in options else 0) + 5, # ...the entire exif header block img.size[0] * 4, # ...a complete scan line 3 * img.size[0] * img.size[1], # ...3 bytes per every pixel in the image ) if new_maxblock < ImageFile.MAXBLOCK: raise old_maxblock = ImageFile.MAXBLOCK ImageFile.MAXBLOCK = new_maxblock try: save(wrapper) finally: ImageFile.MAXBLOCK = old_maxblock try: outfile.seek(0) except AttributeError: pass return outfile class quiet(object): """ A context manager for suppressing the stderr activity of PIL's C libraries. Based on http://stackoverflow.com/a/978264/155370 """ def __enter__(self): try: self.null_fd = os.open(os.devnull, os.O_RDWR) except OSError: # If dev/null isn't writeable, then they just have to put up with # the noise. return self.stderr_fd = sys.__stderr__.fileno() self.old = os.dup(self.stderr_fd) os.dup2(self.null_fd, self.stderr_fd) def __exit__(self, *args, **kwargs): if not getattr(self, 'null_fd', None): return os.dup2(self.old, self.stderr_fd) os.close(self.null_fd) os.close(self.old) def prepare_image(img, format): """ Prepares the image for saving to the provided format by doing some common-sense conversions. This includes things like preserving transparency and quantizing. This function is used automatically by ``save_image()`` immediately before saving unless you specify ``autoconvert=False``. It is provided as a utility for those doing their own processing. :param img: The image to prepare for saving. :param format: The format that the image will be saved to. """ make_opaque = False save_kwargs = {} format = format.upper() if img.mode == 'RGBA': if format in RGBA_TRANSPARENCY_FORMATS: pass elif format in PALETTE_TRANSPARENCY_FORMATS: # If you're going from a format with alpha transparency to one # with palette transparency, transparency values will be # snapped: pixels that are more opaque than not will become # fully opaque; pixels that are more transparent than not will # become fully transparent. This will not produce a good-looking # result if your image contains varying levels of opacity; in # that case, you'll probably want to use a processor to composite # the image on a solid color. The reason we don't do this by # default is because not doing so allows processors to treat # RGBA-format images as a super-type of P-format images: if you # have an RGBA-format image with only a single transparent # color, and save it as a GIF, it will retain its transparency. # In other words, a P-format image converted to an # RGBA-formatted image by a processor and then saved as a # P-format image will give the expected results. # Work around a bug in PIL: split() doesn't check to see if # img is loaded. img.load() alpha = img.split()[-1] mask = Image.eval(alpha, lambda a: 255 if a <= 128 else 0) img = img.convert('RGB').convert('P', palette=Image.ADAPTIVE, colors=255) img.paste(255, mask) save_kwargs['transparency'] = 255 else: # Simply converting an RGBA-format image to an RGB one creates a # gross result, so we paste the image onto a white background. If # that's not what you want, that's fine: use a processor to deal # with the transparency however you want. This is simply a # sensible default that will always produce something that looks # good. Or at least, it will look better than just a straight # conversion. make_opaque = True elif img.mode == 'P': if format in PALETTE_TRANSPARENCY_FORMATS: try: save_kwargs['transparency'] = img.info['transparency'] except KeyError: pass elif format in RGBA_TRANSPARENCY_FORMATS: # Currently PIL doesn't support any RGBA-mode formats that # aren't also P-mode formats, so this will never happen. img = img.convert('RGBA') else: make_opaque = True else: img = img.convert('RGB') # GIFs are always going to be in palette mode, so we can do a little # optimization. Note that the RGBA sources also use adaptive # quantization (above). Images that are already in P mode don't need # any quantization because their colors are already limited. if format == 'GIF': img = img.convert('P', palette=Image.ADAPTIVE) if make_opaque: from .processors import MakeOpaque img = MakeOpaque().process(img).convert('RGB') if format == 'JPEG': save_kwargs['optimize'] = True return img, save_kwargs def process_image(img, processors=None, format=None, autoconvert=True, options=None): from .processors import ProcessorPipeline original_format = img.format # Run the processors img = ProcessorPipeline(processors or []).process(img) format = format or img.format or original_format or 'JPEG' options = options or {} return img_to_fobj(img, format, autoconvert, **options) pilkit-1.1.13/pilkit.egg-info/0000755000076700000240000000000012562721725016007 5ustar mjtstaff00000000000000pilkit-1.1.13/pilkit.egg-info/dependency_links.txt0000644000076700000240000000000112562721724022054 0ustar mjtstaff00000000000000 pilkit-1.1.13/pilkit.egg-info/not-zip-safe0000644000076700000240000000000112170343075020226 0ustar mjtstaff00000000000000 pilkit-1.1.13/pilkit.egg-info/PKG-INFO0000644000076700000240000001073712562721724017113 0ustar mjtstaff00000000000000Metadata-Version: 1.1 Name: pilkit Version: 1.1.13 Summary: A collection of utilities and processors for the Python Imaging Libary. Home-page: http://github.com/matthewwithanm/pilkit/ Author: Matthew Tretter Author-email: m@tthewwithanm.com License: BSD Description: PILKit is a collection of utilities for working with PIL (the Python Imaging Library). One of its main features is a set of **processors** which expose a simple interface for performing manipulations on PIL images. Looking for more advanced processors? Check out `Instakit`_! **For the complete documentation on the latest stable version of PILKit, see** `PILKit on RTD`_. .. image:: https://api.travis-ci.org/matthewwithanm/pilkit.png .. _`PILKit on RTD`: http://pilkit.readthedocs.org .. _`Instakit`: https://github.com/fish2000/instakit Installation ============ 1. Install `PIL`_ or `Pillow`_. 2. Run ``pip install pilkit`` (or clone the source and put the pilkit module on your path) .. note:: If you've never seen Pillow before, it considers itself a more-frequently updated "friendly" fork of PIL that's compatible with setuptools. As such, it shares the same namespace as PIL does and is a drop-in replacement. .. _`PIL`: http://pypi.python.org/pypi/PIL .. _`Pillow`: http://pypi.python.org/pypi/Pillow Usage Overview ============== Processors ---------- The "pilkit.processors" module contains several classes for processing PIL images, which provide an easy to understand API: .. code-block:: python from pilkit.processors import ResizeToFit img = Image.open('/path/to/my/image.png') processor = ResizeToFit(100, 100) new_img = processor.process(img) A few of the included processors are: * ``ResizeToFit`` * ``ResizeToFill`` * ``SmartResize`` * ``Adjust`` * ``TrimBorderColor`` * ``Transpose`` There's also a ``ProcessorPipeline`` class for executing processors sequentially: .. code-block:: python from pilkit.processors import ProcessorPipeline, ResizeToFit, Adjust img = Image.open('/path/to/my/image.png') processor = ProcessorPipeline([Adjust(color=0), ResizeToFit(100, 100)]) new_image = processor.process(img) Utilities --------- In addition to the processors, PILKit contains a few utilities to ease the pain of working with PIL. Some examples: ``prepare_image`` Prepares the image for saving to the provided format by doing some common-sense conversions, including preserving transparency and quantizing. ``save_image`` Wraps PIL's ``Image.save()`` method in order to gracefully handle PIL's "Suspension not allowed here" errors, and (optionally) prepares the image using ``prepare_image`` Utilities are also included for converting between formats, extensions, and mimetypes. Community ========= Please use `the GitHub issue tracker `_ to report bugs. `A mailing list `_ also exists to discuss the project and ask questions, as well as the official `#imagekit `_ channel on Freenode. (Both of these are shared with the `django-imagekit`_ project—from which PILKit spun off.) .. _`django-imagekit`: https://github.com/jdriscoll/django-imagekit Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: BSD License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python :: 2.5 Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3.2 Classifier: Programming Language :: Python :: 3.3 Classifier: Topic :: Utilities pilkit-1.1.13/pilkit.egg-info/SOURCES.txt0000644000076700000240000000213612562721724017674 0ustar mjtstaff00000000000000AUTHORS LICENSE MANIFEST.in README.rst setup.py docs/Makefile docs/make.bat docs/source/conf.py docs/source/index.rst pilkit/__init__.py pilkit/exceptions.py pilkit/lib.py pilkit/pkgmeta.py pilkit/utils.py pilkit.egg-info/PKG-INFO pilkit.egg-info/SOURCES.txt pilkit.egg-info/dependency_links.txt pilkit.egg-info/not-zip-safe pilkit.egg-info/top_level.txt pilkit/processors/__init__.py pilkit/processors/base.py pilkit/processors/crop.py pilkit/processors/resize.py pilkit/processors/utils.py tests/__init__.py tests/__init__.pyc tests/test_processors.py tests/test_processors.pyc tests/test_utils.py tests/test_utils.pyc tests/utils.py tests/utils.pyc tests/__pycache__/__init__.cpython-32.pyc tests/__pycache__/__init__.cpython-33.pyc tests/__pycache__/test_processors.cpython-32.pyc tests/__pycache__/test_processors.cpython-33.pyc tests/__pycache__/test_utils.cpython-32.pyc tests/__pycache__/test_utils.cpython-33.pyc tests/__pycache__/utils.cpython-32.pyc tests/__pycache__/utils.cpython-33.pyc tests/assets/cat.gif tests/assets/lenna-800x600-white-border.jpg tests/assets/lenna-800x600.jpg tests/assets/lenna.pngpilkit-1.1.13/pilkit.egg-info/top_level.txt0000644000076700000240000000000712562721724020535 0ustar mjtstaff00000000000000pilkit pilkit-1.1.13/PKG-INFO0000644000076700000240000001073712562721725014126 0ustar mjtstaff00000000000000Metadata-Version: 1.1 Name: pilkit Version: 1.1.13 Summary: A collection of utilities and processors for the Python Imaging Libary. Home-page: http://github.com/matthewwithanm/pilkit/ Author: Matthew Tretter Author-email: m@tthewwithanm.com License: BSD Description: PILKit is a collection of utilities for working with PIL (the Python Imaging Library). One of its main features is a set of **processors** which expose a simple interface for performing manipulations on PIL images. Looking for more advanced processors? Check out `Instakit`_! **For the complete documentation on the latest stable version of PILKit, see** `PILKit on RTD`_. .. image:: https://api.travis-ci.org/matthewwithanm/pilkit.png .. _`PILKit on RTD`: http://pilkit.readthedocs.org .. _`Instakit`: https://github.com/fish2000/instakit Installation ============ 1. Install `PIL`_ or `Pillow`_. 2. Run ``pip install pilkit`` (or clone the source and put the pilkit module on your path) .. note:: If you've never seen Pillow before, it considers itself a more-frequently updated "friendly" fork of PIL that's compatible with setuptools. As such, it shares the same namespace as PIL does and is a drop-in replacement. .. _`PIL`: http://pypi.python.org/pypi/PIL .. _`Pillow`: http://pypi.python.org/pypi/Pillow Usage Overview ============== Processors ---------- The "pilkit.processors" module contains several classes for processing PIL images, which provide an easy to understand API: .. code-block:: python from pilkit.processors import ResizeToFit img = Image.open('/path/to/my/image.png') processor = ResizeToFit(100, 100) new_img = processor.process(img) A few of the included processors are: * ``ResizeToFit`` * ``ResizeToFill`` * ``SmartResize`` * ``Adjust`` * ``TrimBorderColor`` * ``Transpose`` There's also a ``ProcessorPipeline`` class for executing processors sequentially: .. code-block:: python from pilkit.processors import ProcessorPipeline, ResizeToFit, Adjust img = Image.open('/path/to/my/image.png') processor = ProcessorPipeline([Adjust(color=0), ResizeToFit(100, 100)]) new_image = processor.process(img) Utilities --------- In addition to the processors, PILKit contains a few utilities to ease the pain of working with PIL. Some examples: ``prepare_image`` Prepares the image for saving to the provided format by doing some common-sense conversions, including preserving transparency and quantizing. ``save_image`` Wraps PIL's ``Image.save()`` method in order to gracefully handle PIL's "Suspension not allowed here" errors, and (optionally) prepares the image using ``prepare_image`` Utilities are also included for converting between formats, extensions, and mimetypes. Community ========= Please use `the GitHub issue tracker `_ to report bugs. `A mailing list `_ also exists to discuss the project and ask questions, as well as the official `#imagekit `_ channel on Freenode. (Both of these are shared with the `django-imagekit`_ project—from which PILKit spun off.) .. _`django-imagekit`: https://github.com/jdriscoll/django-imagekit Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: BSD License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python :: 2.5 Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3.2 Classifier: Programming Language :: Python :: 3.3 Classifier: Topic :: Utilities pilkit-1.1.13/README.rst0000644000076700000240000000567212267510475014522 0ustar mjtstaff00000000000000PILKit is a collection of utilities for working with PIL (the Python Imaging Library). One of its main features is a set of **processors** which expose a simple interface for performing manipulations on PIL images. Looking for more advanced processors? Check out `Instakit`_! **For the complete documentation on the latest stable version of PILKit, see** `PILKit on RTD`_. .. image:: https://api.travis-ci.org/matthewwithanm/pilkit.png .. _`PILKit on RTD`: http://pilkit.readthedocs.org .. _`Instakit`: https://github.com/fish2000/instakit Installation ============ 1. Install `PIL`_ or `Pillow`_. 2. Run ``pip install pilkit`` (or clone the source and put the pilkit module on your path) .. note:: If you've never seen Pillow before, it considers itself a more-frequently updated "friendly" fork of PIL that's compatible with setuptools. As such, it shares the same namespace as PIL does and is a drop-in replacement. .. _`PIL`: http://pypi.python.org/pypi/PIL .. _`Pillow`: http://pypi.python.org/pypi/Pillow Usage Overview ============== Processors ---------- The "pilkit.processors" module contains several classes for processing PIL images, which provide an easy to understand API: .. code-block:: python from pilkit.processors import ResizeToFit img = Image.open('/path/to/my/image.png') processor = ResizeToFit(100, 100) new_img = processor.process(img) A few of the included processors are: * ``ResizeToFit`` * ``ResizeToFill`` * ``SmartResize`` * ``Adjust`` * ``TrimBorderColor`` * ``Transpose`` There's also a ``ProcessorPipeline`` class for executing processors sequentially: .. code-block:: python from pilkit.processors import ProcessorPipeline, ResizeToFit, Adjust img = Image.open('/path/to/my/image.png') processor = ProcessorPipeline([Adjust(color=0), ResizeToFit(100, 100)]) new_image = processor.process(img) Utilities --------- In addition to the processors, PILKit contains a few utilities to ease the pain of working with PIL. Some examples: ``prepare_image`` Prepares the image for saving to the provided format by doing some common-sense conversions, including preserving transparency and quantizing. ``save_image`` Wraps PIL's ``Image.save()`` method in order to gracefully handle PIL's "Suspension not allowed here" errors, and (optionally) prepares the image using ``prepare_image`` Utilities are also included for converting between formats, extensions, and mimetypes. Community ========= Please use `the GitHub issue tracker `_ to report bugs. `A mailing list `_ also exists to discuss the project and ask questions, as well as the official `#imagekit `_ channel on Freenode. (Both of these are shared with the `django-imagekit`_ project—from which PILKit spun off.) .. _`django-imagekit`: https://github.com/jdriscoll/django-imagekit pilkit-1.1.13/setup.cfg0000644000076700000240000000007312562721725014642 0ustar mjtstaff00000000000000[egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 pilkit-1.1.13/setup.py0000644000076700000240000000330712562721470014533 0ustar mjtstaff00000000000000#/usr/bin/env python import codecs import os from setuptools import setup, find_packages # Workaround for multiprocessing/nose issue. See http://bugs.python.org/msg170215 try: import multiprocessing except ImportError: pass read = lambda filepath: codecs.open(filepath, 'r', 'utf-8').read() # Load package meta from the pkgmeta module without loading the package. pkgmeta = {} pkgmeta_file = os.path.join(os.path.dirname(__file__), 'pilkit', 'pkgmeta.py') with open(pkgmeta_file) as f: code = compile(f.read(), 'pkgmeta.py', 'exec') exec(code, pkgmeta) setup( name='pilkit', version=pkgmeta['__version__'], description='A collection of utilities and processors for the Python Imaging Libary.', long_description=read(os.path.join(os.path.dirname(__file__), 'README.rst')), author='Matthew Tretter', author_email='m@tthewwithanm.com', license='BSD', url='http://github.com/matthewwithanm/pilkit/', packages=find_packages(exclude=['tests', 'tests.*']), zip_safe=False, include_package_data=True, tests_require=[ 'mock==1.0.1', 'nose==1.2.1', 'nose-progressive==1.3', 'Pillow', ], test_suite='nose.collector', install_requires=[], classifiers=[ 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', 'License :: OSI Approved :: BSD License', 'Operating System :: OS Independent', 'Programming Language :: Python :: 2.5', 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3.2', 'Programming Language :: Python :: 3.3', 'Topic :: Utilities' ], ) pilkit-1.1.13/tests/0000755000076700000240000000000012562721725014163 5ustar mjtstaff00000000000000pilkit-1.1.13/tests/__init__.py0000644000076700000240000000000012164413072016251 0ustar mjtstaff00000000000000pilkit-1.1.13/tests/__init__.pyc0000644000076700000240000000023012336653326016432 0ustar mjtstaff00000000000000 :Qc@sdS(N((((sA/Users/mjt/Code/projects/django-imagekit/pilkit/tests/__init__.pytspilkit-1.1.13/tests/__pycache__/0000755000076700000240000000000012562721725016373 5ustar mjtstaff00000000000000pilkit-1.1.13/tests/__pycache__/__init__.cpython-32.pyc0000644000076700000240000000023412175071025022542 0ustar mjtstaff00000000000000l :Qc@sdS(N((((uA/Users/mjt/Code/projects/django-imagekit/pilkit/tests/__init__.pyuspilkit-1.1.13/tests/__pycache__/__init__.cpython-33.pyc0000644000076700000240000000024012175067203022543 0ustar mjtstaff00000000000000 :Qc@sdS(N((((uA/Users/mjt/Code/projects/django-imagekit/pilkit/tests/__init__.pyuspilkit-1.1.13/tests/__pycache__/test_processors.cpython-32.pyc0000644000076700000240000002065012175365433024261 0ustar mjtstaff00000000000000l uQc@sVddlmZmZddlmZmZmZmZmZddl m Z m Z ddl m Z ddlmZddlZdZd Zd Zd Zd Zd ZdZdZdZdZejddZejddZejddZejddZejddZ dS(i(uImageu ImageDraw(uResizeu ResizeToFillu ResizeToFitu SmartCropu SmartResize(ueq_u assert_true(u Thumbnaili(u create_imageNcCs/tddjt}t|jddS(Nid(idid(u SmartCropuprocessu create_imageueq_usize(uimg((uH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyutest_smartcrop scCs/tddjt}t|jddS(Nid(idid(u ResizeToFilluprocessu create_imageueq_usize(uimg((uH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyutest_resizetofillscCs>tjdd}tddj|}t|jddS(NuRGBiidi2(iid(idi2(uImageunewu ResizeToFituprocessueq_usize(uimg((uH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyutest_resizetofitscCs>tjdd}tddj|}t|jddS(u5 Regression test for matthewwithanm/pilkit#1 uRGBi_iN(i_i_(ii(uImageunewu ResizeToFilluprocessueq_usize(uimg((uH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyutest_resize_roundingscCsDtjdd}tddddj|}t|jddS(NuRGBiidu mat_colori(iid(idid(uImageunewu ResizeToFituprocessueq_usize(uimg((uH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyutest_resizetofit_mat)sc Cstjdd d}|jdddddddddg tj|}|jd dd tddj|}ttt d |j }t |d kd S( u% Test that the Resize processor antialiases. The Resize processor is used by all of the Resize* variants, so this should cover all of resize processors. Basically, this is to test that it converts to RGBA mode before resizing. Related: jdriscoll/django-imagekit#192 uPiiiiidiufilliN(ii(ididii( uImageunewu putpaletteu ImageDrawuellipseuResizeuprocessulenulistufilteruNoneu histogramu assert_true(uimgudu color_count((uH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyutest_resize_antialiasing/s   !cCstjdd}xvttttgD]b}|ddddj|}t|j d|dddd j|}t|j d q%WdS( u< Test that the upscale argument works as expected. uRGBidiuupscaleN(ididT(iiF(idid( uImageunewuResizeu ResizeToFitu ResizeToFillu SmartResizeuTrueuprocessueq_usizeuFalse(uimguPuimg2((uH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyu test_upscaleMs cCshy)tdddddd dd ddWn8tk rc}ztt|dWYdd}~XnXdS( Nuheightiuwidthuupscaleucropuanchorutu3You can't specify an anchor point if crop is False.F(u ThumbnailuFalseu Exceptionueq_ustr(ue((uH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyuHtest_should_raise_exception_if_anchor_is_passed_and_crop_is_set_to_false]s)c Cs2tdddddddd}t|jdS(NuheightiuwidthuupscaleuanchorutF(u ThumbnailuFalseu assert_trueucrop(uthumb((uH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyu=test_should_set_crop_to_true_if_anchor_is_passed_without_cropds!cCsktjdd}ytddj|Wn8tk rf}ztt|dWYdd}~XnXdS(NuRGBiducropu7You must provide both a width and height when cropping.(ididT(uImageunewu ThumbnailuTrueuprocessu Exceptionueq_ustr(uimgue((uH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyuHtest_should_raise_exception_when_crop_is_passed_without_height_and_widthis u$pilkit.processors.resize.SmartResizecCsEtjdd}tddddddj|t|jdS( NuRGBiduheightiuwidthuupscale(ididF(uImageunewu ThumbnailuFalseuprocessu assert_trueucalled(umy_mockuimg((uH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyu1test_should_call_smartresize_when_crop_not_passedqs"cCsTtjdd}tddddddj||jdddddddS( NuRGBiduheightiuwidthuupscale(ididT(uImageunewu ThumbnailuTrueuprocessuassert_called_once_with(umy_mockuimg((uH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyu&test_should_repass_upscale_option_truexs"cCsTtjdd}tddddddj||jdddddddS( NuRGBiduheightiuwidthuupscale(ididF(uImageunewu ThumbnailuFalseuprocessuassert_called_once_with(umy_mockuimg((uH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyu'test_should_repass_upscale_option_falses"u%pilkit.processors.resize.ResizeToFillcCsEtjdd}tddddddj|t|jdS( NuRGBiduheightiuwidthuanchorufake(idid(uImageunewu Thumbnailuprocessu assert_trueucalled(umy_mockuimg((uH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyu;test_should_call_resizetofill_when_crop_and_ancho_is_passeds"u$pilkit.processors.resize.ResizeToFitcCsEtjdd}tddddddj|t|jdS( NuRGBiduheightiuwidthucrop(ididF(uImageunewu ThumbnailuFalseuprocessu assert_trueucalled(umy_mockuimg((uH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyu4test_should_call_resizetofit_when_crop_is_not_passeds"(!u pilkit.libuImageu ImageDrawupilkit.processorsuResizeu ResizeToFillu ResizeToFitu SmartCropu SmartResizeu nose.toolsueq_u assert_trueupilkit.processors.resizeu Thumbnailuutilsu create_imageumockutest_smartcroputest_resizetofillutest_resizetofitutest_resize_roundingutest_resizetofit_matutest_resize_antialiasingu test_upscaleuHtest_should_raise_exception_if_anchor_is_passed_and_crop_is_set_to_falseu=test_should_set_crop_to_true_if_anchor_is_passed_without_cropuHtest_should_raise_exception_when_crop_is_passed_without_height_and_widthupatchu1test_should_call_smartresize_when_crop_not_passedu&test_should_repass_upscale_option_trueu'test_should_repass_upscale_option_falseu;test_should_call_resizetofill_when_crop_and_ancho_is_passedu4test_should_call_resizetofit_when_crop_is_not_passed(((uH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyus((         pilkit-1.1.13/tests/__pycache__/test_processors.cpython-33.pyc0000644000076700000240000002213112175365434024257 0ustar mjtstaff00000000000000 uQic@sddlmZmZddlmZmZmZmZmZddl m Z m Z ddl m Z ddlmZddlZdd Zd d Zd d ZddZddZddZddZddZddZddZejdddZejddd Zejdd!d"Zejd#d$d%Zejd&d'd(Z dS()i(uImageu ImageDraw(uResizeu ResizeToFillu ResizeToFitu SmartCropu SmartResize(ueq_u assert_true(u Thumbnaili(u create_imageNcCs/tddjt}t|jddS(Nid(idid(u SmartCropuprocessu create_imageueq_usize(uimg((uH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyutest_smartcrop sutest_smartcropcCs/tddjt}t|jddS(Nid(idid(u ResizeToFilluprocessu create_imageueq_usize(uimg((uH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyutest_resizetofillsutest_resizetofillcCs>tjdd}tddj|}t|jddS(NuRGBiidi2(iid(idi2(uImageunewu ResizeToFituprocessueq_usize(uimg((uH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyutest_resizetofitsutest_resizetofitcCs>tjdd}tddj|}t|jddS(u5 Regression test for matthewwithanm/pilkit#1 uRGBi_iN(i_i_(ii(uImageunewu ResizeToFilluprocessueq_usize(uimg((uH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyutest_resize_roundingsutest_resize_roundingcCsDtjdd}tddddj|}t|jddS(NuRGBiidu mat_colori(iid(idid(uImageunewu ResizeToFituprocessueq_usize(uimg((uH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyutest_resizetofit_mat)sutest_resizetofit_matc Cstjdd d}|jdddddddddg tj|}|jd dd tddj|}ttt d |j }t |d kd S( u% Test that the Resize processor antialiases. The Resize processor is used by all of the Resize* variants, so this should cover all of resize processors. Basically, this is to test that it converts to RGBA mode before resizing. Related: jdriscoll/django-imagekit#192 uPiiiiidiufilliN(ii(ididii( uImageunewu putpaletteu ImageDrawuellipseuResizeuprocessulenulistufilteruNoneu histogramu assert_true(uimgudu color_count((uH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyutest_resize_antialiasing/s   !utest_resize_antialiasingcCstjdd}xvttttgD]b}|ddddj|}t|j d|dddd j|}t|j d q%WdS( u< Test that the upscale argument works as expected. uRGBidiuupscaleN(ididT(iiF(idid( uImageunewuResizeu ResizeToFitu ResizeToFillu SmartResizeuTrueuprocessueq_usizeuFalse(uimguPuimg2((uH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyu test_upscaleMs u test_upscalecCshy)tdddddd dd ddWn8tk rc}ztt|dWYdd}~XnXdS( Nuheightiuwidthuupscaleucropuanchorutu3You can't specify an anchor point if crop is False.F(u ThumbnailuFalseu Exceptionueq_ustr(ue((uH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyuHtest_should_raise_exception_if_anchor_is_passed_and_crop_is_set_to_false]s)uHtest_should_raise_exception_if_anchor_is_passed_and_crop_is_set_to_falsec Cs2tdddddddd}t|jdS(NuheightiuwidthuupscaleuanchorutF(u ThumbnailuFalseu assert_trueucrop(uthumb((uH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyu=test_should_set_crop_to_true_if_anchor_is_passed_without_cropds!u=test_should_set_crop_to_true_if_anchor_is_passed_without_cropcCsktjdd}ytddj|Wn8tk rf}ztt|dWYdd}~XnXdS(NuRGBiducropu7You must provide both a width and height when cropping.(ididT(uImageunewu ThumbnailuTrueuprocessu Exceptionueq_ustr(uimgue((uH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyuHtest_should_raise_exception_when_crop_is_passed_without_height_and_widthis uHtest_should_raise_exception_when_crop_is_passed_without_height_and_widthu$pilkit.processors.resize.SmartResizecCsEtjdd}tddddddj|t|jdS( NuRGBiduheightiuwidthuupscale(ididF(uImageunewu ThumbnailuFalseuprocessu assert_trueucalled(umy_mockuimg((uH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyu1test_should_call_smartresize_when_crop_not_passedqs"u1test_should_call_smartresize_when_crop_not_passedcCsTtjdd}tddddddj||jdddddddS( NuRGBiduheightiuwidthuupscale(ididT(uImageunewu ThumbnailuTrueuprocessuassert_called_once_with(umy_mockuimg((uH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyu&test_should_repass_upscale_option_truexs"u&test_should_repass_upscale_option_truecCsTtjdd}tddddddj||jdddddddS( NuRGBiduheightiuwidthuupscale(ididF(uImageunewu ThumbnailuFalseuprocessuassert_called_once_with(umy_mockuimg((uH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyu'test_should_repass_upscale_option_falses"u'test_should_repass_upscale_option_falseu%pilkit.processors.resize.ResizeToFillcCsEtjdd}tddddddj|t|jdS( NuRGBiduheightiuwidthuanchorufake(idid(uImageunewu Thumbnailuprocessu assert_trueucalled(umy_mockuimg((uH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyu;test_should_call_resizetofill_when_crop_and_ancho_is_passeds"u;test_should_call_resizetofill_when_crop_and_ancho_is_passedu$pilkit.processors.resize.ResizeToFitcCsEtjdd}tddddddj|t|jdS( NuRGBiduheightiuwidthucrop(ididF(uImageunewu ThumbnailuFalseuprocessu assert_trueucalled(umy_mockuimg((uH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyu4test_should_call_resizetofit_when_crop_is_not_passeds"u4test_should_call_resizetofit_when_crop_is_not_passed(!u pilkit.libuImageu ImageDrawupilkit.processorsuResizeu ResizeToFillu ResizeToFitu SmartCropu SmartResizeu nose.toolsueq_u assert_trueupilkit.processors.resizeu Thumbnailuutilsu create_imageumockutest_smartcroputest_resizetofillutest_resizetofitutest_resize_roundingutest_resizetofit_matutest_resize_antialiasingu test_upscaleuHtest_should_raise_exception_if_anchor_is_passed_and_crop_is_set_to_falseu=test_should_set_crop_to_true_if_anchor_is_passed_without_cropuHtest_should_raise_exception_when_crop_is_passed_without_height_and_widthupatchu1test_should_call_smartresize_when_crop_not_passedu&test_should_repass_upscale_option_trueu'test_should_repass_upscale_option_falseu;test_should_call_resizetofill_when_crop_and_ancho_is_passedu4test_should_call_resizetofit_when_crop_is_not_passed(((uH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyus((         pilkit-1.1.13/tests/__pycache__/test_utils.cpython-32.pyc0000644000076700000240000001052712336653331023215 0ustar mjtstaff00000000000000l wzRc@s ddlmZddlmZmZddlmZddlmZm Z m Z m Z m Z ddl mZmZmZddlmZddlmZd Zd Zeed Zeed Zd ZeedZdZdZdS(i(uUnsupportedOperation(u UnknownFormatuUnknownExtension(uImage(uextension_to_formatuformat_to_extensionu FileWrapperu save_imageu prepare_image(ueq_uraisesuok_(uNamedTemporaryFilei(u create_imagecCs*ttddttdddS(Nu.jpeguJPEGu.rgbauSGI(ueq_uextension_to_format(((uC/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_utils.pyutest_extension_to_format scCs*ttddttdddS(NuPNGu.pnguICOu.ico(ueq_uformat_to_extension(((uC/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_utils.pyu test_format_to_extension_no_initscCstddS(NuTXT(uformat_to_extension(((uC/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_utils.pyutest_unknown_formatscCstddS(Nu.txt(uextension_to_format(((uC/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_utils.pyutest_unknown_extensionscCsttdddS(u] Ensure default extensions are honored. Since PIL's ``Image.EXTENSION`` lists ``'.jpe'`` before the more common JPEG extensions, it would normally be the extension we'd get for that format. ``pilkit.utils.DEFAULT_EXTENSIONS`` is our way of specifying which extensions we'd prefer, and this tests to make sure it's working. uJPEGu.jpgN(ueq_uformat_to_extension(((uC/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_utils.pyutest_default_extensions cCs*Gddt}t|jdS(NcBs|EeZdZdS(cSs tdS(N(uUnsupportedOperation(uself((uC/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_utils.pyufileno0sN(u__name__u __module__ufileno(u __locals__((uC/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_utils.pyuK/s uK(uobjectu FileWrapperufileno(uK((uC/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_utils.pyutest_filewrapper,scCs3t}t}t||jd|jdS(ur Test that ``save_image`` accepts filename strings (not just file objects). This is a test for GH-8. uJPEGN(u create_imageuNamedTemporaryFileu save_imageunameuclose(uimuoutfile((uC/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_utils.pyutest_save_with_filename6s  cCs3tjdd}tdt|ddkdS(u Make sure formats are normalized by ``prepare_image()``. See https://github.com/matthewwithanm/django-imagekit/issues/262 uRGBAidu transparencyugIFiN(idid(uImageunewuok_u prepare_image(uim((uC/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_utils.pyutest_format_normalizationBsN(uiouUnsupportedOperationupilkit.exceptionsu UnknownFormatuUnknownExtensionu pilkit.libuImageu pilkit.utilsuextension_to_formatuformat_to_extensionu FileWrapperu save_imageu prepare_imageu nose.toolsueq_uraisesuok_utempfileuNamedTemporaryFileuutilsu create_imageutest_extension_to_formatu test_format_to_extension_no_initutest_unknown_formatutest_unknown_extensionutest_default_extensionuAttributeErrorutest_filewrapperutest_save_with_filenameutest_format_normalization(((uC/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_utils.pyus(    pilkit-1.1.13/tests/__pycache__/test_utils.cpython-33.pyc0000644000076700000240000001126612336653334023222 0ustar mjtstaff00000000000000 wzRc@s"ddlmZddlmZmZddlmZddlmZm Z m Z m Z m Z ddl mZmZmZddlmZddlmZd d Zd d Zeed dZeeddZddZeeddZddZddZdS(i(uUnsupportedOperation(u UnknownFormatuUnknownExtension(uImage(uextension_to_formatuformat_to_extensionu FileWrapperu save_imageu prepare_image(ueq_uraisesuok_(uNamedTemporaryFilei(u create_imagecCs*ttddttdddS(Nu.jpeguJPEGu.rgbauSGI(ueq_uextension_to_format(((uC/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_utils.pyutest_extension_to_format sutest_extension_to_formatcCs*ttddttdddS(NuPNGu.pnguICOu.ico(ueq_uformat_to_extension(((uC/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_utils.pyu test_format_to_extension_no_initsu test_format_to_extension_no_initcCstddS(NuTXT(uformat_to_extension(((uC/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_utils.pyutest_unknown_formatsutest_unknown_formatcCstddS(Nu.txt(uextension_to_format(((uC/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_utils.pyutest_unknown_extensionsutest_unknown_extensioncCsttdddS(u] Ensure default extensions are honored. Since PIL's ``Image.EXTENSION`` lists ``'.jpe'`` before the more common JPEG extensions, it would normally be the extension we'd get for that format. ``pilkit.utils.DEFAULT_EXTENSIONS`` is our way of specifying which extensions we'd prefer, and this tests to make sure it's working. uJPEGu.jpgN(ueq_uformat_to_extension(((uC/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_utils.pyutest_default_extensions utest_default_extensioncCs-Gdddt}t|jdS(NcBs |EeZdZddZdS(utest_filewrapper..KcSs tdS(N(uUnsupportedOperation(uself((uC/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_utils.pyufileno0su"test_filewrapper..K.filenoN(u__name__u __module__u __qualname__ufileno(u __locals__((uC/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_utils.pyuK/suK(uobjectu FileWrapperufileno(uK((uC/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_utils.pyutest_filewrapper,sutest_filewrappercCs3t}t}t||jd|jdS(ur Test that ``save_image`` accepts filename strings (not just file objects). This is a test for GH-8. uJPEGN(u create_imageuNamedTemporaryFileu save_imageunameuclose(uimuoutfile((uC/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_utils.pyutest_save_with_filename6s  utest_save_with_filenamecCs3tjdd}tdt|ddkdS(u Make sure formats are normalized by ``prepare_image()``. See https://github.com/matthewwithanm/django-imagekit/issues/262 uRGBAidu transparencyugIFiN(idid(uImageunewuok_u prepare_image(uim((uC/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_utils.pyutest_format_normalizationBsutest_format_normalizationN(uiouUnsupportedOperationupilkit.exceptionsu UnknownFormatuUnknownExtensionu pilkit.libuImageu pilkit.utilsuextension_to_formatuformat_to_extensionu FileWrapperu save_imageu prepare_imageu nose.toolsueq_uraisesuok_utempfileuNamedTemporaryFileuutilsu create_imageutest_extension_to_formatu test_format_to_extension_no_initutest_unknown_formatutest_unknown_extensionutest_default_extensionuAttributeErrorutest_filewrapperutest_save_with_filenameutest_format_normalization(((uC/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_utils.pyus(    pilkit-1.1.13/tests/__pycache__/utils.cpython-32.pyc0000644000076700000240000000165612175071025022154 0ustar mjtstaff00000000000000l :Qc@s2ddlZddlmZdZdZdS(iN(uImagecCs7tjjt}tjj|dd}t|dS(u See also: http://en.wikipedia.org/wiki/Lenna http://sipi.usc.edu/database/database.php?volume=misc&image=12 uassetsu lenna.pngur+b(uosupathudirnameu__file__ujoinuopen(udirupath((u>/Users/mjt/Code/projects/django-imagekit/pilkit/tests/utils.pyuget_image_filescCstjtS(N(uImageuopenuget_image_file(((u>/Users/mjt/Code/projects/django-imagekit/pilkit/tests/utils.pyu create_images(uosu pilkit.libuImageuget_image_fileu create_image(((u>/Users/mjt/Code/projects/django-imagekit/pilkit/tests/utils.pyus  pilkit-1.1.13/tests/__pycache__/utils.cpython-33.pyc0000644000076700000240000000173412175067460022162 0ustar mjtstaff00000000000000 :Q|c@s8ddlZddlmZddZddZdS(iN(uImagecCs7tjjt}tjj|dd}t|dS(u See also: http://en.wikipedia.org/wiki/Lenna http://sipi.usc.edu/database/database.php?volume=misc&image=12 uassetsu lenna.pngur+b(uosupathudirnameu__file__ujoinuopen(udirupath((u>/Users/mjt/Code/projects/django-imagekit/pilkit/tests/utils.pyuget_image_filesuget_image_filecCstjtS(N(uImageuopenuget_image_file(((u>/Users/mjt/Code/projects/django-imagekit/pilkit/tests/utils.pyu create_imagesu create_image(uosu pilkit.libuImageuget_image_fileu create_image(((u>/Users/mjt/Code/projects/django-imagekit/pilkit/tests/utils.pyus  pilkit-1.1.13/tests/assets/0000755000076700000240000000000012562721725015465 5ustar mjtstaff00000000000000pilkit-1.1.13/tests/assets/cat.gif0000644000076700000240000006514012412017247016720 0ustar mjtstaff00000000000000GIF89add333fff! NETSCAPE2.0! ,dd H  *\ȰCJx0!ŋ"cE n 2"ɓ Ȗ$X L51"gNR%OD pЖ 8TԧөH`JʴBdYn9@o ŚԻ[֬ҽ& p pa]"$l.R3R@䭌5/e{y Z4[[7~tAbм 0j6nk&-@amg͝y/EJ9 _xfq㹃/\}}rf=7G7b'`Di"piـ~ h]h@X ҆ItaOvʱ|0pՕtݵJ72(F65)g4y_N!dT\F$Hz|'feo2yf[e.`[Vie}Rq/ْp*6wxd< (D%JVfFubxFeqI瓕g'x驜e*]ꬒ"YXړkנz"buw+䠈6{'WiFhhj>ZviB&e,bK\WY ."zPyG^{^rr۟Ljū&IQp,&Ơ c9\iE(򓠥cȧbT*l3 ]P+|3ʗyr^5\drġT5,cLGZ4gmAvsX^lʄ\닗X6Gjv^VAUîvG7oruu'u֞TPmPU2=ogXZqזzqM}oծq nڪV_[e6"\JwsAkZ--rQF9ެޓG 67};rU]8Q NK{ԒM 'h#W겪n5Gb^aPUp尃^5?Ra]QEU,ݬ>LO2MVȆ)U4Dqr|r yM]-v{OJƢXXL [sziUV{ q)Sqe%bZayg؞ɕE(fbrӢw]qBIVv$*Z,ZB^JbɛZOb^glhYy,N{ⴘtY5Wb'Y~jl%c:^֭euUny^nk|6 n%)׭Ե&1vc:|kVw)f8V]35 b; J,3T@j;_EEB)W[M!W)z2g3N\Ygm ^^V_PurPD&Ym\Ln"V#gCUH*Պզ(%Zɬ 16|SxcBJЂ.IQҕ Ϧ`8ޏNQXV<0m%]!#OZkעصJ3UN_S2WgfژZX{-M9WM.SR^6C}3MHkm"7JdQn8}\ڑW;$bΫ%smV99K4}E5f};R4NK.o`! ,dd H  *\ȰCJx0!ŋ"cE n 2"ɓ Ȗ$X J51"@3Lt'Ρ lQhKE*RSMh h`FAdYn9@o z5%[x׫YhZaW0\+N{6@ߍkTZo~ԲT+5щMk}8Xԩ^ f+E.@(w7|siϝzk*<:g-jfp/:+֯|zهT{\wXqytwLuQVrwk@ 8dea"w_+UMP@]vbs hٌ>՘Jgu%yVjٛvFy!mAbrQQuV2xLn dUo2}&g[ eeǦ]i%gd'іT8a5砀[dy_S]^k8&YV`Fִ]]n.נj$Jj^eEdxzuuҕeIqŊ[i)~m젠p&ļ8[:oqK(H@/Pku>('\Fmܾ'FwnbT_3FvF&\Twrm'6V]RvZFm BZѐY"mxZ *s%Vw㝭{KءLq~*mܡK{W_큫[+%c OwEVf9 cPAmc-k١.;T Rwt"<+)N-E 3cύ.qEɐdXE1ٖjԢ'XRDL$BeG ΒΩȄ%=!5讶O>t Я-j8!xiP.*<]ޱ`=*dZS,MjJhώfO :EI4X1 6 ֨9ӬdeH׭Xᳳr;cՐ8l >zo^+-mUX_JV{R$nV2zV\D_28meٟ$6QOe6&% oz9UW#Nsƕb`Λ ˔[. ͫWO&}on)_q0Kx~9/$ ! d,dd H  *\ȰCJx0!ŋ"cE n 2"ɓ Ȗ$X L51"gNR%OD pЖ 8TԧөH`JʴBdYn9@o ŚԻ[֬ҽ& p pa]"$l.R3R@䭌5/e{y Z4[[7~tAbм 0j6nk&-@amg͝y/EJ9 _xfq㹃/\}}rf=7G7b'`Di"piـ~ h]h@X ҆ItaOvʱ|0pՕtݵJ72(F65)g4y_N!dT\F$Hz|'feo2yf[e.`[Vie}Rq/ْp*6wxd< (D%JVfFubxFeqI瓕g'x驜e*]ꬒ"YXړkנz"buw+䠈6{'WiFhhj>ZviB&e,bK\WY ."zPyG^{^rr۟Ljū&IQp,&Ơ c9\iE(򓠥cȧbT*l3 ]P+|3ʗyr^5\drġT5,cLGZ4gmAvsX^lʄ\닗X6Gjv^VAUîvG7oruu'u֞TPmPU2=ogXZqזzqM}oծq nڪV_[e6"\JwsAkZ--rQF9ެޓG 67};rU]8Q NK{ԒM 'h#W겪n5Gb^aPUp尃^5?Ra]QEU,ݬ>LO2MVȆ)U4Dqr|r yM]-!>LĂ1)``eDVIv<gm5w.I`՝2Fqg@T٨1l. ^8j[\Wv79J@UNZBF\(*ęR1ehť'FyZY$rlS#ְ>(ѐtY+YTǤ XceSaPHԗ!(^lɲ>U&)+3CX!^+ȻlҮO.BzzsL<izD99E 2BQ9UP"KHEm qlY7YԹQ{WULf eAy[KmlDL?abmh`bьbVzl\ wyqS\PXmZviB&e,bK\WY ."zPyG^{^rr۟Ljū&IQp,&Ơ c9\iE(򓠥cȧbT*l3 ]P+|3ʗyr^5\drġT5,cLGZ4gmAvsX^lʄ\닗X6Gjv^VAUîvG7oruu'u֞TPmPU2=ogXZqזzqM}oծq nڪV_[e6"\JwsAkZ--rQF9ެޓG 67};rU]8Q NK{ԒM 'h#W겪n5Gb^aPUp尃^5?Ra]QEU,ݬ>LO2MVȆ)U4Dqr|r yM]-="#d:5˅֖kG#[ W{W?Eu*D՝rfZ{&SBPBItU6Q%o[75xfy^J$7{\ZZUkd&*qZ wn:`)C&9)f,}ק+g oF4 /?lfd{د04kK%Z lZRYv䇼g$yq_Ejj_W(#*O1V34.Wi P1my si`K$Wօ3%rOyt`U*$$UuMPNNh$qPTpi'mgDz;/K4%piL;q*+L?c9AT2jĴ\.s9/J$@^g ɱBT*vce1ʪx"JҔlgD'DB&4pM4j,;"vH,rpʐ,I͊KhD0'ɴ;QI5T G`R+g2D#' ѤBPZN5$xϝ1*X-2(IcVQEx8(שvfN߃*PsG;9У᯦:AldřJnBc_ "k2m&nFm$nV'tM!lH6" ,FR10XHo)u q2fIlD\lkEFmucrҒD ! ,dd H  *\ȰCJx0!ŋ"cE n 2"ɓ Ȗ$X L51"gNR%OD pЖ 8TԧөH`JʴBdYn9@o ŚԻ[֬ҽ& p pa]"$l.R3R@䭌5/e{y Z4[[7~tAbм 0j6nk&-@amg͝y/EJ9 _xfq㹃/\}}rf=7G7b'`Di"piـ~ h]h@X ҆ItaOvʱ|0pՕtݵJ72(F65)g4y_N!dT\F$Hz|'feo2yf[e.`[Vie}Rq/ْp*6wxd< (D%JVfFubxFeqI瓕g'x驜e*]ꬒ"YXړkנz"buw+䠈6{'WiFhhj>ZviB&e,bK\WY ."zPyG^{^rr۟Ljū&IQp,&Ơ c9\iE(򓠥cȧbT*l3 ]P+|3ʗyr^5\drġT5,cLGZ4gmAvsX^lʄ\닗X6Gjv^VAUîvG7oruu'u֞TPmPU2=ogXZqזzqM}oծq nڪV_[e6"\JwsAkZ--rQF9ެޓG 67};rU]8Q NK{ԒM 'h#W겪n5Gb^aPUp尃^5?Ra]QEU,ݬ>LO2MVȆ)U4Dqr|r yM]-v{OJƢXXL [sziUV{ q)Sqe%bZayg؞ɕE(fbrӢw]qBIVv$*Z,ZB^JbɛZOb^glhYy,N{ⴘtY5Wb'Y~jl%c:^֭euUny^nk|6 n%)׭Ե&1vc:|kVw)f8V]35 b; J,3T@j;_EEB)W[M!W)z2g3N\Ygm ^^V_PurPD&Ym\Ln"V#gCUH*Պզ(%Zɬ 16|SxcBJЂ.IQҕ Ϧ`8ޏNQXV<0m%]!#OZkעصJ3UN_S2WgfژZX{-M9WM.SR^6C}3MHkm"7JdQn8}\ڑW;$bΫ%smV99K4}E5f};R4NK.o`! ,dd H  *\ȰCJx0!ŋ"cE n 2"ɓ Ȗ$X J51"@3Lt'Ρ lQhKE*RSMh h`FAdYn9@o z5%[x׫YhZaW0\+N{6@ߍkTZo~ԲT+5щMk}8Xԩ^ f+E.@(w7|siϝzk*<:g-jfp/:+֯|zهT{\wXqytwLuQVrwk@ 8dea"w_+UMP@]vbs hٌ>՘Jgu%yVjٛvFy!mAbrQQuV2xLn dUo2}&g[ eeǦ]i%gd'іT8a5砀[dy_S]^k8&YV`Fִ]]n.נj$Jj^eEdxzuuҕeIqŊ[i)~m젠p&ļ8[:oqK(H@/Pku>('\Fmܾ'FwnbT_3FvF&\Twrm'6V]RvZFm BZѐY"mxZ *s%Vw㝭{KءLq~*mܡK{W_큫[+%c OwEVf9 cPAmc-k١.;T Rwt"<+)N-E 3cύ.qEɐdXE1ٖjԢ'XRDL$BeG ΒΩȄ%=!5讶O>t Я-j8!xiP.*<]ޱ`=*dZS,MjJhώfO :EI4X1 6 ֨9ӬdeH׭Xᳳr;cՐ8l >zo^+-mUX_JV{R$nV2zV\D_28meٟ$6QOe6&% oz9UW#Nsƕb`Λ ˔[. ͫWO&}on)_q0Kx~9/$ ! ,dd H  *\ȰCJx0!ŋ"cE n 2"ɓ Ȗ$X J51"@3Lt'Ρ lQhKE*RSMh h`FAdYn9@o z5%[x׫YhZaW0\+k6эkTZo~4^>5щWk}8Xԩ43mͶW]@Qܹ59yE<]Kwut=s _;W+}o٧y퇐wpwWu;1l;Umv-^ µ!47׃ɥx 2q}bW%a7R`(YS"wgM&b*hXg[i%g%7Q朊zCz'gٹg\E_dUdi*ueFP`aפ)8(Yx7@>U(ya)k%Obeta)Tw:xѦgլf^2{jTu4&`f1YYjZbPnbf›ONtܮqVFݸVH,~ lWmTz /PmF\ Īhqʔ(ŭEr+[) o̥ JDMQra|j?bi8FW]TtFZaV<$&v9 mie=^VZҩEr;Ze3#Ε oJ-F+dDSqo~ ̑X[[zMYޘ'm~Zؕ`]>/%khS"OH2PQeS &ʘq5XY5]Kڪ[ziq5q_'7t0L>i[y8J~qhW My$bieqXg6P&6I\&4۶ƵKy 2E?S[װsHMV^ڢ2$-r {ă;hgB6 -Z?b urEj(W^v' mh#e<&a!Y{y%/ `Z͗XXEIWtMlc nIκUSeL;[ɬfq >Z$%uZO (ϣ1f5An|%OxкmsR/BpR 1Cυ3ڗ5T&e4! XNXbE'DrVeʨJSd@c&q41V!q <t)24:M[!ԒT @];Y)P=t.4ZZ֍eA:WFF0q]̱X:ԫjUhE¿ PUL)+ւr1,4ZU#l)7a hµFa}oGr)amDN5ҡߤXvkݖ@6ԓ'F Ӗ?Ym/ʷ$y g7f>$1kHbi!XK! ,dd H  *\ȰCJx0!ŋ"cE n 2"ɓ Ȗ$X J51"@3Lt'Ρ lQhKE*RSMh h`FAdYn9@o z5%[x׫YhZaW0\+k6эkTZo~4^>5щWk}8Xԩ43mͶW]@Qܹ59yE<]Kwut=s _;W+}o٧y퇐wpwW} qjUm;v2^ µ!7׃Ec ߋ!eٌgUnufczb/VdS"wgQԌ($R"V2x28TBnYdT97dY.g$XZWkzRmgOEءnUETA(YZV_Q-vfWRjnouhMbGkQ*st}SS_e*vo];֕Qv[ #JN] Z[ٗ~{Zɚ6|e,`mRa^箷xi{]='yѺߢo6)|׬{*r!nJ\sхe/dIװ2Yv2@-ܴn_=hU[AG T+|* ةi5-]U)cW?L`T+ɦ?FuPUDb^xkMVGW 7@`y؟?7{qNک5$Bm )5'\lS9Ydvy[=Ý'Bo92%V;}q'\kTPY_D&/: 2,Nj\SWBqPV|fa7h!ZN%s[LTn~{ZG@ѯnQbv֝yWڨUn ZSppvSJ-4,= p#{\EAݒ˜J gDOh)dK5j'5Ңխ*h:-*v*5E .Әsu*ĚUe$'(*ΞR}ev҅/g'X|t9jG,[LN !WqV'Un$&}M:y&7/)M&EfK("/f{cBVw%ߧ[ " <3$ ! ,dd H  *\ȰCJx0!ŋ"cE n 2"ɓ Ȗ$X J51"@3Lt'Ρ lQhKE*RSMh h`FAdYn9@o z5%[x׫YhZaW0\+k6эkTZo~4^>5щWk}8Xԩ43mͶW]@Qܹ59<]Kwut+cgj٪oou+o>AW!wp}gWu;1l;UmvS|pYhmz0ք \45cؕ}4Ɓ(Dcg8w|5wgBěb*hXg[i%\G4dT9Jg`i^Ie~Ŧda=ybg\\d99bcb"Rjd|nouw%[15ddqdwꮼ ^SܛkYKAET"۫.*TC9Un:i؎zPyay>1b«lB//{qp+{ښ\{>*+Z>՚ϩ)2kt]\!m`8,iZ(c{fc:UT7#@b>lڠ<,\T7VE$]=ӝ39?ZAǻR216Wcƕ\,/{H3X3cU@sPĖw* qmqO3F`l 2OƼY@Pm^D]ZZ{zhCJ}[,֘E+3":$s yϙs]dmQܮW͞}9!~ |p>rɏkYnm4sP|~.s=dQ`_D6%*3Ym#7WZ1p!|8"Y8fzWZȅYn4pS?:1K]v YZԆ;(ڬs|V5\*SW&]|zW&ɤQSس)]luI=]\ IЇ]ȒE>RiyNLV%DLV/;Kf~8ˉpb$DGLVuz$'k-mO]se49O]z.f3R®"3teW*MҦyͮ9 ʯ֔51.?zy&LJE=,U[x"D3sB7i/rYW3g5ݖMS&C"J"o3[6sIPjr'&I"S(7Q,ek,P 'ʋׄ@P1h9u6jFwQ_J ҳ4&I'PS)kAe:OWԩ=էG3Ԥ597ԣjLRUM|ZV6˯C-k6Ѥ`&<_ft5jbhXrE܀[DEC(YΚB\-,:ӳxWMIl7)Yj3CIDvkvgnK[2gTM:\fdXΚ%دh'nly7Nvw$ ߘ[֭o|?&.+crۇKF qa! ,dd H  *\ȰCJx0!ŋ"cE n 2"ɓ Ȗ$X J51"@3Lt 'Ρ lQhKE*RSMh h`FAdYn9@o z5%[x׫YhZaW0\+k6эk4޹o~/׿I=`Īvxi_U:{s{ P6nN>~09s (EM?~x%yÞW4yz߿MO},`{iWFcǟ6zTr`Yw fZ5h]'!B!·!s-ۊXysTj*}yą]F&f|7ATieZg;ȗb*%i؄[i%d\P^&_1V`Qgdai搬QV>U{9yҝor]eJfULIנd eNI*{jIu+r!+zjPkn)Jtd1Ր*yz*V{ZLN f^4k.JVʫޜ2yﮌV}9pY/iZn ջJE$|:nlﶺhc,$wO;) /JLDdVdQ9*tɝY"*v3Pu,Ļԣ2'ȉ-o8}ldьmWkMin:獪TT"%*>TmxP9aV"2~TzMla8Bn&^{m[LZ jhEbύlrvf(dgUfsAϺ*3fJ\}?rqYU]"5bbi>a޻u*sgf=#JCB# 2[ qŚW Q7ʬz ?N9 bfAA@ꃣS; eBjĒOt,`yެ$O50jSJh&DŃUWnu\'oͅlKhc䪹ElI _ C5e9ɉOL2,[/ۙ 0 c@Z'`?#'(eMU6iM$:V2,/}Qdf0͠3Kť$ZY3А;jCiQXVQ2oS¤ g|1hlmzTqJՌf* ƌΈ)&G3 Os*VddWh 2vYic:!iU'cZXfX_3Ӳ JHDX]e1Sg˭n#QXgcZ* ZD tsTeMuCas ^75b. f$ ! ,dd H  *\ȰCJx0!ŋ"cE n 2"ɓ Ȗ$X J51"@3Lt 'Ρ lQhKE*RSMh h`FAdYn9@o z5%[x׫YhZaW0\+k6эk4޹o~/׿I=`Īvxi_U:{s{ P6nN>^3s (EM?~x%yÞW<\ߦ̯o0|ŕ~!{߁EJ-NEU`{yR]CYP|pyV ¥aXy(!"']Wg 0\+qb GFyeܐ2bFe(\PAWmbhX[i%b)XHLAFszuVVd٘Yziibf\XdyYɝZZt j{uVftnWx"tWjTQSDg٭ lNU’([ʦV4j]>K"է߾Jjæk]-kLت+/{.U{) prcr1.ܰRi_ڤ5P!{核+m%piyrjWq[Nkf`1A&AgةiVơ)lA&^+k2)h\Ó$u+︤AvP؜qP/nV)sUjqY(M@fՃz.lIȚJYhfiSX&qA\i<^^tWM;iM.J*dbʵz-ᦂ}^@:C!n:N:ĵ3q;.z̟Emj˗fgjiX/ww \hB&GckKbM9#XT@F.C#a\ASIs BZ^K+/*6c uoZ_dVOvZ*ljN%s̀+KJ}bשD9-SBcA#ZFE,J:D"XnN#V㰈u ǢH5]}BV1O$Hig)HG6DcLW*Y>-H R$$STՙlFXxGOfReSWV'z3dIIRfR/ nɚ|uU<#ˉuN 8mQ̋0Im3*z%[b|9m&d=ii̪2]0ܬ ȦLL/s͕ ӑX#c Qf|(0"LIY~,K=&8:YLL)NiKzդGRk('5-J@uCdIhj4v5S`1LTi*QJPud'u7BM&XR?8͆u$  ɱt= ]&Q?))י~k/9 .\R^"l.J׹SDqC ! ,dd H  *\ȰCJx0!ŋ"cE n 2"ɓ Ȗ$X J51"@3Lt 'Ρ lQhKE*RSMh h`FAdYn9@o z5%[x׫YhZaW0\+k6эk4޹o~/׿I=`Īvxi_U:{s{ P6nN>^3s (EM?~x%yÞW<\ߦ̯o0|ŕ~!{߁EJ-NEU`{yR]CYP|pyV ¥aXy(!"']Wg 0\+qb GFyeܐ2bFe(\PAWmbhX[i%b)XHLAFszuVVd٘Yziibf\XdyYɝZZt j{uVftnWx"tWjTQSDg٭ lNU’([ʦV4j]>K"է߾Jjæk]-kLت+/*F*/[z^q{())[wkd[mk饷yIUipIvei~KW- KL4,X&/]XigS>wq*YLhKuD>Yf9<];֨j3 .;_K83T% r(XW@?}, iSHT3E7ЂW O(jG Z$*jI O0꒴xFN9ZvEyk;Y.satkyIcd e=vpA[՜)7&_YƳ?"15H.KF<&ԛvVU$+DյTe/-/ËȢijrd I.3.Bi/y/ʒ)YZTRFq.L^{Jw-VU kK^;pilkit-1.1.13/tests/test_processors.py0000644000076700000240000001105412412017247017766 0ustar mjtstaff00000000000000from pilkit.lib import Image, ImageDraw from pilkit.processors import (Resize, ResizeToFill, ResizeToFit, SmartCrop, SmartResize, MakeOpaque) from nose.tools import eq_, assert_true import os from pilkit.processors.resize import Thumbnail from .utils import create_image import mock def test_smartcrop(): img = SmartCrop(100, 100).process(create_image()) eq_(img.size, (100, 100)) def test_resizetofill(): img = ResizeToFill(100, 100).process(create_image()) eq_(img.size, (100, 100)) def test_resizetofit(): # First create an image with aspect ratio 2:1... img = Image.new('RGB', (200, 100)) # ...then resize it to fit within a 100x100 canvas. img = ResizeToFit(100, 100).process(img) # Assert that the image has maintained the aspect ratio. eq_(img.size, (100, 50)) def test_resize_rounding(): """ Regression test for matthewwithanm/pilkit#1 """ img = Image.new('RGB', (95, 95)) img = ResizeToFill(28, 28).process(img) eq_(img.size, (28, 28)) def test_resizetofit_mat(): img = Image.new('RGB', (200, 100)) img = ResizeToFit(100, 100, mat_color=0x000000).process(img) eq_(img.size, (100, 100)) def test_resize_antialiasing(): """ Test that the Resize processor antialiases. The Resize processor is used by all of the Resize* variants, so this should cover all of resize processors. Basically, this is to test that it converts to RGBA mode before resizing. Related: jdriscoll/django-imagekit#192 """ # Create a palette image and draw a circle into it. img = Image.new('P', (500, 500), 1) img.putpalette([ 0, 0, 0, 255, 255, 255, 0, 0, 255, ]) d = ImageDraw.ImageDraw(img) d.ellipse((100, 100, 400, 400), fill=2) # Resize the image using the Resize processor img = Resize(100, 100).process(img) # Count the number of colors color_count = len(list(filter(None, img.histogram()))) assert_true(color_count > 2) def test_upscale(): """ Test that the upscale argument works as expected. """ img = Image.new('RGB', (100, 100)) for P in [Resize, ResizeToFit, ResizeToFill, SmartResize]: img2 = P(500, 500, upscale=True).process(img) eq_(img2.size, (500, 500)) img2 = P(500, 500, upscale=False).process(img) eq_(img2.size, (100, 100)) def test_should_raise_exception_if_anchor_is_passed_and_crop_is_set_to_false(): try: Thumbnail(height=200, width=200, upscale=False, crop=False, anchor='t') except Exception as e: eq_(str(e), "You can't specify an anchor point if crop is False.") def test_should_set_crop_to_true_if_anchor_is_passed_without_crop(): thumb = Thumbnail(height=200, width=200, upscale=False, anchor='t') assert_true(thumb.crop) def test_should_raise_exception_when_crop_is_passed_without_height_and_width(): img = Image.new('RGB', (100, 100)) try: Thumbnail(crop=True).process(img) except Exception as e: eq_(str(e), 'You must provide both a width and height when cropping.') @mock.patch('pilkit.processors.resize.SmartResize') def test_should_call_smartresize_when_crop_not_passed(my_mock): img = Image.new('RGB', (100, 100)) Thumbnail(height=200, width=200, upscale=False).process(img) assert_true(my_mock.called) @mock.patch('pilkit.processors.resize.SmartResize') def test_should_repass_upscale_option_true(my_mock): img = Image.new('RGB', (100, 100)) Thumbnail(height=200, width=200, upscale=True).process(img) my_mock.assert_called_once_with(width=200, upscale=True, height=200) @mock.patch('pilkit.processors.resize.SmartResize') def test_should_repass_upscale_option_false(my_mock): img = Image.new('RGB', (100, 100)) Thumbnail(height=200, width=200, upscale=False).process(img) my_mock.assert_called_once_with(width=200, upscale=False, height=200) @mock.patch('pilkit.processors.resize.ResizeToFill') def test_should_call_resizetofill_when_crop_and_ancho_is_passed(my_mock): img = Image.new('RGB', (100, 100)) Thumbnail(height=200, width=200, anchor='fake').process(img) assert_true(my_mock.called) @mock.patch('pilkit.processors.resize.ResizeToFit') def test_should_call_resizetofit_when_crop_is_not_passed(my_mock): img = Image.new('RGB', (100, 100)) Thumbnail(height=200, width=200, crop=False).process(img) assert_true(my_mock.called) def test_make_gifs_opaque(): dir = os.path.dirname(__file__) path = os.path.join(dir, 'assets', 'cat.gif') gif = Image.open(path) MakeOpaque().process(gif) pilkit-1.1.13/tests/test_processors.pyc0000644000076700000240000001650712411621441020135 0ustar mjtstaff00000000000000 #'Tc@sqddlmZmZddlmZmZmZmZmZm Z ddl m Z m Z ddl Z ddlmZddlmZddlZdZd Zd Zd Zd Zd ZdZdZdZdZejddZejddZejddZ ejddZ!ejddZ"dZ#dS(i(tImaget ImageDraw(tResizet ResizeToFillt ResizeToFitt SmartCropt SmartResizet MakeOpaque(teq_t assert_trueN(t Thumbnaili(t create_imagecCs/tddjt}t|jddS(Nid(idid(RtprocessR Rtsize(timg((sH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyttest_smartcrop scCs/tddjt}t|jddS(Nid(idid(RR R RR (R((sH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyttest_resizetofillscCs>tjdd}tddj|}t|jddS(NtRGBiidi2(iid(idi2(RtnewRR RR (R((sH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyttest_resizetofitscCs>tjdd}tddj|}t|jddS(s5 Regression test for matthewwithanm/pilkit#1 Ri_iN(i_i_(ii(RRRR RR (R((sH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyttest_resize_rounding scCsDtjdd}tddddj|}t|jddS(NRiidt mat_colori(iid(idid(RRRR RR (R((sH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyttest_resizetofit_mat*sc Cstjdd d}|jdddddddddg tj|}|jd dd tddj|}ttt d |j }t |d kd S( s% Test that the Resize processor antialiases. The Resize processor is used by all of the Resize* variants, so this should cover all of resize processors. Basically, this is to test that it converts to RGBA mode before resizing. Related: jdriscoll/django-imagekit#192 tPiiiiiditfilliN(ii(ididii( RRt putpaletteRtellipseRR tlentlisttfiltertNonet histogramR (Rtdt color_count((sH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyttest_resize_antialiasing0s   !cCstjdd}xvttttgD]b}|dddtj|}t|j d|dddt j|}t|j dq%WdS( s< Test that the upscale argument works as expected. RiditupscaleN(idid(ii(idid( RRRRRRtTrueR RR tFalse(RRtimg2((sH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyt test_upscaleNs c CsVy)tdddddtdtddWn&tk rQ}tt|dnXdS( NtheightitwidthR#tcroptanchortts3You can't specify an anchor point if crop is False.(R R%t ExceptionRtstr(te((sH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pytHtest_should_raise_exception_if_anchor_is_passed_and_crop_is_set_to_false^s)c Cs2tdddddtdd}t|jdS(NR(iR)R#R+R,(R R%R R*(tthumb((sH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyt=test_should_set_crop_to_true_if_anchor_is_passed_without_cropes!cCsYtjdd}ytdtj|Wn&tk rT}tt|dnXdS(NRidR*s7You must provide both a width and height when cropping.(idid(RRR R$R R-RR.(RR/((sH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pytHtest_should_raise_exception_when_crop_is_passed_without_height_and_widthjs s$pilkit.processors.resize.SmartResizecCsEtjdd}tdddddtj|t|jdS(NRidR(iR)R#(idid(RRR R%R R tcalled(tmy_mockR((sH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyt1test_should_call_smartresize_when_crop_not_passedrs"cCsTtjdd}tdddddtj||jdddtdddS(NRidR(iR)R#(idid(RRR R$R tassert_called_once_with(R5R((sH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyt&test_should_repass_upscale_option_trueys"cCsTtjdd}tdddddtj||jdddtdddS(NRidR(iR)R#(idid(RRR R%R R7(R5R((sH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyt'test_should_repass_upscale_option_falses"s%pilkit.processors.resize.ResizeToFillcCsEtjdd}tddddddj|t|jdS( NRidR(iR)R+tfake(idid(RRR R R R4(R5R((sH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyt;test_should_call_resizetofill_when_crop_and_ancho_is_passeds"s$pilkit.processors.resize.ResizeToFitcCsEtjdd}tdddddtj|t|jdS(NRidR(iR)R*(idid(RRR R%R R R4(R5R((sH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyt4test_should_call_resizetofit_when_crop_is_not_passeds"cCsMtjjt}tjj|dd}tj|}tj|dS(Ntassetsscat.gif( tostpathtdirnamet__file__tjoinRtopenRR (tdirR?tgif((sH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyttest_make_gifs_opaques($t pilkit.libRRtpilkit.processorsRRRRRRt nose.toolsRR R>tpilkit.processors.resizeR tutilsR tmockRRRRRR"R'R0R2R3tpatchR6R8R9R;R<RF(((sH/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_processors.pyts,.          pilkit-1.1.13/tests/test_utils.py0000644000076700000240000000440012412017267016723 0ustar mjtstaff00000000000000import os from io import UnsupportedOperation from pilkit.exceptions import UnknownFormat, UnknownExtension from pilkit.lib import Image from pilkit.utils import (extension_to_format, format_to_extension, FileWrapper, save_image, prepare_image, quiet) from mock import Mock, patch from nose.tools import eq_, raises, ok_ from tempfile import NamedTemporaryFile from .utils import create_image def test_extension_to_format(): eq_(extension_to_format('.jpeg'), 'JPEG') eq_(extension_to_format('.rgba'), 'SGI') def test_format_to_extension_no_init(): eq_(format_to_extension('PNG'), '.png') eq_(format_to_extension('ICO'), '.ico') @raises(UnknownFormat) def test_unknown_format(): format_to_extension('TXT') @raises(UnknownExtension) def test_unknown_extension(): extension_to_format('.txt') def test_default_extension(): """ Ensure default extensions are honored. Since PIL's ``Image.EXTENSION`` lists ``'.jpe'`` before the more common JPEG extensions, it would normally be the extension we'd get for that format. ``pilkit.utils.DEFAULT_EXTENSIONS`` is our way of specifying which extensions we'd prefer, and this tests to make sure it's working. """ eq_(format_to_extension('JPEG'), '.jpg') @raises(AttributeError) def test_filewrapper(): class K(object): def fileno(self): raise UnsupportedOperation FileWrapper(K()).fileno() def test_save_with_filename(): """ Test that ``save_image`` accepts filename strings (not just file objects). This is a test for GH-8. """ im = create_image() outfile = NamedTemporaryFile() save_image(im, outfile.name, 'JPEG') outfile.close() def test_format_normalization(): """ Make sure formats are normalized by ``prepare_image()``. See https://github.com/matthewwithanm/django-imagekit/issues/262 """ im = Image.new('RGBA', (100, 100)) ok_('transparency' in prepare_image(im, 'gIF')[1]) def test_quiet(): """ Make sure the ``quiet`` util doesn't error if devnull is unwriteable. See https://github.com/matthewwithanm/django-imagekit/issues/294 """ mocked = Mock(side_effect=OSError) with patch.object(os, 'open', mocked): with quiet(): pass pilkit-1.1.13/tests/test_utils.pyc0000644000076700000240000000733512411621441017072 0ustar mjtstaff00000000000000 !'Tc@s ddlmZddlmZmZddlmZddlmZm Z m Z m Z m Z ddl mZmZmZddlmZddlmZd Zd Zeed Zeed Zd ZeedZdZdZdS(i(tUnsupportedOperation(t UnknownFormattUnknownExtension(tImage(textension_to_formattformat_to_extensiont FileWrappert save_imaget prepare_image(teq_traisestok_(tNamedTemporaryFilei(t create_imagecCs*ttddttdddS(Ns.jpegtJPEGs.rgbatSGI(R R(((sC/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_utils.pyttest_extension_to_format scCs*ttddttdddS(NtPNGs.pngtICOs.ico(R R(((sC/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_utils.pyt test_format_to_extension_no_initscCstddS(NtTXT(R(((sC/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_utils.pyttest_unknown_formatscCstddS(Ns.txt(R(((sC/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_utils.pyttest_unknown_extensionscCsttdddS(s] Ensure default extensions are honored. Since PIL's ``Image.EXTENSION`` lists ``'.jpe'`` before the more common JPEG extensions, it would normally be the extension we'd get for that format. ``pilkit.utils.DEFAULT_EXTENSIONS`` is our way of specifying which extensions we'd prefer, and this tests to make sure it's working. Rs.jpgN(R R(((sC/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_utils.pyttest_default_extensions cCs-dtfdY}t|jdS(NtKcBseZdZRS(cSs tdS(N(R(tself((sC/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_utils.pytfileno0s(t__name__t __module__R(((sC/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_utils.pyR/s(tobjectRR(R((sC/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_utils.pyttest_filewrapper,scCs3t}t}t||jd|jdS(sr Test that ``save_image`` accepts filename strings (not just file objects). This is a test for GH-8. RN(R R Rtnametclose(timtoutfile((sC/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_utils.pyttest_save_with_filename6s  cCs3tjdd}tdt|ddkdS(s Make sure formats are normalized by ``prepare_image()``. See https://github.com/matthewwithanm/django-imagekit/issues/262 tRGBAidt transparencytgIFiN(idid(RtnewR R(R!((sC/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_utils.pyttest_format_normalizationBsN(tioRtpilkit.exceptionsRRt pilkit.libRt pilkit.utilsRRRRRt nose.toolsR R R ttempfileR tutilsR RRRRRtAttributeErrorRR#R((((sC/Users/mjt/Code/projects/django-imagekit/pilkit/tests/test_utils.pyts(    pilkit-1.1.13/tests/utils.py0000644000076700000240000000057412164413072015672 0ustar mjtstaff00000000000000import os from pilkit.lib import Image def get_image_file(): """ See also: http://en.wikipedia.org/wiki/Lenna http://sipi.usc.edu/database/database.php?volume=misc&image=12 """ dir = os.path.dirname(__file__) path = os.path.join(dir, 'assets', 'lenna.png') return open(path, 'r+b') def create_image(): return Image.open(get_image_file()) pilkit-1.1.13/tests/utils.pyc0000644000076700000240000000154612336653326016046 0ustar mjtstaff00000000000000 :Qc@s2ddlZddlmZdZdZdS(iN(tImagecCs7tjjt}tjj|dd}t|dS(s See also: http://en.wikipedia.org/wiki/Lenna http://sipi.usc.edu/database/database.php?volume=misc&image=12 tassetss lenna.pngsr+b(tostpathtdirnamet__file__tjointopen(tdirR((s>/Users/mjt/Code/projects/django-imagekit/pilkit/tests/utils.pytget_image_filescCstjtS(N(RRR (((s>/Users/mjt/Code/projects/django-imagekit/pilkit/tests/utils.pyt create_images(Rt pilkit.libRR R (((s>/Users/mjt/Code/projects/django-imagekit/pilkit/tests/utils.pyts