[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