django-imagekit/imagekit/utils.py
2012-02-13 22:12:07 -05:00

212 lines
5.9 KiB
Python

import tempfile
import types
from django.db.models.loading import cache
from django.utils.functional import wraps
from .imagecache import get_default_image_cache_backend
from .lib import Image, ImageFile
def img_to_fobj(img, format, **kwargs):
tmp = tempfile.TemporaryFile()
try:
img.save(tmp, format, **kwargs)
except IOError:
# PIL can have problems saving large JPEGs if MAXBLOCK isn't big enough,
# So if we have a problem saving, we temporarily increase it. See
# http://github.com/jdriscoll/django-imagekit/issues/50
old_maxblock = ImageFile.MAXBLOCK
ImageFile.MAXBLOCK = img.size[0] * img.size[1]
try:
img.save(tmp, format, **kwargs)
finally:
ImageFile.MAXBLOCK = old_maxblock
tmp.seek(0)
return tmp
def get_spec_files(instance):
try:
return instance._ik.spec_files
except AttributeError:
return []
def open_image(target):
target.seek(0)
img = Image.open(target)
img.copy = types.MethodType(_wrap_copy(img.copy), img, img.__class__)
return img
def _wrap_copy(f):
@wraps(f)
def copy(self):
img = f()
try:
img.app = self.app
except AttributeError:
pass
try:
img._getexif = self._getexif
except AttributeError:
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):
if 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 = None
if 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
def _get_models(apps):
models = []
for app_label in apps or []:
app = cache.get_app(app_label)
models += [m for m in cache.get_models(app)]
return models
def invalidate_app_cache(apps):
for model in _get_models(apps):
print 'Invalidating cache for "%s.%s"' % (model._meta.app_label, model.__name__)
for obj in model._default_manager.order_by('-pk'):
for f in get_spec_files(obj):
f.invalidate()
def validate_app_cache(apps, force_revalidation=False):
for model in _get_models(apps):
for obj in model._default_manager.order_by('-pk'):
model_name = '%s.%s' % (model._meta.app_label, model.__name__)
if force_revalidation:
print 'Invalidating & validating cache for "%s"' % model_name
else:
print 'Validating cache for "%s"' % model_name
for f in get_spec_files(obj):
if force_revalidation:
f.invalidate()
f.validate()
def autodiscover():
"""
Auto-discover INSTALLED_APPS imagespecs.py modules and fail silently when
not present. This forces an import on them to register any admin bits they
may want.
Copied from django.contrib.admin
"""
import copy
from django.conf import settings
from django.utils.importlib import import_module
from django.utils.module_loading import module_has_submodule
from .templatetags import imagekit_tags
for app in settings.INSTALLED_APPS:
mod = import_module(app)
# Attempt to import the app's admin module.
try:
import_module('%s.imagespecs' % app)
except:
# Decide whether to bubble up this error. If the app just
# doesn't have an admin module, we can ignore the error
# attempting to import it, otherwise we want it to bubble up.
if module_has_submodule(mod, 'imagespecs'):
raise
class SpecWrapper(object):
"""
Wraps a user-defined spec object so we can access properties that don't
exist without errors.
"""
def __init__(self, spec):
self.processors = getattr(spec, 'processors', None)
self.format = getattr(spec, 'format', None)
self.options = getattr(spec, 'options', None)
self.autoconvert = getattr(spec, 'autoconvert', True)
self.storage = getattr(spec, 'storage', None)
self.image_cache_backend = getattr(spec, 'image_cache_backend', None) \
or get_default_image_cache_backend()