summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--PKG-INFO2
-rw-r--r--docs/conf.py4
-rw-r--r--docs/releasenotes.rst20
-rw-r--r--docs/usage.rst36
-rw-r--r--pydenticon.egg-info/PKG-INFO2
-rw-r--r--pydenticon.egg-info/requires.txt2
-rw-r--r--pydenticon/__init__.py37
-rw-r--r--setup.py2
-rw-r--r--tests/test_pydenticon.py46
9 files changed, 111 insertions, 40 deletions
diff --git a/PKG-INFO b/PKG-INFO
index 6bfb983..8e48c91 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: pydenticon
-Version: 0.2
+Version: 0.3
Summary: Library for generating identicons. Port of Sigil (https://github.com/cupcake/sigil) with enhancements.
Home-page: https://github.com/azaghal/pydenticon
Author: Branko Majic
diff --git a/docs/conf.py b/docs/conf.py
index 54a0eb6..ac49123 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -49,9 +49,9 @@ copyright = u'2013, Branko Majic'
# built documents.
#
# The short X.Y version.
-version = '0.2'
+version = '0.3'
# The full version, including alpha/beta/rc tags.
-release = '0.2'
+release = '0.3'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff --git a/docs/releasenotes.rst b/docs/releasenotes.rst
index ffbe84f..15b5b45 100644
--- a/docs/releasenotes.rst
+++ b/docs/releasenotes.rst
@@ -1,6 +1,26 @@
Release Notes
=============
+0.3
+---
+
+Update introducing support for more output formats and ability to use
+transparency for PNG identicons.
+
+New features:
+
+* `PYD-6: Add support for having transparent backgrounds in identicons
+ <https://projects.majic.rs/pydenticon/issues/PYD-6>`_
+
+ Ability to use alpha-channel specification in PNG identicons to obtain
+ complete or partial transparency. Works for both background and foreground
+ colour.
+
+* `PYD-7: Ability to specify image format
+ <https://projects.majic.rs/pydenticon/issues/PYD-7>`_
+
+ Ability to specify any output format supported by the Pillow library.
+
0.2
---
diff --git a/docs/usage.rst b/docs/usage.rst
index c8df87e..b4fa374 100644
--- a/docs/usage.rst
+++ b/docs/usage.rst
@@ -85,6 +85,12 @@ Finally, the resulting identicons can be in different formats::
identicon_ascii = generator.generate("john.doe@example.com", 200, 200,
output_format="ascii")
+Supported output formats are dependant on the local Pillow installation. For
+exact list of available formats, have a look at `Pillow documentation
+<https://pillow.readthedocs.io/>`_. The ``ascii`` format is the only format
+explicitly handled by the *Pydenticon* library itself (mainly useful for
+debugging purposes).
+
Using the generated identicons
------------------------------
@@ -93,9 +99,11 @@ either to be stored somewhere on disk, or maybe streamed back to the user via
HTTP response. Since the generate function returns raw data, this is quite easy
to achieve::
- # Generate same identicon in two different formats.
+ # Generate same identicon in three different formats.
identicon_png = generator.generate("john.doe@example.com", 200, 200,
output_format="png")
+ identicon_gif = generator.generate("john.doe@example.com", 200, 200,
+ output_format="gif")
identicon_ascii = generator.generate("john.doe@example.com", 200, 200,
output_format="ascii")
@@ -104,9 +112,35 @@ to achieve::
f.write(identicon_png)
f.close()
+ f = open("sample.gif", "wb")
+ f.write(identicon_gif)
+ f.close()
+
# ASCII identicon can be printed-out to console directly.
print identicon_ascii
+
+Working with transparency
+-------------------------
+
+.. note::
+ New in version ``0.3``.
+
+.. warning::
+ The only output format that properly supports transparency at the moment is
+ ``PNG``. If you are using anything else, transparency will not work.
+
+If you ever find yourself in need of having a transparent background or
+foreground, you can easily do this using the syntax
+``rgba(224,224,224,0)``. All this does is effectively adding alpha channel to
+selected colour.
+
+The alpha channel value ranges from ``0`` to ``255``, letting you specify how
+much transparency/opaqueness you want. For example, to have it at roughly 50%
+(more like at ``50.2%`` since you can't use fractions), you would simply specify
+value as ``rgba(224,224,224,128)``.
+
+
Full example
------------
diff --git a/pydenticon.egg-info/PKG-INFO b/pydenticon.egg-info/PKG-INFO
index 6bfb983..8e48c91 100644
--- a/pydenticon.egg-info/PKG-INFO
+++ b/pydenticon.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: pydenticon
-Version: 0.2
+Version: 0.3
Summary: Library for generating identicons. Port of Sigil (https://github.com/cupcake/sigil) with enhancements.
Home-page: https://github.com/azaghal/pydenticon
Author: Branko Majic
diff --git a/pydenticon.egg-info/requires.txt b/pydenticon.egg-info/requires.txt
index 5873a22..7e2fba5 100644
--- a/pydenticon.egg-info/requires.txt
+++ b/pydenticon.egg-info/requires.txt
@@ -1 +1 @@
-Pillow \ No newline at end of file
+Pillow
diff --git a/pydenticon/__init__.py b/pydenticon/__init__.py
index 9d484b2..0edfdb0 100644
--- a/pydenticon/__init__.py
+++ b/pydenticon/__init__.py
@@ -184,11 +184,11 @@ class Generator(object):
return [int(digest[i * 2:i * 2 + 2], 16) for i in range(16)]
- def _generate_png(self, matrix, width, height, padding, foreground, background):
+ def _generate_image(self, matrix, width, height, padding, foreground, background, image_format):
"""
- Generates an identicon image in the PNG format out of the passed block
- matrix, with the requested width, height, padding, foreground colour,
- and background colour.
+ Generates an identicon image in requested image format out of the passed
+ block matrix, with the requested width, height, padding, foreground
+ colour, background colour, and image format.
Arguments:
@@ -212,13 +212,16 @@ class Generator(object):
represented as a string of format supported by the PIL.ImageColor
module.
+ image_format - Format to use for the image. Format needs to be
+ supported by the Pillow library.
+
Returns:
- Identicon image in PNG format, returned as a byte list.
+ Identicon image in requested format, returned as a byte list.
"""
# Set-up a new image object, setting the background to provided value.
- image = Image.new("RGB", (width + padding[2] + padding[3], height + padding[0] + padding[1]), background)
+ image = Image.new("RGBA", (width + padding[2] + padding[3], height + padding[0] + padding[1]), background)
# Set-up a draw image (for drawing the blocks).
draw = ImageDraw.Draw(image)
@@ -244,11 +247,14 @@ class Generator(object):
stream = BytesIO()
# Save the image to stream.
- image.save(stream, format="png", optimize=True)
+ try:
+ image.save(stream, format=image_format, optimize=True)
+ except KeyError:
+ raise ValueError("Pillow does not support requested image format: %s" % image_format)
image_raw = stream.getvalue()
stream.close()
- # Return the resulting PNG.
+ # Return the resulting image.
return image_raw
def _generate_ascii(self, matrix, foreground, background):
@@ -296,7 +302,8 @@ class Generator(object):
bottom, left, right.
output_format - Output format of resulting identicon image. Supported
- formats are: "png", "ascii". Default is "png".
+ formats are anything that is supported by Pillow, plus a special
+ "ascii" mode.
inverted - Specifies whether the block colours should be inverted or
not. Default is False.
@@ -313,21 +320,19 @@ class Generator(object):
matrix = self._generate_matrix(digest_byte_list)
# Determine the background and foreground colours.
- if output_format == "png":
- background = self.background
- foreground = self.foreground[digest_byte_list[0] % len(self.foreground)]
- elif output_format == "ascii":
+ if output_format == "ascii":
foreground = "+"
background = "-"
+ else:
+ background = self.background
+ foreground = self.foreground[digest_byte_list[0] % len(self.foreground)]
# Swtich the colours if inverted image was requested.
if inverted:
foreground, background = background, foreground
# Generate the identicon in requested format.
- if output_format == "png":
- return self._generate_png(matrix, width, height, padding, foreground, background)
if output_format == "ascii":
return self._generate_ascii(matrix, foreground, background)
else:
- raise ValueError("Unsupported format requested: %s" % output_format)
+ return self._generate_image(matrix, width, height, padding, foreground, background, output_format)
diff --git a/setup.py b/setup.py
index 8feaac0..c572f75 100644
--- a/setup.py
+++ b/setup.py
@@ -10,7 +10,7 @@ os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir)))
setup(
name='pydenticon',
- version='0.2',
+ version='0.3',
packages=['pydenticon'],
include_package_data=True,
license='BSD', # example license
diff --git a/tests/test_pydenticon.py b/tests/test_pydenticon.py
index 515b271..cc6b13c 100644
--- a/tests/test_pydenticon.py
+++ b/tests/test_pydenticon.py
@@ -152,7 +152,7 @@ class GeneratorTest(unittest.TestCase):
# Verify the expected and actual result are identical.
self.assertEqual(expected_digest_byte_list, digest_byte_list)
- def test_generate_png_basics(self):
+ def test_generate_image_basics(self):
"""
Tests some basics about generated PNG identicon image. This includes:
@@ -179,7 +179,7 @@ class GeneratorTest(unittest.TestCase):
generator = Generator(5, 5)
# Generate the raw image.
- raw_image = generator._generate_png(matrix, width, height, padding, foreground, background)
+ raw_image = generator._generate_image(matrix, width, height, padding, foreground, background, "png")
# Try to load the raw image.
image_stream = BytesIO(raw_image)
@@ -189,7 +189,7 @@ class GeneratorTest(unittest.TestCase):
self.assertEqual(image.size[0], 240)
self.assertEqual(image.size[1], 240)
self.assertEqual(image.format, "PNG")
- self.assertEqual(image.mode, "RGB")
+ self.assertEqual(image.mode, "RGBA")
def test_generate_ascii(self):
"""
@@ -238,6 +238,18 @@ class GeneratorTest(unittest.TestCase):
image = PIL.Image.open(image_stream)
self.assertEqual(image.format, "PNG")
+ # Verify that JPEG image is returned when requested.
+ raw_image = generator.generate(data, 200, 200, output_format="jpeg")
+ image_stream = BytesIO(raw_image)
+ image = PIL.Image.open(image_stream)
+ self.assertEqual(image.format, "JPEG")
+
+ # Verify that GIF image is returned when requested.
+ raw_image = generator.generate(data, 200, 200, output_format="gif")
+ image_stream = BytesIO(raw_image)
+ image = PIL.Image.open(image_stream)
+ self.assertEqual(image.format, "GIF")
+
# Verify that ASCII "image" is returned when requested.
raw_image = generator.generate(data, 200, 200, output_format="ascii")
self.assertIsInstance(raw_image, str)
@@ -257,8 +269,8 @@ class GeneratorTest(unittest.TestCase):
# Verify that an exception is raised in case of unsupported format.
self.assertRaises(ValueError, generator.generate, data, 200, 200, output_format="invalid")
- @mock.patch.object(Generator, '_generate_png')
- def test_generate_inverted_png(self, generate_png_mock):
+ @mock.patch.object(Generator, '_generate_image')
+ def test_generate_inverted_png(self, generate_image_mock):
"""
Tests if the foreground and background are properly inverted when
generating PNG images.
@@ -276,11 +288,11 @@ class GeneratorTest(unittest.TestCase):
# Verify that colours are picked correctly when no inverstion is requsted.
generator.generate(data, 200, 200, inverted=False, output_format="png")
- generate_png_mock.assert_called_with(mock.ANY, mock.ANY, mock.ANY, mock.ANY, foreground, background)
+ generate_image_mock.assert_called_with(mock.ANY, mock.ANY, mock.ANY, mock.ANY, foreground, background, "png")
# Verify that colours are picked correctly when inversion is requsted.
generator.generate(data, 200, 200, inverted=True, output_format="png")
- generate_png_mock.assert_called_with(mock.ANY, mock.ANY, mock.ANY, mock.ANY, background, foreground)
+ generate_image_mock.assert_called_with(mock.ANY, mock.ANY, mock.ANY, mock.ANY, background, foreground, "png")
@mock.patch.object(Generator, '_generate_ascii')
def test_generate_inverted_ascii(self, generate_ascii_mock):
@@ -310,8 +322,8 @@ class GeneratorTest(unittest.TestCase):
generator.generate(data, 200, 200, inverted=True, output_format="ascii")
generate_ascii_mock.assert_called_with(mock.ANY, "-", "+")
- @mock.patch.object(Generator, '_generate_png')
- def test_generate_foreground(self, generate_png_mock):
+ @mock.patch.object(Generator, '_generate_image')
+ def test_generate_foreground(self, generate_image_mock):
"""
Tests if the foreground colour is picked correctly.
"""
@@ -327,15 +339,15 @@ class GeneratorTest(unittest.TestCase):
# result in foreground colour of index '1'.
data = "some test data"
generator.generate(data, 200, 200)
- generate_png_mock.assert_called_with(mock.ANY, mock.ANY, mock.ANY, mock.ANY, foreground[1], background)
+ generate_image_mock.assert_called_with(mock.ANY, mock.ANY, mock.ANY, mock.ANY, foreground[1], background, "png")
# The first byte of hex digest should be 149 for this data, which should
# result in foreground colour of index '5'.
data = "some other test data"
generator.generate(data, 200, 200)
- generate_png_mock.assert_called_with(mock.ANY, mock.ANY, mock.ANY, mock.ANY, foreground[5], background)
+ generate_image_mock.assert_called_with(mock.ANY, mock.ANY, mock.ANY, mock.ANY, foreground[5], background, "png")
- def test_generate_png_compare(self):
+ def test_generate_image_compare(self):
"""
Tests generated PNG identicon against a set of pre-generated samples.
"""
@@ -359,10 +371,10 @@ class GeneratorTest(unittest.TestCase):
height = 200
padding = (20, 20, 20, 20)
- # Load the reference images, making sure they're in RGB mode.
- test1_ref = PIL.Image.open("tests/samples/test1.png").convert(mode="RGB")
- test2_ref = PIL.Image.open("tests/samples/test2.png").convert(mode="RGB")
- test3_ref = PIL.Image.open("tests/samples/test3.png").convert(mode="RGB")
+ # Load the reference images, making sure they're in RGBA mode.
+ test1_ref = PIL.Image.open("tests/samples/test1.png").convert(mode="RGBA")
+ test2_ref = PIL.Image.open("tests/samples/test2.png").convert(mode="RGBA")
+ test3_ref = PIL.Image.open("tests/samples/test3.png").convert(mode="RGBA")
# Set-up the Generator.
generator = Generator(5, 5, foreground=foreground, background=background)
@@ -389,7 +401,7 @@ class GeneratorTest(unittest.TestCase):
# Verify that all the diffs are essentially black (i.e. no differences
# between generated identicons and reference samples).
- expected_extrema = ((0, 0), (0, 0), (0, 0))
+ expected_extrema = ((0, 0), (0, 0), (0, 0), (0, 0))
self.assertEqual(diff1.getextrema(), expected_extrema)
self.assertEqual(diff2.getextrema(), expected_extrema)