Skip to content

Runtime performance imporovements #6

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
11 changes: 9 additions & 2 deletions imagefit/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,22 @@ class Settings(LazySettings):
# cache backend name
IMAGEFIT_CACHE_BACKEND_NAME = getattr(settings, 'IMAGEFIT_CACHE_NAME', 'imagefit')

settings.CACHES = {
if hasattr(settings, "CACHES"):
caches = settings.CACHES
else:
caches = {}
settings.CACHES = caches
caches.update({
IMAGEFIT_CACHE_BACKEND_NAME: {
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
'LOCATION': os.path.join(tempfile.gettempdir(), 'django_imagefit')
}
}
})

# ConditionalGetMiddleware is required for browser caching
if not 'django.middleware.http.ConditionalGetMiddleware' in settings.MIDDLEWARE_CLASSES:
settings.MIDDLEWARE_CLASSES += ('django.middleware.http.ConditionalGetMiddleware',)

IMAGEFIT_FORMAT_SETTINGS = getattr(settings, "IMAGEFIT_FORMAT_SETTINGS", {"JPEG": {"quality":85}})

settings = Settings()
51 changes: 44 additions & 7 deletions imagefit/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from imagefit.conf import settings
from PIL import Image as PilImage


import mimetypes
try:
import StringIO
Expand All @@ -18,14 +19,30 @@ class Image(object):

def __init__(self, path, cache=None, cached_name=None, *args, **kwargs):
self.path = path
self.pil = PilImage.open(path)
self.pil_ = None
self.cache = cache
self.cached_name = cached_name

# force RGB
if self.pil.mode not in ('L', 'RGB'):
self.pil = self.pil.convert('RGB')


@property
def pil(self):
"""
Load the actual image object only on demand - these can get big.
"""

if self.pil_ is None:
self.pil_ = PilImage.open(self.path)
# force RGB
if self.pil_.mode not in ('L', 'RGBA'):
self.pil_ = self.pil_.convert('RGBA')

return self.pil_

@pil.setter
def pil(self, value):
self.pil_ = value

@property
def mimetype(self):
return mimetypes.guess_type(self.path)[0]
Expand Down Expand Up @@ -73,18 +90,38 @@ def render(self):
return self.cache.get(self.cached_name)
else:
image_str = StringIO.StringIO()
# not much other supports than png, yet works
self.pil.save(image_str, 'png')
ext = self.extension
self.pil.save(image_str, ext, **settings.IMAGEFIT_FORMAT_SETTINGS.get(ext, {}))
return image_str.getvalue()

@property
def extension(self):
ext = os.path.splitext(self.cached_name)[1].lower()

try:
fmt = PilImage.EXTENSION[ext]
except KeyError:
PilImage.init()
try:
fmt = PilImage.EXTENSION[ext]
except KeyError:
fmt = "JPEG"
#raise KeyError(ext) # unknown extension
if not fmt:
fmt = "JPEG"

print(fmt)
return fmt

def save(self):
"""
Save the image to the cache if provided and not cached yet.
"""
if self.cache and not self.is_cached:
image_str = StringIO.StringIO()
# not much other supports than png, yet works
self.pil.save(image_str, 'png')
ext = self.extension
self.pil.save(image_str, ext, **settings.IMAGEFIT_FORMAT_SETTINGS.get(ext, {}))
self.cache.set(self.cached_name, image_str.getvalue())
image_str.close()

Expand Down
11 changes: 11 additions & 0 deletions imagefit/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@
from django.core.cache import get_cache
from django.utils.http import http_date

from django.http import Http404, HttpResponse, HttpResponseNotModified
from django.views.static import was_modified_since

from imagefit.conf import settings
from imagefit.models import Image, Presets

import os
import stat


cache = get_cache(settings.IMAGEFIT_CACHE_BACKEND_NAME)
Expand All @@ -33,6 +37,13 @@ def resize(request, path_name, format, url):
url = url[1:]
# generate Image instance
image = Image(path=os.path.join(prefix, url))
if not os.path.exists(image.path):
return HttpResponse(status=404)

statobj = os.stat(image.path)
if not was_modified_since(request.META.get('HTTP_IF_MODIFIED_SINCE'),
statobj[stat.ST_MTIME], statobj[stat.ST_SIZE]):
return HttpResponseNotModified(mimetype=image.mimetype)

if settings.IMAGEFIT_CACHE_ENABLED:
image.cache = cache
Expand Down