diff --git a/sorl/thumbnail/engines/pil_engine.py b/sorl/thumbnail/engines/pil_engine.py index c2197aec0..8566dc56b 100644 --- a/sorl/thumbnail/engines/pil_engine.py +++ b/sorl/thumbnail/engines/pil_engine.py @@ -1,19 +1,42 @@ from __future__ import unicode_literals, division -import math from sorl.thumbnail.engines.base import EngineBase from sorl.thumbnail.compat import BufferIO try: - from PIL import Image, ImageFile, ImageDraw, ImageFilter + from PIL import Image, ImageFile, ImageDraw, ImageFilter, ImageMode except ImportError: import Image import ImageFile import ImageDraw + import ImageMode EXIF_ORIENTATION = 0x0112 +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. + """ + mode_descriptor = ImageMode.getmode(image.mode) + width, height = image.size + return width * height * len(mode_descriptor.bands) + + +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 round_corner(radius, fill): """Draw a round corner""" corner = Image.new('L', (radius, radius), 0) # (0, 0, 0, 0)) @@ -204,6 +227,9 @@ def _entropy_crop(self, image, geometry_width, geometry_height, image_width, ima return image + # Add the histogram_entropy fumnction as a static method: + _get_image_entropy = staticmethod(histogram_entropy) + def _scale(self, image, width, height): return image.resize((width, height), resample=Image.ANTIALIAS) @@ -261,10 +287,3 @@ def _get_raw_data(self, image, format_, quality, image_info=None, progressive=Fa bf.close() return raw_data - - def _get_image_entropy(self, image): - """calculate the entropy of an image""" - hist = image.histogram() - hist_size = sum(hist) - hist = [float(h) / hist_size for h in hist] - return -sum([p * math.log(p, 2) for p in hist if p != 0]) diff --git a/tests/thumbnail_tests/test_engines.py b/tests/thumbnail_tests/test_engines.py index fb08b047b..fda69a84b 100644 --- a/tests/thumbnail_tests/test_engines.py +++ b/tests/thumbnail_tests/test_engines.py @@ -340,9 +340,19 @@ def mean_pixel(x, y): for x, y in coords: self.assertEqual(0 <= mean_pixel(x, y) < 5, True) + @unittest.skipIf( + 'pil_engine' not in settings.THUMBNAIL_ENGINE, + 'the other engines fail this test', + ) def test_smart_crop(self): - # TODO: Complete test for smart crop - self.BACKEND.get_thumbnail('32x32', 'data/white_border.jpg', crop='smart') + th = self.BACKEND.get_thumbnail('data/white_border.jpg', '32x32', crop='smart') + self.assertEqual(th.x, 32) + self.assertEqual(th.y, 32) + + engine = PILEngine() + im = engine.get_image(th) + self.assertEqual(im.size[0], 32) + self.assertEqual(im.size[1], 32) @unittest.skipIf( 'pil_engine' not in settings.THUMBNAIL_ENGINE,