Changeset - 93602620893a
[Not reviewed]
0 2 0
Branko Majic (branko) - 9 years ago 2016-12-03 15:07:14
branko@majic.rs
PYD-7: Updated code to allow passing-in image format for Pillow. This allows generating non-PNG identicons. Tests have been updated to cover the new use-case.
2 files changed with 43 insertions and 26 deletions:
0 comments (0 inline, 0 general)
pydenticon/__init__.py
Show inline comments
 
@@ -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,9 +212,12 @@ 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.
 
@@ -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)
tests/test_pydenticon.py
Show inline comments
 
@@ -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)
 
@@ -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.
 
        """
0 comments (0 inline, 0 general)