Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-pilkit for openSUSE:Factory checked in at 2023-10-06 21:13:59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-pilkit (Old) and /work/SRC/openSUSE:Factory/.python-pilkit.new.28202 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-pilkit" Fri Oct 6 21:13:59 2023 rev:7 rq:1115887 version:3.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-pilkit/python-pilkit.changes 2022-04-06 21:52:52.578618926 +0200 +++ /work/SRC/openSUSE:Factory/.python-pilkit.new.28202/python-pilkit.changes 2023-10-06 21:16:42.872778536 +0200 @@ -1,0 +2,16 @@ +Thu Oct 5 08:36:31 UTC 2023 - Markéta Machová <mmach...@suse.com> + +- Update to 3.0 + * Create Convert processor and GaussianBlur processor + * Updating histogram entropy implementations + * Make processors.Resize more memory-efficient + * Added WebP as a transparency format + * Use pytest instead of nose + * Make it compatible with Pillow10 + * test: use unittest.mock instead of mock +- Drop merged patches: + * switch-to-pytest.patch + * python-pilkit-no-mock.patch + * pil-fix-test.patch + +------------------------------------------------------------------- Old: ---- pil-fix-test.patch pilkit-2.0.tar.gz python-pilkit-no-mock.patch switch-to-pytest.patch New: ---- pilkit-3.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-pilkit.spec ++++++ --- /var/tmp/diff_new_pack.TMneNW/_old 2023-10-06 21:16:44.020820012 +0200 +++ /var/tmp/diff_new_pack.TMneNW/_new 2023-10-06 21:16:44.020820012 +0200 @@ -1,7 +1,7 @@ # # spec file for package python-pilkit # -# Copyright (c) 2022 SUSE LLC +# Copyright (c) 2023 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -16,18 +16,14 @@ # -%{?!python_module:%define python_module() python-%{**} python3-%{**}} +%{?sle15_python_module_pythons} Name: python-pilkit -Version: 2.0 +Version: 3.0 Release: 0 Summary: A collection of utilities and processors for the Python Imaging Libary License: BSD-3-Clause URL: https://github.com/matthewwithanm/pilkit/ Source: https://files.pythonhosted.org/packages/source/p/pilkit/pilkit-%{version}.tar.gz -Patch0: pil-fix-test.patch -Patch1: switch-to-pytest.patch -# https://github.com/matthewwithanm/pilkit/issues/54 -Patch2: python-pilkit-no-mock.patch BuildRequires: %{python_module setuptools} BuildRequires: fdupes BuildRequires: python-rpm-macros @@ -36,6 +32,7 @@ BuildRequires: %{python_module Pillow} BuildRequires: %{python_module pytest} # /SECTION +Requires: python-Pillow %python_subpackages %description @@ -62,5 +59,6 @@ %files %{python_files} %license LICENSE %doc AUTHORS README.rst -%{python_sitelib}/* +%{python_sitelib}/pilkit +%{python_sitelib}/pilkit-%{version}*-info ++++++ pilkit-2.0.tar.gz -> pilkit-3.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pilkit-2.0/PKG-INFO new/pilkit-3.0/PKG-INFO --- old/pilkit-2.0/PKG-INFO 2017-02-17 13:07:49.000000000 +0100 +++ new/pilkit-3.0/PKG-INFO 2023-09-28 00:01:05.112009800 +0200 @@ -1,123 +1,125 @@ -Metadata-Version: 1.1 +Metadata-Version: 2.1 Name: pilkit -Version: 2.0 -Summary: A collection of utilities and processors for the Python Imaging Libary. +Version: 3.0 +Summary: A collection of utilities and processors for the Python Imaging Library. 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 - :target: https://travis-ci.org/matthewwithanm/pilkit - - .. _`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 <https://github.com/matthewwithanm/pilkit/issues>`_ - to report bugs. `A mailing list <https://groups.google.com/forum/#!forum/django-imagekit>`_ - also exists to discuss the project and ask questions, as well as the official - `#imagekit <irc://irc.freenode.net/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 -Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.3 -Classifier: Programming Language :: Python :: 3.4 -Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 Classifier: Topic :: Utilities +License-File: LICENSE +License-File: AUTHORS +Requires-Dist: Pillow>=7.0 + +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://github.com/matthewwithanm/pilkit/workflows/Python%20CI/badge.svg + :target: https://github.com/matthewwithanm/pilkit/actions?query=workflow%3A%22Python+CI%22 + +.. _`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 <https://github.com/matthewwithanm/pilkit/issues>`_ +to report bugs. `A mailing list <https://groups.google.com/forum/#!forum/django-imagekit>`_ +also exists to discuss the project and ask questions, as well as the official +`#imagekit <irc://irc.freenode.net/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 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pilkit-2.0/README.rst new/pilkit-3.0/README.rst --- old/pilkit-2.0/README.rst 2017-02-17 12:45:57.000000000 +0100 +++ new/pilkit-3.0/README.rst 2023-09-26 22:35:02.000000000 +0200 @@ -9,8 +9,8 @@ **For the complete documentation on the latest stable version of PILKit, see** `PILKit on RTD`_. -.. image:: https://api.travis-ci.org/matthewwithanm/pilkit.png - :target: https://travis-ci.org/matthewwithanm/pilkit +.. image:: https://github.com/matthewwithanm/pilkit/workflows/Python%20CI/badge.svg + :target: https://github.com/matthewwithanm/pilkit/actions?query=workflow%3A%22Python+CI%22 .. _`PILKit on RTD`: http://pilkit.readthedocs.org .. _`Instakit`: https://github.com/fish2000/instakit Binary files old/pilkit-2.0/docs/source/_ext/__pycache__/pil.cpython-311.pyc and new/pilkit-3.0/docs/source/_ext/__pycache__/pil.cpython-311.pyc differ Binary files old/pilkit-2.0/docs/source/_ext/original.jpg and new/pilkit-3.0/docs/source/_ext/original.jpg differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pilkit-2.0/docs/source/_ext/pil.py new/pilkit-3.0/docs/source/_ext/pil.py --- old/pilkit-2.0/docs/source/_ext/pil.py 1970-01-01 01:00:00.000000000 +0100 +++ new/pilkit-3.0/docs/source/_ext/pil.py 2023-09-26 22:35:02.000000000 +0200 @@ -0,0 +1,63 @@ +import os, sys, io, base64 +from docutils import nodes +from sphinx.directives.code import CodeBlock + + +def visit_pil(self, node): + pass + + +def depart_pil(self, node): + pass + + +class PILNode(nodes.Structural, nodes.Element): + pass + + +class PILDirective(CodeBlock): + has_content = True + + def run(self): + code_node = CodeBlock.run(self) + nodes.image() + + from PIL import Image + + lib_path = os.path.abspath('..') + working_path = os.path.dirname(os.path.realpath(__file__)) + static_path = os.path.join(working_path, '..', '_static') + + sys.path.append(lib_path) + os.chdir(working_path) + + node = PILNode() + + g = globals() + l = locals() + for line in self.content: + result = exec(line, g, l) + + buffer = io.BytesIO() + new_img = l.get('new_img') + new_img.save(buffer, format='PNG') + + image_node = nodes.image() + image_node['alt'] = 'New Image' + image_node['uri'] = 'data:image/png;base64,' + base64.b64encode(buffer.getvalue()).decode() + + node += code_node + node += image_node + + return [node] + + +def setup(app): + app.add_node(PILNode, html=(visit_pil, depart_pil)) + app.add_directive('pil-block', PILDirective) + + return { + 'version': '0.1', + 'parallel_read_safe': True, + 'parallel_write_safe': True, + } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pilkit-2.0/docs/source/conf.py new/pilkit-3.0/docs/source/conf.py --- old/pilkit-2.0/docs/source/conf.py 2017-02-17 12:45:57.000000000 +0100 +++ new/pilkit-3.0/docs/source/conf.py 2023-09-26 22:35:02.000000000 +0200 @@ -16,7 +16,8 @@ # 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('.')) +# sys.path.insert(0, os.path.abspath('.')) +sys.path.append(os.path.abspath('./_ext')) # -- General configuration ----------------------------------------------------- @@ -25,7 +26,7 @@ # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = [] +extensions = ['pil'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pilkit-2.0/docs/source/index.rst new/pilkit-3.0/docs/source/index.rst --- old/pilkit-2.0/docs/source/index.rst 2017-02-17 12:45:57.000000000 +0100 +++ new/pilkit-3.0/docs/source/index.rst 2023-09-26 22:35:02.000000000 +0200 @@ -5,18 +5,25 @@ .. include:: ../../README.rst +Contents +-------- + +.. toctree:: + :maxdepth: 2 + + processors/resize + processors/filter + + Authors -======= +------- .. include:: ../../AUTHORS -Contents -========= +Indices and tables +------------------ * :ref:`genindex` * :ref:`modindex` * :ref:`search` - -.. toctree:: - :maxdepth: 2 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pilkit-2.0/docs/source/processors/filter.rst new/pilkit-3.0/docs/source/processors/filter.rst --- old/pilkit-2.0/docs/source/processors/filter.rst 1970-01-01 01:00:00.000000000 +0100 +++ new/pilkit-3.0/docs/source/processors/filter.rst 2023-09-26 22:35:02.000000000 +0200 @@ -0,0 +1,37 @@ + +Filter +======= + +Original Image + +.. image:: ../_ext/original.jpg + + +Gaussian Blur +------------- + +.. pil-block:: + + from pilkit.processors.filter import GaussianBlur + + old_img = Image.open('original.jpg') + blur = GaussianBlur(1) + new_img = blur.process(old_img) + + +.. pil-block:: + + from pilkit.processors.filter import GaussianBlur + + old_img = Image.open('original.jpg') + blur = GaussianBlur(5) + new_img = blur.process(old_img) + + +.. pil-block:: + + from pilkit.processors.filter import GaussianBlur + + old_img = Image.open('original.jpg') + blur = GaussianBlur(10) + new_img = blur.process(old_img) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pilkit-2.0/docs/source/processors/resize.rst new/pilkit-3.0/docs/source/processors/resize.rst --- old/pilkit-2.0/docs/source/processors/resize.rst 1970-01-01 01:00:00.000000000 +0100 +++ new/pilkit-3.0/docs/source/processors/resize.rst 2023-09-26 22:35:02.000000000 +0200 @@ -0,0 +1,115 @@ + +Resize +======= + +Original Image + +.. image:: ../_ext/original.jpg + + +Resize To Fill +--------------- +.. pil-block:: + + from pilkit.processors.resize import ResizeToFill + + old_img = Image.open('original.jpg') + resizer = ResizeToFill(300, 300) + new_img = resizer.process(old_img) + +.. pil-block:: + + from pilkit.processors.resize import ResizeToFill + + old_img = Image.open('original.jpg') + resizer = ResizeToFill(600, 300) + new_img = resizer.process(old_img) + +.. pil-block:: + + from pilkit.processors.resize import ResizeToFill + + old_img = Image.open('original.jpg') + resizer = ResizeToFill(300, 600) + new_img = resizer.process(old_img) + + +Resize To Cover +---------------- +.. pil-block:: + + from pilkit.processors.resize import ResizeToCover + + old_img = Image.open('original.jpg') + resizer = ResizeToCover(300, 300) # width, height + new_img = resizer.process(old_img) + +.. pil-block:: + + from pilkit.processors.resize import ResizeToCover + + old_img = Image.open('original.jpg') + resizer = ResizeToCover(600, 300) # width, height + new_img = resizer.process(old_img) + +.. pil-block:: + + from pilkit.processors.resize import ResizeToCover + + old_img = Image.open('original.jpg') + resizer = ResizeToCover(300, 600) # width, height + new_img = resizer.process(old_img) + + +Resize To Fit +-------------- +.. pil-block:: + + from pilkit.processors.resize import ResizeToFit + + old_img = Image.open('original.jpg') + resizer = ResizeToFit(300, 300) + new_img = resizer.process(old_img) + +.. pil-block:: + + from pilkit.processors.resize import ResizeToFit + + old_img = Image.open('original.jpg') + resizer = ResizeToFit(600, 300) + new_img = resizer.process(old_img) + +.. pil-block:: + + from pilkit.processors.resize import ResizeToFit + + old_img = Image.open('original.jpg') + resizer = ResizeToFit(300, 600) + new_img = resizer.process(old_img) + + +Thumbnail +---------- +.. pil-block:: + + from pilkit.processors.resize import Thumbnail + + old_img = Image.open('original.jpg') + resizer = Thumbnail(300, 300) + new_img = resizer.process(old_img) + +.. pil-block:: + + from pilkit.processors.resize import Thumbnail + + old_img = Image.open('original.jpg') + resizer = Thumbnail(600, 300) + new_img = resizer.process(old_img) + +.. pil-block:: + + from pilkit.processors.resize import Thumbnail + + old_img = Image.open('original.jpg') + resizer = Thumbnail(300, 600) + new_img = resizer.process(old_img) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pilkit-2.0/pilkit/lib.py new/pilkit-3.0/pilkit/lib.py --- old/pilkit-2.0/pilkit/lib.py 2017-02-17 12:45:57.000000000 +0100 +++ new/pilkit-3.0/pilkit/lib.py 2023-09-27 02:00:56.000000000 +0200 @@ -4,7 +4,7 @@ # depending on the installation method used. try: from PIL import Image, ImageColor, ImageChops, ImageEnhance, ImageFile, \ - ImageFilter, ImageDraw, ImageStat + ImageFilter, ImageDraw, ImageStat, ImageMode except ImportError: try: import Image @@ -15,6 +15,7 @@ import ImageFilter import ImageDraw import ImageStat + import ImageMode 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.') @@ -33,3 +34,34 @@ string_types = [basestring, str] except NameError: string_types = [str] + + +def getattrsafe(obj, attr, fallback_attr = None): + """Similar to getattr but accept dotted path + + The idea of this function is to pass dotted path to attribute. + If the path is missing then the fallback will be evaluated as dotted path also. + If the fallback is not present then the attribute error for the first path is thrown + + The main idea of this function is for compatibility with Pillow < 10 + + Example:: + + >>> from PIL import Image + >>> getattrsafe(Image, 'Transpose.FLIP_HORIZONTAL', 'FLIP_HORIZONTAL') + """ + names = attr.split('.') + res = obj + for i, name in enumerate(names): + try: + res = getattr(res, name) + except AttributeError: + missing = '.'.join(names[:i + 1]) + if fallback_attr is None: + raise AttributeError("'{}' object has no attribute '{}'".format(type(obj).__name__, missing)) + else: + try: + return getattrsafe(obj, fallback_attr) + except AttributeError: + raise AttributeError("'{}' object has no attribute '{}' or '{}'".format(type(obj).__name__, missing, fallback_attr)) + return res diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pilkit-2.0/pilkit/pkgmeta.py new/pilkit-3.0/pilkit/pkgmeta.py --- old/pilkit-2.0/pilkit/pkgmeta.py 2017-02-17 12:55:50.000000000 +0100 +++ new/pilkit-3.0/pilkit/pkgmeta.py 2023-09-27 02:35:50.000000000 +0200 @@ -1,5 +1,5 @@ __title__ = 'pilkit' __author__ = 'Matthew Tretter' -__version__ = '2.0' +__version__ = '3.0' __license__ = 'BSD' __all__ = ['__title__', '__author__', '__version__', '__license__'] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pilkit-2.0/pilkit/processors/__init__.py new/pilkit-3.0/pilkit/processors/__init__.py --- old/pilkit-2.0/pilkit/processors/__init__.py 2017-02-17 12:45:57.000000000 +0100 +++ new/pilkit-3.0/pilkit/processors/__init__.py 2023-09-26 22:35:02.000000000 +0200 @@ -12,5 +12,7 @@ from .base import * from .crop import * +from .convert import * +from .filter import * from .overlay import * from .resize import * diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pilkit-2.0/pilkit/processors/base.py new/pilkit-3.0/pilkit/processors/base.py --- old/pilkit-2.0/pilkit/processors/base.py 2017-02-17 12:45:57.000000000 +0100 +++ new/pilkit-3.0/pilkit/processors/base.py 2023-09-27 02:37:01.000000000 +0200 @@ -1,4 +1,4 @@ -from pilkit.lib import Image, ImageColor, ImageEnhance +from pilkit.lib import Image, ImageColor, ImageEnhance, getattrsafe class ProcessorPipeline(list): @@ -80,7 +80,7 @@ # Handle palleted images. img = img.convert('RGBA') # Copy orignial image and flip the orientation. - reflection = img.copy().transpose(Image.FLIP_TOP_BOTTOM) + reflection = img.copy().transpose(Transpose.FLIP_VERTICAL) # Create a new image filled with the bgcolor the same size. background = Image.new("RGBA", img.size, background_color) # Calculate our alpha mask. @@ -116,11 +116,11 @@ """ 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 + FLIP_HORIZONTAL = getattrsafe(Image, 'Transpose.FLIP_LEFT_RIGHT', 'FLIP_LEFT_RIGHT') # noqa + FLIP_VERTICAL = getattrsafe(Image, 'Transpose.FLIP_TOP_BOTTOM', 'FLIP_TOP_BOTTOM') # noqa + ROTATE_90 = getattrsafe(Image, 'Transpose.ROTATE_90', 'ROTATE_90') + ROTATE_180 = getattrsafe(Image, 'Transpose.ROTATE_180', 'ROTATE_180') + ROTATE_270 = getattrsafe(Image, 'Transpose.ROTATE_270', 'ROTATE_270') methods = [AUTO] _EXIF_ORIENTATION_STEPS = { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pilkit-2.0/pilkit/processors/convert.py new/pilkit-3.0/pilkit/processors/convert.py --- old/pilkit-2.0/pilkit/processors/convert.py 1970-01-01 01:00:00.000000000 +0100 +++ new/pilkit-3.0/pilkit/processors/convert.py 2023-09-26 22:35:02.000000000 +0200 @@ -0,0 +1,15 @@ + +class Convert(object): + """ + Converts image to different mode + """ + + def __init__(self, mode): + """ + :param mode: Define the mode to which an image is to be converted + + """ + self.mode = mode + + def process(self, img): + return img.convert(self.mode) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pilkit-2.0/pilkit/processors/filter.py new/pilkit-3.0/pilkit/processors/filter.py --- old/pilkit-2.0/pilkit/processors/filter.py 1970-01-01 01:00:00.000000000 +0100 +++ new/pilkit-3.0/pilkit/processors/filter.py 2023-09-26 22:35:02.000000000 +0200 @@ -0,0 +1,16 @@ +from PIL import ImageFilter + +class GaussianBlur(object): + """ + Performs Gaussian blur filter on image. + """ + + def __init__(self, radius): + """ + :param radius: Blur radius (passed to GaussianBlur filter) + """ + + self.radius = radius + + def process(self, img): + return img.filter(ImageFilter.GaussianBlur(self.radius)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pilkit-2.0/pilkit/processors/resize.py new/pilkit-3.0/pilkit/processors/resize.py --- old/pilkit-2.0/pilkit/processors/resize.py 2017-02-17 12:45:57.000000000 +0100 +++ new/pilkit-3.0/pilkit/processors/resize.py 2023-09-27 02:37:01.000000000 +0200 @@ -1,5 +1,6 @@ from .base import Anchor -from ..lib import Image +from .utils import resolve_palette +from ..lib import Image, getattrsafe class Resize(object): @@ -7,6 +8,8 @@ Resizes an image to the specified width and height. """ + LANCZOS = getattrsafe(Image, 'Resampling.LANCZOS', 'LANCZOS') + def __init__(self, width, height, upscale=True): """ :param width: The target width, in pixels. @@ -20,8 +23,8 @@ 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) + img = resolve_palette(img) + img = img.resize((self.width, self.height), self.LANCZOS) return img diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pilkit-2.0/pilkit/processors/utils.py new/pilkit-3.0/pilkit/processors/utils.py --- old/pilkit-2.0/pilkit/processors/utils.py 2017-02-17 12:45:57.000000000 +0100 +++ new/pilkit-3.0/pilkit/processors/utils.py 2023-09-27 01:01:12.000000000 +0200 @@ -1,18 +1,32 @@ -import math -from ..lib import Image +from ..lib import Image, ImageMode -def histogram_entropy(im): +def color_count(image): + """ Return the number of color values in the input image -- + this is the number of pixels times the band count + of the image. """ - 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 + mode_descriptor = ImageMode.getmode(image.mode) + width, height = image.size + return width * height * len(mode_descriptor.bands) - """ - if not isinstance(im, Image.Image): - return 0 # Fall back to a constant entropy. +def histogram_entropy_py(image): + """ Calculate the entropy of an images' histogram. """ + from math import log2, fsum + histosum = float(color_count(image)) + histonorm = (histocol / histosum for histocol in image.histogram()) + return -fsum(p * log2(p) for p in histonorm if p != 0.0) + +# Select the Pillow native histogram entropy function - if +# available - and fall back to the Python implementation: +histogram_entropy = getattr(Image.Image, 'entropy', histogram_entropy_py) + +def resolve_palette(image): + """ Convert a palette image to a non-palette image. """ - histogram = im.histogram() - hist_ceil = float(sum(histogram)) - histonorm = [histocol / hist_ceil for histocol in histogram] + # We need to load the image before accessing the palette + image.load() - return -sum([p * math.log(p, 2) for p in histonorm if p != 0]) + if image.palette is None: + return image + return image.convert(image.palette.mode) \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pilkit-2.0/pilkit/utils.py new/pilkit-3.0/pilkit/utils.py --- old/pilkit-2.0/pilkit/utils.py 2017-02-17 12:45:57.000000000 +0100 +++ new/pilkit-3.0/pilkit/utils.py 2023-09-27 02:00:56.000000000 +0200 @@ -3,13 +3,14 @@ import sys from io import UnsupportedOperation from .exceptions import UnknownExtension, UnknownFormat -from .lib import Image, ImageFile, StringIO, string_types +from .lib import Image, ImageFile, StringIO, string_types, getattrsafe -RGBA_TRANSPARENCY_FORMATS = ['PNG'] +RGBA_TRANSPARENCY_FORMATS = ['PNG', 'WEBP'] PALETTE_TRANSPARENCY_FORMATS = ['PNG', 'GIF'] DEFAULT_EXTENSIONS = { 'JPEG': '.jpg', + 'PNG': '.png', } @@ -245,6 +246,10 @@ # In case of Azure, the file descriptor is not present so we can return # from here return + except UnsupportedOperation: + # In case of Windows 2016, the file descriptor is not present so we can return + # from here + return try: self.null_fd = os.open(os.devnull, os.O_RDWR) except OSError: @@ -306,8 +311,8 @@ 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) + palette = getattrsafe(Image, 'Palette.ADAPTIVE', 'ADAPTIVE') + img = img.convert('RGB').convert('P', palette=palette, colors=255) img.paste(255, mask) save_kwargs['transparency'] = 255 else: @@ -339,7 +344,8 @@ # 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) + palette = getattrsafe(Image, 'Palette.ADAPTIVE', 'ADAPTIVE') + img = img.convert('P', palette=palette) if make_opaque: from .processors import MakeOpaque diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pilkit-2.0/pilkit.egg-info/PKG-INFO new/pilkit-3.0/pilkit.egg-info/PKG-INFO --- old/pilkit-2.0/pilkit.egg-info/PKG-INFO 2017-02-17 13:07:49.000000000 +0100 +++ new/pilkit-3.0/pilkit.egg-info/PKG-INFO 2023-09-28 00:01:05.000000000 +0200 @@ -1,123 +1,125 @@ -Metadata-Version: 1.1 +Metadata-Version: 2.1 Name: pilkit -Version: 2.0 -Summary: A collection of utilities and processors for the Python Imaging Libary. +Version: 3.0 +Summary: A collection of utilities and processors for the Python Imaging Library. 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 - :target: https://travis-ci.org/matthewwithanm/pilkit - - .. _`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 <https://github.com/matthewwithanm/pilkit/issues>`_ - to report bugs. `A mailing list <https://groups.google.com/forum/#!forum/django-imagekit>`_ - also exists to discuss the project and ask questions, as well as the official - `#imagekit <irc://irc.freenode.net/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 -Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.3 -Classifier: Programming Language :: Python :: 3.4 -Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 Classifier: Topic :: Utilities +License-File: LICENSE +License-File: AUTHORS +Requires-Dist: Pillow>=7.0 + +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://github.com/matthewwithanm/pilkit/workflows/Python%20CI/badge.svg + :target: https://github.com/matthewwithanm/pilkit/actions?query=workflow%3A%22Python+CI%22 + +.. _`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 <https://github.com/matthewwithanm/pilkit/issues>`_ +to report bugs. `A mailing list <https://groups.google.com/forum/#!forum/django-imagekit>`_ +also exists to discuss the project and ask questions, as well as the official +`#imagekit <irc://irc.freenode.net/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 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pilkit-2.0/pilkit.egg-info/SOURCES.txt new/pilkit-3.0/pilkit.egg-info/SOURCES.txt --- old/pilkit-2.0/pilkit.egg-info/SOURCES.txt 2017-02-17 13:07:49.000000000 +0100 +++ new/pilkit-3.0/pilkit.egg-info/SOURCES.txt 2023-09-28 00:01:05.000000000 +0200 @@ -7,6 +7,11 @@ docs/make.bat docs/source/conf.py docs/source/index.rst +docs/source/_ext/original.jpg +docs/source/_ext/pil.py +docs/source/_ext/__pycache__/pil.cpython-311.pyc +docs/source/processors/filter.rst +docs/source/processors/resize.rst pilkit/__init__.py pilkit/exceptions.py pilkit/lib.py @@ -16,10 +21,14 @@ pilkit.egg-info/SOURCES.txt pilkit.egg-info/dependency_links.txt pilkit.egg-info/not-zip-safe +pilkit.egg-info/pbr.json +pilkit.egg-info/requires.txt pilkit.egg-info/top_level.txt pilkit/processors/__init__.py pilkit/processors/base.py +pilkit/processors/convert.py pilkit/processors/crop.py +pilkit/processors/filter.py pilkit/processors/overlay.py pilkit/processors/resize.py pilkit/processors/utils.py @@ -27,5 +36,7 @@ tests/test_processors.py tests/test_utils.py tests/utils.py +tests/assets/GaussianBlur_radius_3.png +tests/assets/GaussianBlur_radius_7.png tests/assets/cat.gif tests/assets/reference.png \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pilkit-2.0/pilkit.egg-info/pbr.json new/pilkit-3.0/pilkit.egg-info/pbr.json --- old/pilkit-2.0/pilkit.egg-info/pbr.json 1970-01-01 01:00:00.000000000 +0100 +++ new/pilkit-3.0/pilkit.egg-info/pbr.json 2016-02-25 21:03:24.000000000 +0100 @@ -0,0 +1 @@ +{"is_release": false, "git_version": "a636041"} \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pilkit-2.0/pilkit.egg-info/requires.txt new/pilkit-3.0/pilkit.egg-info/requires.txt --- old/pilkit-2.0/pilkit.egg-info/requires.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/pilkit-3.0/pilkit.egg-info/requires.txt 2023-09-28 00:01:05.000000000 +0200 @@ -0,0 +1 @@ +Pillow>=7.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pilkit-2.0/setup.cfg new/pilkit-3.0/setup.cfg --- old/pilkit-2.0/setup.cfg 2017-02-17 13:07:49.000000000 +0100 +++ new/pilkit-3.0/setup.cfg 2023-09-28 00:01:05.113009700 +0200 @@ -1,5 +1,4 @@ [egg_info] tag_build = tag_date = 0 -tag_svn_revision = 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pilkit-2.0/setup.py new/pilkit-3.0/setup.py --- old/pilkit-2.0/setup.py 2017-02-17 12:45:57.000000000 +0100 +++ new/pilkit-3.0/setup.py 2023-09-27 02:34:34.000000000 +0200 @@ -1,15 +1,13 @@ -#/usr/bin/env python +#!/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() +def read(filepath): + with codecs.open(filepath, 'r', 'utf-8') as f: + return f.read() + # Load package meta from the pkgmeta module without loading the package. pkgmeta = {} @@ -22,7 +20,7 @@ setup( name='pilkit', version=pkgmeta['__version__'], - description='A collection of utilities and processors for the Python Imaging Libary.', + description='A collection of utilities and processors for the Python Imaging Library.', long_description=read(os.path.join(os.path.dirname(__file__), 'README.rst')), author='Matthew Tretter', author_email='m...@tthewwithanm.com', @@ -31,25 +29,20 @@ packages=find_packages(exclude=['tests', 'tests.*']), zip_safe=False, include_package_data=True, - tests_require=[ - 'mock>=1.0.1', - 'nose>=1.3.6', - 'nose-progressive>=1.5.1', - 'Pillow', + install_requires=[ + 'Pillow>=7.0' ], - 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', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.3', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', 'Topic :: Utilities' ], ) Binary files old/pilkit-2.0/tests/assets/GaussianBlur_radius_3.png and new/pilkit-3.0/tests/assets/GaussianBlur_radius_3.png differ Binary files old/pilkit-2.0/tests/assets/GaussianBlur_radius_7.png and new/pilkit-3.0/tests/assets/GaussianBlur_radius_7.png differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pilkit-2.0/tests/test_processors.py new/pilkit-3.0/tests/test_processors.py --- old/pilkit-2.0/tests/test_processors.py 2017-02-17 12:45:57.000000000 +0100 +++ new/pilkit-3.0/tests/test_processors.py 2023-09-27 02:27:32.000000000 +0200 @@ -1,21 +1,23 @@ +import os +from unittest import mock +import pytest + from pilkit.lib import Image, ImageDraw, ImageColor from pilkit.processors import (Resize, ResizeToFill, ResizeToFit, SmartCrop, - SmartResize, MakeOpaque, ColorOverlay) -from nose.tools import eq_, assert_true -import os + SmartResize, MakeOpaque, ColorOverlay, Convert, + GaussianBlur) from pilkit.processors.resize import Thumbnail -from .utils import create_image -import mock +from .utils import create_image, compare_images, get_image_file def test_smartcrop(): img = SmartCrop(100, 100).process(create_image()) - eq_(img.size, (100, 100)) + assert img.size == (100, 100) def test_resizetofill(): img = ResizeToFill(100, 100).process(create_image()) - eq_(img.size, (100, 100)) + assert img.size == (100, 100) def test_resizetofit(): @@ -26,7 +28,7 @@ img = ResizeToFit(100, 100).process(img) # Assert that the image has maintained the aspect ratio. - eq_(img.size, (100, 50)) + assert img.size == (100, 50) def test_resize_rounding(): @@ -36,13 +38,13 @@ img = Image.new('RGB', (95, 95)) img = ResizeToFill(28, 28).process(img) - eq_(img.size, (28, 28)) + assert 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)) + assert img.size == (100, 100) def test_coloroverlay(): @@ -52,7 +54,16 @@ img = Image.new('RGB', (200, 100)) color = ImageColor.getrgb('#cc0000') img = ColorOverlay(color, overlay_opacity=1.0).process(img) - eq_(img.getpixel((0,0)), (204, 0, 0)) + assert img.getpixel((0,0)) == (204, 0, 0) + +def test_convert(): + img = Image.new('RGBA', (200, 100)) + + img_RGBa = Convert("RGBa").process(img) + assert img_RGBa.mode == "RGBa" + + img_RGBa_RGBA = Convert("RGBA").process(img) + assert img_RGBa_RGBA.mode == "RGBA" def test_resize_antialiasing(): @@ -82,7 +93,7 @@ # Count the number of colors color_count = len(list(filter(None, img.histogram()))) - assert_true(color_count > 2) + assert color_count > 2 def test_upscale(): @@ -95,37 +106,33 @@ for P in [Resize, ResizeToFit, ResizeToFill, SmartResize]: img2 = P(500, 500, upscale=True).process(img) - eq_(img2.size, (500, 500)) + assert img2.size == (500, 500) img2 = P(500, 500, upscale=False).process(img) - eq_(img2.size, (100, 100)) + assert img2.size == (100, 100) def test_should_raise_exception_if_anchor_is_passed_and_crop_is_set_to_false(): - try: + with pytest.raises(Exception, match=r"You can't specify an anchor point if crop is False."): 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) + assert thumb.crop def test_should_raise_exception_when_crop_is_passed_without_height_and_width(): img = Image.new('RGB', (100, 100)) - try: + with pytest.raises(Exception, match=r"You must provide both a width and height when cropping."): 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) + assert my_mock.called @mock.patch('pilkit.processors.resize.SmartResize') @@ -146,13 +153,27 @@ 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) + assert 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) + assert my_mock.called + +def test_GaussianBlur_radius_3(): + img = GaussianBlur(radius = 3).process(create_image()) + img = img.crop((112,112,144,144)) + + expected_img = Image.open(get_image_file("GaussianBlur_radius_3.png")) + assert compare_images(img, expected_img) + +def test_GaussianBlur_radius_7(): + img = GaussianBlur(radius=7).process(create_image()) + img = img.crop((112, 112, 144, 144)) + + expected_img = Image.open(get_image_file("GaussianBlur_radius_7.png")) + assert compare_images(img, expected_img) def test_make_gifs_opaque(): dir = os.path.dirname(__file__) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pilkit-2.0/tests/test_utils.py new/pilkit-3.0/tests/test_utils.py --- old/pilkit-2.0/tests/test_utils.py 2017-02-17 12:45:57.000000000 +0100 +++ new/pilkit-3.0/tests/test_utils.py 2023-09-27 02:27:32.000000000 +0200 @@ -1,33 +1,35 @@ import os -from io import UnsupportedOperation +import io +import pytest +from unittest.mock import Mock, patch +from tempfile import NamedTemporaryFile + 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') + assert extension_to_format('.jpeg') == 'JPEG' + assert extension_to_format('.rgba') == 'SGI' def test_format_to_extension_no_init(): - eq_(format_to_extension('PNG'), '.png') - eq_(format_to_extension('ICO'), '.ico') + assert format_to_extension('PNG') == '.png' + assert format_to_extension('ICO') == '.ico' -@raises(UnknownFormat) def test_unknown_format(): - format_to_extension('TXT') + with pytest.raises(UnknownFormat): + format_to_extension('TXT') -@raises(UnknownExtension) def test_unknown_extension(): - extension_to_format('.txt') + with pytest.raises(UnknownExtension): + extension_to_format('.txt') def test_default_extension(): @@ -40,17 +42,17 @@ extensions we'd prefer, and this tests to make sure it's working. """ - eq_(format_to_extension('JPEG'), '.jpg') + assert format_to_extension('JPEG') == '.jpg' -@raises(AttributeError) def test_filewrapper(): class K(object): def fileno(self): - raise UnsupportedOperation + raise io.UnsupportedOperation - FileWrapper(K()).fileno() + with pytest.raises(AttributeError): + FileWrapper(K()).fileno() def test_save_with_filename(): @@ -60,9 +62,8 @@ """ im = create_image() - outfile = NamedTemporaryFile() - save_image(im, outfile.name, 'JPEG') - outfile.close() + with NamedTemporaryFile() as outfile: + save_image(im, outfile.name, 'JPEG') def test_format_normalization(): @@ -71,7 +72,8 @@ See https://github.com/matthewwithanm/django-imagekit/issues/262 """ im = Image.new('RGBA', (100, 100)) - ok_('transparency' in prepare_image(im, 'gIF')[1]) + assert 'transparency' in prepare_image(im, 'gIF')[1] + def test_quiet(): """ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pilkit-2.0/tests/utils.py new/pilkit-3.0/tests/utils.py --- old/pilkit-2.0/tests/utils.py 2017-02-17 12:45:57.000000000 +0100 +++ new/pilkit-3.0/tests/utils.py 2023-09-26 22:35:02.000000000 +0200 @@ -2,7 +2,7 @@ from pilkit.lib import Image -def get_image_file(): +def get_image_file(image_name='reference.png'): """ See also: @@ -11,9 +11,21 @@ """ dir = os.path.dirname(__file__) - path = os.path.join(dir, 'assets', 'reference.png') + path = os.path.join(dir, 'assets', image_name) return open(path, 'r+b') - def create_image(): return Image.open(get_image_file()) + +def compare_images(a, b): + if a.size != b.size: + return False + + rows, cols = a.size + + for row in range(rows): + for col in range(cols): + if a.getpixel((row, col)) != b.getpixel((row, col)): + return False + + return True