Skip to content

Commit

Permalink
undermythumb now fingerprints images before storage.
Browse files Browse the repository at this point in the history
  • Loading branch information
mattdennewitz committed Jan 11, 2012
1 parent afa836e commit 3d3b2ff
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 80 deletions.
22 changes: 13 additions & 9 deletions exampleproject/blog/models.py
Expand Up @@ -8,21 +8,25 @@ class BlogPost(models.Model):
title = models.CharField(max_length=100)

# an image with thumbnails
artwork = ImageWithThumbnailsField(max_length=255,
upload_to='artwork/',
thumbnails=(('homepage_image', CropRenderer(300, 150)),
('pagination_image', CropRenderer(150, 75))),
help_text='Source artwork. Thumbnails automatically generated from this field.')
artwork = ImageWithThumbnailsField(
max_length=255,
upload_to='artwork/',
blank=True,
thumbnails=(('homepage_image', CropRenderer(300, 150)),
('pagination_image', CropRenderer(150, 75))),
help_text='Source artwork. Thumbnails automatically generated '
'from this field.')

# an override field, capable of rolling up a path
# when it has no value. useful for overriding
# when it has no value. useful for overriding
# auto-generated thumbnails. the fallback path
# should point to an ImageFieldFile of some sort.
#
# under the hood, this is just an ImageField
homepage_image = ImageFallbackField(fallback_path='artwork.thumbnails.homepage_image',
upload_to='artwork/',
help_text='Optional override for "homepage_image" thumbnail.')
homepage_image = ImageFallbackField(
fallback_path='artwork.thumbnails.homepage_image',
upload_to='artwork/',
help_text='Optional override for "homepage_image" thumbnail.')

def __unicode__(self):
return self.title
32 changes: 27 additions & 5 deletions undermythumb/fields.py
Expand Up @@ -3,7 +3,6 @@
from django.db.models.fields.files import (ImageField,
ImageFieldFile,
ImageFileDescriptor)
from django.utils.encoding import force_unicode

from undermythumb.files import (ThumbnailFieldFile,
ImageWithThumbnailsFieldFile)
Expand Down Expand Up @@ -98,10 +97,33 @@ def __init__(self, thumbnails=None, fallback_path=None, *args, **kwargs):
self.thumbnails = thumbnails or []
self.fallback_path = fallback_path

def get_thumbnail_filename(self, instance, original, key, ext):
# return filename
base, _ext = os.path.splitext(force_unicode(original))
return '%s-%s%s' % (base, key, ext)
def get_thumbnail_filename(self, instance, original_file,
thumbnail_name, ext):
"""Generates a predictable thumbnail filename.
Thumbnail generation follows this template: ::
{thumbnail_name}.{source file hash}.{ext}
Place no expensive calculations here -- this runs any
time a thumbnail field is accessed.
:param instance: Model instance containing the field
:param original_file: Uploaded image file
:param thumbnail_name: Model instance field name
:param ext: File extension *with* '.' separator.
"""

path = os.path.dirname(original_file.name)
hash_value, _ = os.path.splitext(os.path.basename(original_file.name))

filename = '%(thumbnail)s.%(hash)s%(ext)s' % {
'path': path,
'thumbnail': thumbnail_name,
'hash': hash_value,
'ext': ext}

return os.path.join(path, filename)

def south_field_triple(self):
"""Return a description of this field for South.
Expand Down
40 changes: 25 additions & 15 deletions undermythumb/files.py
@@ -1,3 +1,6 @@
from hashlib import sha1
import os

from django.db.models.fields.files import ImageFieldFile


Expand All @@ -24,20 +27,20 @@ def _populate(self):
key = attname
ext = '.%s' % renderer.format

name = self.field.get_thumbnail_filename(
instance=self.instance,
original=self.file,
key=key,
ext=ext)
name = self.field.get_thumbnail_filename(
instance=self.instance,
original_file=self.file,
thumbnail_name=key,
ext=ext)

thumbnail = ThumbnailFieldFile(
attname,
renderer,
self.instance,
self.field,
name)
thumbnail = ThumbnailFieldFile(
attname,
renderer,
self.instance,
self.field,
name)

self._cache[attname] = thumbnail
self._cache[attname] = thumbnail

def clear_cache(self):
self._cache = {}
Expand Down Expand Up @@ -74,13 +77,20 @@ def __init__(self, *args, **kwargs):
self.thumbnails = ThumbnailSet(self)

def save(self, name, content, save=True):
"""Save the original image, and its thumbnails.
"""
# set file name to first 8 chars of hash of contents
_, ext = os.path.splitext(name)
file_hash = sha1(content.read()).hexdigest()[:8]
name = file_hash + ext

# save source file
super(ImageWithThumbnailsFieldFile, self).save(name, content, save)

self.thumbnails.clear_cache()

# iterate over thumbnail
for thumbnail in self.thumbnails:
rendered = thumbnail.renderer.generate(content)
self.field.storage.save(thumbnail.name, rendered)
setattr(self.instance, self.field.attname, thumbnail.name)

if save:
self.instance.save()
51 changes: 0 additions & 51 deletions undermythumb/thumbnails.py

This file was deleted.

0 comments on commit 3d3b2ff

Please sign in to comment.