mirror of
https://github.com/Hopiu/django-imagekit.git
synced 2026-03-17 05:40:25 +00:00
Merge branch 'release/1.0.2'
* release/1.0.2: Fixing some reST syntax. Bumping version numbers. Adding a changelog. Basic tests for extension_to_format and format_to_extension. References #45. Fix in `format_to_extension` mapping On-demand loading of PIL plugins 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. Back to dev.
This commit is contained in:
commit
3fd2450e8d
7 changed files with 154 additions and 22 deletions
28
docs/changelog.rst
Normal file
28
docs/changelog.rst
Normal file
|
|
@ -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.
|
||||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ Digging Deeper
|
|||
.. toctree::
|
||||
|
||||
apireference
|
||||
changelog
|
||||
|
||||
|
||||
Indices and tables
|
||||
|
|
|
|||
|
|
@ -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, 0, 2, 'final', 0)
|
||||
__license__ = 'BSD'
|
||||
|
|
|
|||
|
|
@ -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':
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -49,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 = _format_to_extension(format)
|
||||
if not extension:
|
||||
raise UnknownFormatError(format)
|
||||
return extension
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
|
|||
Loading…
Reference in a new issue