[Python-modules-commits] [willow] 01/06: Import willow_1.1.orig.tar.gz

Christopher Stuart Hoskin mans0954 at moszumanska.debian.org
Tue Dec 5 23:10:39 UTC 2017


This is an automated email from the git hooks/post-receive script.

mans0954 pushed a commit to branch master
in repository willow.

commit 3477512641360b87eafb88581386b7e626edda5f
Author: Christopher Hoskin <mans0954 at debian.org>
Date:   Tue Dec 5 22:56:45 2017 +0000

    Import willow_1.1.orig.tar.gz
---
 MANIFEST.in               |  1 +
 README.rst                |  1 +
 docs/changelog.rst        |  8 +++++++-
 docs/guide/operations.rst | 20 ++++++++++++++++++++
 docs/reference.rst        | 24 ++++++++++++++++++++++++
 setup.py                  |  2 +-
 tests/test_pillow.py      | 28 ++++++++++++++++++++++++----
 tests/test_wand.py        | 31 +++++++++++++++++++++++++++----
 willow/__init__.py        |  2 +-
 willow/plugins/pillow.py  | 28 ++++++++++++++++++++++++++++
 willow/plugins/wand.py    | 27 +++++++++++++++++++++++++++
 11 files changed, 161 insertions(+), 11 deletions(-)

diff --git a/MANIFEST.in b/MANIFEST.in
index e1dab17..597a588 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -2,3 +2,4 @@ graft willow
 global-exclude __pycache__
 global-exclude *.py[co]
 global-exclude *.swp
+include LICENSE
diff --git a/README.rst b/README.rst
index 0a85a0d..f5053cf 100644
--- a/README.rst
+++ b/README.rst
@@ -75,6 +75,7 @@ Operation                           Pillow               Wand                 Op
 ``get_size()``                      ✓                    ✓                    ✓
 ``resize(size)``                    ✓                    ✓
 ``crop(rect)``                      ✓                    ✓
+``set_background_color_rgb(color)`` ✓                    ✓
 ``auto_orient()``                   ✓                    ✓
 ``save_as_jpeg(file, quality)``     ✓                    ✓
 ``save_as_png(file)``               ✓                    ✓
diff --git a/docs/changelog.rst b/docs/changelog.rst
index 507960e..f739e24 100644
--- a/docs/changelog.rst
+++ b/docs/changelog.rst
@@ -1,7 +1,13 @@
 Changelog
 =========
 
-1.0 (04/08/2016)
+1.1 (04/12/2017)
+----------------
+
+ - Added `set_background_color_rgb` operation
+ - Update MANIFEST.in (Sanny Kumar)
+
+1.0 (04/08/2017)
 ----------------
 
  - OpenCV 3 support (Will Giddens)
diff --git a/docs/guide/operations.rst b/docs/guide/operations.rst
index 328cec6..ab507ea 100644
--- a/docs/guide/operations.rst
+++ b/docs/guide/operations.rst
@@ -61,6 +61,26 @@ original image is not modified.
     isinstance(i, Image)
     i.get_size() == (200, 200)
 
+Setting a background colour
+---------------------------
+
+If the image has transparency, you can replace the transparency with a solid
+background colour using the :meth:`~Image.set_background_color_rgb` method.
+
+It takes the background color as a three element tuple of integers between
+0 - 255 (representing the red, green and blue channels respectively).
+
+It returns a new :class:`~Image` object containing the background color and
+the alpha channel removed. The original image is not modified.
+
+.. code-block:: python
+
+    # Sets background color to white
+    i = i.set_background_color_rgb((255, 255, 255))
+
+    isinstance(i, Image)
+    i.has_alpha() == False
+
 Detecting features
 ------------------
 
diff --git a/docs/reference.rst b/docs/reference.rst
index 578ace7..7c26304 100644
--- a/docs/reference.rst
+++ b/docs/reference.rst
@@ -139,6 +139,25 @@ Here's a full list of operations provided by Willow out of the box:
         # Cut out a square from the middle of the image
         cropped_image = source_image.resize((100, 100, 200, 200))
 
+.. method:: set_background_color_rgb(color)
+
+    (Pillow/Wand only)
+
+    If the image has an alpha channel, this will add a background colour using
+    the alpha channel as a mask. The alpha channel will be removed from the
+    resulting image.
+
+    The background colour must be specified as a tuple of three integers with
+    values between 0 - 255.
+
+    This operation will convert the image to RGB format, but will not do
+    anything if there is not an alpha channel.
+
+    .. code-block:: python
+
+        # Set the background colour of the image to white
+        image = source_image.set_background_color_rgb((255, 255, 255))
+
 .. method:: auto_orient()
 
     (Pillow/Wand only)
@@ -192,6 +211,11 @@ Here's a full list of operations provided by Willow out of the box:
 
     Saves the image to the specified file-like object in JPEG format.
 
+    Note: If the image has an alpha channel, this operation may raise an
+    exception or save a broken image (depending on the backend being used).
+    To resolve this, use the :meth:`~Image.set_background_color_rgb` method to
+    replace the alpha channel with a solid background color before saving as JPEG.
+
     Returns a ``JPEGImageFile`` wrapping the file.
 
     .. code-block:: python
diff --git a/setup.py b/setup.py
index 5502393..abae811 100644
--- a/setup.py
+++ b/setup.py
@@ -20,7 +20,7 @@ except ImportError:
 
 setup(
     name='Willow',
-    version='1.0',
+    version='1.1',
     description='A Python image library that sits on top of Pillow, Wand and OpenCV',
     author='Karl Hobley',
     author_email='karl at kaed.uk',
diff --git a/tests/test_pillow.py b/tests/test_pillow.py
index 7160f22..d6edf94 100644
--- a/tests/test_pillow.py
+++ b/tests/test_pillow.py
@@ -26,9 +26,23 @@ class TestPillowOperations(unittest.TestCase):
         cropped_image = self.image.crop((10, 10, 100, 100))
         self.assertEqual(cropped_image.get_size(), (90, 90))
 
+    def test_set_background_color_rgb(self):
+        red_background_image = self.image.set_background_color_rgb((255, 0, 0))
+        self.assertFalse(red_background_image.has_alpha())
+        self.assertEqual(red_background_image.image.getpixel((10, 10)), (255, 0, 0))
+
+    def test_set_background_color_rgb_color_argument_check(self):
+        with self.assertRaises(TypeError) as e:
+            self.image.set_background_color_rgb('rgb(255, 0, 0)')
+
+        self.assertEqual(str(e.exception), "the 'color' argument must be a 3-element tuple or list")
+
     def test_save_as_jpeg(self):
+        # Remove alpha channel from image
+        image = self.image.set_background_color_rgb((255, 255, 255))
+
         output = io.BytesIO()
-        return_value = self.image.save_as_jpeg(output)
+        return_value = image.save_as_jpeg(output)
         output.seek(0)
 
         self.assertEqual(imghdr.what(output), 'jpeg')
@@ -36,14 +50,20 @@ class TestPillowOperations(unittest.TestCase):
         self.assertEqual(return_value.f, output)
 
     def test_save_as_jpeg_optimised(self):
-        unoptimised = self.image.save_as_jpeg(io.BytesIO())
-        optimised = self.image.save_as_jpeg(io.BytesIO(), optimize=True)
+        # Remove alpha channel from image
+        image = self.image.set_background_color_rgb((255, 255, 255))
+
+        unoptimised = image.save_as_jpeg(io.BytesIO())
+        optimised = image.save_as_jpeg(io.BytesIO(), optimize=True)
 
         # Optimised image must be smaller than unoptimised image
         self.assertTrue(optimised.f.tell() < unoptimised.f.tell())
 
     def test_save_as_jpeg_progressive(self):
-        image = self.image.save_as_jpeg(io.BytesIO(), progressive=True)
+        # Remove alpha channel from image
+        image = self.image.set_background_color_rgb((255, 255, 255))
+
+        image = image.save_as_jpeg(io.BytesIO(), progressive=True)
 
         self.assertTrue(PILImage.open(image.f).info['progressive'])
 
diff --git a/tests/test_wand.py b/tests/test_wand.py
index 6bc4c74..b84746a 100644
--- a/tests/test_wand.py
+++ b/tests/test_wand.py
@@ -28,9 +28,26 @@ class TestWandOperations(unittest.TestCase):
         cropped_image = self.image.crop((10, 10, 100, 100))
         self.assertEqual(cropped_image.get_size(), (90, 90))
 
+    def test_set_background_color_rgb(self):
+        red_background_image = self.image.set_background_color_rgb((255, 0, 0))
+        self.assertFalse(red_background_image.has_alpha())
+        colour = red_background_image.image[10][10]
+        self.assertEqual(colour.red, 1.0)
+        self.assertEqual(colour.green, 0.0)
+        self.assertEqual(colour.blue, 0.0)
+
+    def test_set_background_color_rgb_color_argument_check(self):
+        with self.assertRaises(TypeError) as e:
+            self.image.set_background_color_rgb('rgb(255, 0, 0)')
+
+        self.assertEqual(str(e.exception), "the 'color' argument must be a 3-element tuple or list")
+
     def test_save_as_jpeg(self):
+        # Remove alpha channel from image
+        image = self.image.set_background_color_rgb((255, 255, 255))
+
         output = io.BytesIO()
-        return_value = self.image.save_as_jpeg(output)
+        return_value = image.save_as_jpeg(output)
         output.seek(0)
 
         self.assertEqual(imghdr.what(output), 'jpeg')
@@ -39,14 +56,20 @@ class TestWandOperations(unittest.TestCase):
 
     @unittest.expectedFailure
     def test_save_as_jpeg_optimised(self):
-        unoptimised = self.image.save_as_jpeg(io.BytesIO())
-        optimised = self.image.save_as_jpeg(io.BytesIO(), optimize=True)
+        # Remove alpha channel from image
+        image = self.image.set_background_color_rgb((255, 255, 255))
+
+        unoptimised = image.save_as_jpeg(io.BytesIO())
+        optimised = image.save_as_jpeg(io.BytesIO(), optimize=True)
 
         # Optimised image must be smaller than unoptimised image
         self.assertTrue(optimised.f.tell() < unoptimised.f.tell())
 
     def test_save_as_jpeg_progressive(self):
-        image = self.image.save_as_jpeg(io.BytesIO(), progressive=True)
+        # Remove alpha channel from image
+        image = self.image.set_background_color_rgb((255, 255, 255))
+
+        image = image.save_as_jpeg(io.BytesIO(), progressive=True)
 
         self.assertTrue(PILImage.open(image.f).info['progressive'])
 
diff --git a/willow/__init__.py b/willow/__init__.py
index f487025..360ecc8 100644
--- a/willow/__init__.py
+++ b/willow/__init__.py
@@ -29,4 +29,4 @@ def setup():
 setup()
 
 
-__version__ = '1.0'
+__version__ = '1.1'
diff --git a/willow/plugins/pillow.py b/willow/plugins/pillow.py
index f8b635e..b404794 100644
--- a/willow/plugins/pillow.py
+++ b/willow/plugins/pillow.py
@@ -58,6 +58,34 @@ class PillowImage(Image):
         return PillowImage(self.image.crop(rect))
 
     @Image.operation
+    def set_background_color_rgb(self, color):
+        if not self.has_alpha():
+            # Don't change image that doesn't have an alpha channel
+            return self
+
+        # Check type of color
+        if not isinstance(color, (tuple, list)) or not len(color) == 3:
+            raise TypeError("the 'color' argument must be a 3-element tuple or list")
+
+        # Convert non-RGB colour formats to RGB
+        # As we only allow the background color to be passed in as RGB, we
+        # convert the format of the original image to match.
+        image = self.image.convert('RGBA')
+
+        # Generate a new image with background colour and draw existing image on top of it
+        # The new image must temporarily be RGBA in order for alpha_composite to work
+        new_image = _PIL_Image().new('RGBA', self.image.size, (color[0], color[1], color[2], 255))
+
+        if hasattr(new_image, 'alpha_composite'):
+            new_image.alpha_composite(image)
+        else:
+            # Pillow < 4.2.0 fallback
+            # This method may be slower as the operation generates a new image
+            new_image = _PIL_Image().alpha_composite(new_image, image)
+
+        return PillowImage(new_image.convert('RGB'))
+
+    @Image.operation
     def save_as_jpeg(self, f, quality=85, optimize=False, progressive=False):
         if self.image.mode in ['1', 'P']:
             image = self.image.convert('RGB')
diff --git a/willow/plugins/wand.py b/willow/plugins/wand.py
index 6e4ae0b..42d324e 100644
--- a/willow/plugins/wand.py
+++ b/willow/plugins/wand.py
@@ -19,6 +19,11 @@ def _wand_image():
     return wand.image
 
 
+def _wand_color():
+    import wand.color
+    return wand.color
+
+
 def _wand_api():
     import wand.api
     return wand.api
@@ -31,6 +36,7 @@ class WandImage(Image):
     @classmethod
     def check(cls):
         _wand_image()
+        _wand_color()
         _wand_api()
 
     def _clone(self):
@@ -61,6 +67,27 @@ class WandImage(Image):
         return clone
 
     @Image.operation
+    def set_background_color_rgb(self, color):
+        if not self.has_alpha():
+            # Don't change image that doesn't have an alpha channel
+            return self
+
+        # Check type of color
+        if not isinstance(color, (tuple, list)) or not len(color) == 3:
+            raise TypeError("the 'color' argument must be a 3-element tuple or list")
+
+        clone = self._clone()
+
+        # Wand will perform the compositing at the point of setting alpha_channel to 'remove'
+        clone.image.background_color = _wand_color().Color('rgb({}, {}, {})'.format(*color))
+        clone.image.alpha_channel = 'remove'
+
+        # Set alpha_channel to False manually as Wand doesn't do it
+        clone.image.alpha_channel = False
+
+        return clone
+
+    @Image.operation
     def save_as_jpeg(self, f, quality=85, optimize=False, progressive=False):
         with self.image.convert('pjpeg' if progressive else 'jpeg') as converted:
             converted.compression_quality = quality

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/willow.git



More information about the Python-modules-commits mailing list