Possible Duplicate:
resize image on save
Am trying to create a thumbnail in django, am trying to build a custom class specifically to be used for generating thumbnails. As following
from cStringIO import StringIO
from PIL import Image
class Thumbnail(object):
SIZE = (50, 50)
def __init__(self, source):
self.source = source
self.output = None
def generate(self, size=None, fit=True):
if not size:
size = self.SIZE
if not isinstance(size, tuple):
raise TypeError('Thumbnail class: The size parameter must be an instance of a tuple.')
# resize properties
box = size
factor = 1
image = Image.open(self.source)
# Convert to RGB if necessary
if image.mode not in ('L', 'RGB'):
image = image.convert('RGB')
while image.size[0]/factor > 2*box[0] and image.size[1]*2/factor > 2*box[1]:
factor *=2
if factor > 1:
image.thumbnail((image.size[0]/factor, image.size[1]/factor), Image.NEAREST)
#calculate the cropping box and get the cropped part
if fit:
x1 = y1 = 0
x2, y2 = image.size
wRatio = 1.0 * x2/box[0]
hRatio = 1.0 * y2/box[1]
if hRatio > wRatio:
y1 = int(y2/2-box[1]*wRatio/2)
y2 = int(y2/2+box[1]*wRatio/2)
else:
x1 = int(x2/2-box[0]*hRatio/2)
x2 = int(x2/2+box[0]*hRatio/2)
image = image.crop((x1,y1,x2,y2))
#Resize the image with best quality algorithm ANTI-ALIAS
image.thumbnail(box, Image.ANTIALIAS)
# save image to memory
temp_handle = StringIO()
image.save(temp_handle, 'png')
temp_handle.seek(0)
self.output = temp_handle
return self
def get_output(self):
self.output.seek(0)
return self.output.read()
the purpose of the class is so i can use it inside different locations to generate thumbnails on the fly. The class works perfectly, I've tested it directly under a view.. I've implemented the thumbnail class inside the save method of the forms to resize the original images on saving.
in my design, I have two fields for thumbnails. I was able to generate one thumbnail, if I try to generate two it crashes and I've been stuck for hours not sure whats the problem.
Here is my model
class Image(models.Model):
article = models.ForeignKey(Article)
title = models.CharField(max_length=100, null=True, blank=True)
src = models.ImageField(upload_to='publication/image/')
r128 = models.ImageField(upload_to='publication/image/128/', blank=True, null=True)
r200 = models.ImageField(upload_to='publication/image/200/', blank=True, null=True)
uploaded_at = models.DateTimeField(auto_now=True)
Here is my forms
class ImageForm(models.ModelForm):
"""
"""
class Meta:
model = Image
fields = ('src',)
def save(self, commit=True):
instance = super(ImageForm, self).save(commit=True)
instance.r128 = SimpleUploadedFile(
instance.src.name,
Thumbnail(instance.src).generate((128, 128)).get_output(),
content_type='image/png'
)
instance.r200 = SimpleUploadedFile(
instance.src.name,
Thumbnail(instance.src).generate((200, 200)).get_output(),
content_type='image/png'
)
if commit:
instance.save()
return instance
the strange part is, when i remove the line which contains instance.r200 in the form save. It works fine, and it does the thumbnail and stores it successfully. Once I add the second thumbnail it fails..
Any ideas what am doing wrong here?
Thanks
Update:
as per the comment request, am appending the error trace
IOError at /en/publication/new/
cannot identify image file
Request Method: POST
Request URL: http://127.0.0.1:8000/en/publication/new/?image-extra=
Django Version: 1.4.2
Exception Type: IOError
Exception Value:
cannot identify image file
Exception Location: /Users/mo/Projects/pythonic/snowflake-env/lib/python2.7/site-packages/PIL/Image.py in open, line 1980
Python Executable: /Users/mo/Projects/pythonic/snowflake-env/bin/python
Python Version: 2.7.2
Update
Tried to create print statement and below is the output
Source: publication/image/tumblr_m9o7244nZM1rykg1io1_1280_11.jpg
Source: publication/image/tumblr_m9o7244nZM1rykg1io1_1280_11.jpg
ERROR:root:cannot identify image file
ERROR:django.request:Internal Server Error: /en/publication/new/
Traceback (most recent call last):
File "/Users/mo/Projects/pythonic/snowflake-env/lib/python2.7/site-packages/django/core/handlers/base.py", line 111, in get_response
response = callback(request, *callback_args, **callback_kwargs)
File "/Users/mo/Projects/pythonic/snowflake-env/lib/python2.7/site-packages/django/contrib/auth/decorators.py", line 20, in _wrapped_view
return view_func(request, *args, **kwargs)
File "/Users/mo/Projects/pythonic/snowflake-env/lib/python2.7/site-packages/django/db/transaction.py", line 209, in inner
return func(*args, **kwargs)
File "/Users/mo/Projects/pythonic/snowflake-env/snowflake/snowflake/apps/publication/views.py", line 69, in new
formset.save()
File "/Users/mo/Projects/pythonic/snowflake-env/lib/python2.7/site-packages/django/forms/models.py", line 497, in save
return self.save_existing_objects(commit) + self.save_new_objects(commit)
File "/Users/mo/Projects/pythonic/snowflake-env/lib/python2.7/site-packages/django/forms/models.py", line 628, in save_new_objects
self.new_objects.append(self.save_new(form, commit=commit))
File "/Users/mo/Projects/pythonic/snowflake-env/lib/python2.7/site-packages/django/forms/models.py", line 727, in save_new
obj = form.save(commit=False)
File "/Users/mo/Projects/pythonic/snowflake-env/snowflake/snowflake/apps/publication/forms.py", line 113, in save
Thumbnail(instance.src).generate((200, 200)).get_output(),
File "/Users/mo/Projects/pythonic/snowflake-env/snowflake/snowflake/apps/core/utils.py", line 23, in generate
image = Image.open(self.source)
File "/Users/mo/Projects/pythonic/snowflake-env/lib/python2.7/site-packages/PIL/Image.py", line 1980, in open
raise IOError("cannot identify image file")
IOError: cannot identify image file
As seen, the first image is printed and processed successfully the second image is failing.
update
traceback error update after applying the copy() in the thumbnail class
ERROR:root:cannot identify image file
ERROR:django.request:Internal Server Error: /en/publication/new/
Traceback (most recent call last):
File "/Users/mo/Projects/pythonic/snowflake-env/lib/python2.7/site-packages/django/core/handlers/base.py", line 111, in get_response
response = callback(request, *callback_args, **callback_kwargs)
File "/Users/mo/Projects/pythonic/snowflake-env/lib/python2.7/site-packages/django/contrib/auth/decorators.py", line 20, in _wrapped_view
return view_func(request, *args, **kwargs)
File "/Users/mo/Projects/pythonic/snowflake-env/lib/python2.7/site-packages/django/db/transaction.py", line 209, in inner
return func(*args, **kwargs)
File "/Users/mo/Projects/pythonic/snowflake-env/snowflake/snowflake/apps/publication/views.py", line 69, in new
formset.save()
File "/Users/mo/Projects/pythonic/snowflake-env/lib/python2.7/site-packages/django/forms/models.py", line 497, in save
return self.save_existing_objects(commit) + self.save_new_objects(commit)
File "/Users/mo/Projects/pythonic/snowflake-env/lib/python2.7/site-packages/django/forms/models.py", line 628, in save_new_objects
self.new_objects.append(self.save_new(form, commit=commit))
File "/Users/mo/Projects/pythonic/snowflake-env/lib/python2.7/site-packages/django/forms/models.py", line 727, in save_new
obj = form.save(commit=False)
File "/Users/mo/Projects/pythonic/snowflake-env/snowflake/snowflake/apps/publication/forms.py", line 113, in save
f128.write(Thumbnail(instance.src).generate((128, 128)).get_output())
File "/Users/mo/Projects/pythonic/snowflake-env/snowflake/snowflake/apps/core/utils.py", line 15, in __init__
self._pilImage = Image.open(self.source)
File "/Users/mo/Projects/pythonic/snowflake-env/lib/python2.7/site-packages/PIL/Image.py", line 1980, in open
raise IOError("cannot identify image file")
IOError: cannot identify image file
Update
Finally, I managed to get it to work, but I had to stream the file into self.source as belo
def __init__(self, source):
self.source = StringIO(file(source.path, "rb").read())
self.output = None
self._pilImage = Image.open(self.source)
is the above ideal approach? is it a good idea to read the file at each hit? if no, what are my alternatives?