From 5985def06b5684ce78d0b2b783291f14ff5a5993 Mon Sep 17 00:00:00 2001 From: Bryan Veloso Date: Wed, 2 Nov 2011 13:49:17 +0900 Subject: [PATCH 1/8] Back to dev. --- imagekit/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imagekit/__init__.py b/imagekit/__init__.py index 93b5287..47d15b3 100644 --- a/imagekit/__init__.py +++ b/imagekit/__init__.py @@ -1,4 +1,4 @@ __title__ = 'django-imagekit' __author__ = 'Justin Driscoll, Bryan Veloso, Greg Newman, Chris Drackett, Matthew Tretter, Eric Eldredge' -__version__ = (1, 0, 1, 'final', 0) +__version__ = (1, 1, 0, 'dev', 0) __license__ = 'BSD' From d36e624acb349b3fd78bb3fb91ba0bcc696719c2 Mon Sep 17 00:00:00 2001 From: deepakprakash Date: Wed, 2 Nov 2011 14:25:22 +0530 Subject: [PATCH 2/8] Fix conversion of PNG "palette" or "P" mode images to JPEG. "P" mode images need to be converted to 'RGB' if target image format is not PNG or GIF. --- imagekit/utils.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/imagekit/utils.py b/imagekit/utils.py index 637433e..2c72185 100644 --- a/imagekit/utils.py +++ b/imagekit/utils.py @@ -10,10 +10,11 @@ def img_to_fobj(img, format, **kwargs): tmp = tempfile.TemporaryFile() # Preserve transparency if the image is in Pallette (P) mode. - if img.mode == 'P': + transparency_formats = ('PNG', 'GIF', ) + if img.mode == 'P' and format in transparency_formats: kwargs['transparency'] = len(img.split()[-1].getcolors()) else: - img.convert('RGB') + img = img.convert('RGB') img.save(tmp, format, **kwargs) tmp.seek(0) From 14bac58373d87ab4d90879b1654b62bf89603bc4 Mon Sep 17 00:00:00 2001 From: Matthew Tretter Date: Wed, 2 Nov 2011 11:26:24 -0400 Subject: [PATCH 3/8] On-demand loading of PIL plugins --- imagekit/models.py | 39 +++++++++++++---------- imagekit/utils.py | 79 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+), 16 deletions(-) diff --git a/imagekit/models.py b/imagekit/models.py index 435d58b..e5ed1bb 100755 --- a/imagekit/models.py +++ b/imagekit/models.py @@ -10,7 +10,9 @@ from django.db.models.signals import post_save, post_delete from django.utils.encoding import force_unicode, smart_str from imagekit.lib import Image, ImageFile -from imagekit.utils import img_to_fobj, get_spec_files, open_image +from imagekit.utils import img_to_fobj, get_spec_files, open_image, \ + format_to_extension, extension_to_format, UnknownFormatError, \ + UnknownExtensionError from imagekit.processors import ProcessorPipeline # Modify image file buffer size. @@ -95,24 +97,26 @@ class ImageSpec(_ImageSpecMixin): dispatch_uid='%s.delete' % uid) -def get_registered_extensions(): - Image.preinit() - return Image.EXTENSION - - def _get_suggested_extension(name, format): - if format: - # Try to look up an extension by the format. - extensions = [k for k, v in get_registered_extensions().iteritems() \ - if v == format.upper()] - else: - extensions = [] original_extension = os.path.splitext(name)[1] - if not extensions or original_extension.lower() in extensions: - # If the original extension matches the format, use it. + try: + suggested_extension = format_to_extension(format) + except UnknownFormatError: extension = original_extension else: - extension = extensions[0] + if suggested_extension.lower() == original_extension.lower(): + extension = original_extension + else: + try: + original_format = extension_to_format(original_extension) + except UnknownExtensionError: + extension = suggested_extension + else: + # If the formats match, give precedence to the original extension. + if format.lower() == original_format.lower(): + extension = original_extension + else: + extension = suggested_extension return extension @@ -129,7 +133,10 @@ class _ImageSpecFileMixin(object): # The extension is explicit, so assume they want the matching format. extension = os.path.splitext(filename)[1].lower() # Try to guess the format from the extension. - format = get_registered_extensions().get(extension) + try: + format = extension_to_format(extension) + except UnknownExtensionError: + pass format = format or img.format or original_format or 'JPEG' if format != 'JPEG': diff --git a/imagekit/utils.py b/imagekit/utils.py index 2c72185..9f681b6 100644 --- a/imagekit/utils.py +++ b/imagekit/utils.py @@ -50,3 +50,82 @@ def _wrap_copy(f): pass return img return copy + + +class UnknownExtensionError(Exception): + pass + + +class UnknownFormatError(Exception): + pass + + +_pil_init = 0 + + +def _preinit_pil(): + """Loads the standard PIL file format drivers. Returns True if ``preinit()`` + was called (and there's a potential that more drivers were loaded) or False + if there is no possibility that new drivers were loaded. + + """ + global _pil_init + if _pil_init < 1: + Image.preinit() + _pil_init = 1 + return True + return False + + +def _init_pil(): + """Loads all PIL file format drivers. Returns True if ``init()`` was called + (and there's a potential that more drivers were loaded) or False if there is + no possibility that new drivers were loaded. + + """ + global _pil_init + _preinit_pil() + if _pil_init < 2: + Image.init() + _pil_init = 2 + return True + return False + + +def _extension_to_format(extension): + return Image.EXTENSION.get(extension.lower()) + + +def _format_to_extension(format): + for k, v in Image.EXTENSION.iteritems(): + if v == format.upper(): + return k + return None + + +def extension_to_format(extension): + """Returns the format that corresponds to the provided extension. + + """ + format = _extension_to_format(extension) + if not format and _preinit_pil(): + format = _extension_to_format(extension) + if not format and _init_pil(): + format = _extension_to_format(extension) + if not format: + raise UnknownExtensionError(extension) + return format + + +def format_to_extension(format): + """Returns the first extension that matches the provided format. + + """ + extension = _format_to_extension(format) + if not extension and _preinit_pil(): + extension = _format_to_extension(format) + if not extension and _init_pil(): + extension = _extension_to_format(extension) + if not extension: + raise UnknownFormatError(format) + return extension From f1b1f2ec7161dc72be1370be0e74c1ea8b58501c Mon Sep 17 00:00:00 2001 From: Matthew Tretter Date: Wed, 2 Nov 2011 12:21:45 -0400 Subject: [PATCH 4/8] Fix in `format_to_extension` mapping --- imagekit/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imagekit/utils.py b/imagekit/utils.py index 9f681b6..b6ca548 100644 --- a/imagekit/utils.py +++ b/imagekit/utils.py @@ -125,7 +125,7 @@ def format_to_extension(format): if not extension and _preinit_pil(): extension = _format_to_extension(format) if not extension and _init_pil(): - extension = _extension_to_format(extension) + extension = _format_to_extension(format) if not extension: raise UnknownFormatError(format) return extension From 0f7c400239ac88b020b129421fb2aa5b3433ceee Mon Sep 17 00:00:00 2001 From: Bryan Veloso Date: Thu, 3 Nov 2011 02:57:01 +0900 Subject: [PATCH 5/8] Basic tests for extension_to_format and format_to_extension. References #45. --- tests/core/tests.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/tests/core/tests.py b/tests/core/tests.py index dd83fce..36d7ae7 100644 --- a/tests/core/tests.py +++ b/tests/core/tests.py @@ -5,6 +5,7 @@ from django.core.files.base import ContentFile from django.db import models from django.test import TestCase +from imagekit import utils from imagekit.lib import Image from imagekit.models import ImageSpec from imagekit.processors import Adjust @@ -18,7 +19,6 @@ class Photo(models.Model): class IKTest(TestCase): - """ Base TestCase class. """ def generate_image(self): tmp = tempfile.TemporaryFile() Image.new('RGB', (800, 600)).save(tmp, 'JPEG') @@ -53,3 +53,19 @@ class IKTest(TestCase): def test_thumbnail_source_file(self): self.assertEqual( self.photo.thumbnail.source_file, self.photo.original_image) + + +class IKUtilsTest(TestCase): + def test_extension_to_format(self): + self.assertEqual(utils.extension_to_format('.jpeg'), 'JPEG') + self.assertEqual(utils.extension_to_format('.rgba'), 'SGI') + + with self.assertRaises(utils.UnknownExtensionError): + utils.extension_to_format('.txt') + + def test_format_to_extension_no_init(self): + self.assertEqual(utils.format_to_extension('PNG'), '.png') + self.assertEqual(utils.format_to_extension('ICO'), '.ico') + + with self.assertRaises(utils.UnknownFormatError): + utils.format_to_extension('TXT') From 026955711e22101306e11679114149ceb0bb3c44 Mon Sep 17 00:00:00 2001 From: Bryan Veloso Date: Thu, 3 Nov 2011 14:12:18 +0900 Subject: [PATCH 6/8] Adding a changelog. --- docs/changelog.rst | 28 ++++++++++++++++++++++++++++ docs/index.rst | 1 + 2 files changed, 29 insertions(+) create mode 100644 docs/changelog.rst diff --git a/docs/changelog.rst b/docs/changelog.rst new file mode 100644 index 0000000..5207f2b --- /dev/null +++ b/docs/changelog.rst @@ -0,0 +1,28 @@ +Changelog +========= + +v1.0.2 +------ + +- Added this changelog. + +- Enhanced extension detection, format detection, and conversion between the + two. This eliminates the reliance on an image being loaded into memory + beforehand in order to detect said image's extension. + +- Fixed a regression from the 0.4.x series in which ImageKit was unable to + convert a PNG file in ``P`` or "palette" mode to JPEG. + +v1.0.1 +------ + +- Minor fixes related to the rendering of `README.rst` as a reStructured + text file. + +- Fixed the included admin template not being found when ImageKit was and + the packaging of the included admin templates. + +v1.0 +---- + +- Initial release of the *new* field-based ImageKit API. diff --git a/docs/index.rst b/docs/index.rst index 01916fd..5e78c02 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -22,6 +22,7 @@ Digging Deeper .. toctree:: apireference + changelog Indices and tables From 44392b7b2456626a79b06cdf8aebe450d29644ad Mon Sep 17 00:00:00 2001 From: Bryan Veloso Date: Thu, 3 Nov 2011 14:15:03 +0900 Subject: [PATCH 7/8] Bumping version numbers. --- docs/conf.py | 4 ++-- imagekit/__init__.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 4005268..b8fd9cb 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -48,9 +48,9 @@ copyright = u'2011, Justin Driscoll, Bryan Veloso, Greg Newman, Chris Drackett & # built documents. # # The short X.Y version. -version = '1.0.1' +version = '1.0.2' # The full version, including alpha/beta/rc tags. -release = '1.0.1' +release = '1.0.2' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/imagekit/__init__.py b/imagekit/__init__.py index 47d15b3..ef5b0cb 100644 --- a/imagekit/__init__.py +++ b/imagekit/__init__.py @@ -1,4 +1,4 @@ __title__ = 'django-imagekit' __author__ = 'Justin Driscoll, Bryan Veloso, Greg Newman, Chris Drackett, Matthew Tretter, Eric Eldredge' -__version__ = (1, 1, 0, 'dev', 0) +__version__ = (1, 0, 2, 'final', 0) __license__ = 'BSD' From 5666a640f083890a5cf7c5359db18cdd1c410377 Mon Sep 17 00:00:00 2001 From: Bryan Veloso Date: Thu, 3 Nov 2011 14:16:08 +0900 Subject: [PATCH 8/8] Fixing some reST syntax. --- docs/changelog.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 5207f2b..faab49f 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -16,7 +16,7 @@ v1.0.2 v1.0.1 ------ -- Minor fixes related to the rendering of `README.rst` as a reStructured +- Minor fixes related to the rendering of ``README.rst`` as a reStructured text file. - Fixed the included admin template not being found when ImageKit was and