Resize images on demand

288 views
Skip to first unread message

Michel Thadeu Sabchuk

unread,
Apr 17, 2007, 2:54:20 PM4/17/07
to Django developers
Hi guys!

I done a cool functionality to my site, the possibility to resize
images on demand. It's not 100% done yet but my goal is to do
something like:

...
class Article(models.Model):
photo = models.ImageField(upload_to='some/path/some/where')
def get_photo_200x200(self):
return self.get_photo_miniature(200, 200)
...

The method self.get_photo_miniature will work like get_photo_url, but
it receives the limits of the image miniature, this method check if
there is a file called some/path/some/where/photo_200x200.jpg
(supposing the image filename is photo.jpg). If this file exists,
returns the proper url to it, if not, it resizes the image and store
on this file to then return the miniature url.

I need PIL to this work, but it works a pretty way. The above is
working for me, but the custom method get_photo_miniature is defined
on my model. I want to know if this is a useful feature, then I can
dig up where to put this to make it generic.

Now that I done, I think I can do it another way, maybe using filters.
As images generally goes in templates, I can do something like:

...
<img src="{{ object.image|thumbnail:"200x200" }}">
...

I think you catch the idea. What do you think?
I sent a post about the problem of the filename being unique, I don't
bother about this anymore, I see that if I put 2 files with same name,
the files start to append a _ on the filename. But I still think the
upload_to keyword could receive id.

Thanks for all help, sorry if I was meaningless.

Jacob Kaplan-Moss

unread,
Apr 17, 2007, 2:56:15 PM4/17/07
to django-d...@googlegroups.com
Hey Michel --

Please direct questions of this nature to django-users; django-dev is
used to discuss the development of Django itself, not to answer usage
questions.

Thanks!

Jacob

Michel Thadeu Sabchuk

unread,
Apr 18, 2007, 12:02:35 PM4/18/07
to Django developers
Hi

Ok, sorry about that Jacob!
Thanks for pointing me at right place!

Best Regards,

chris....@gmail.com

unread,
Apr 18, 2007, 9:05:19 PM4/18/07
to Django developers
Just a question out to the developers-

Would you consider adding a thumbnail capability to Django? I know
there are contributions out there that do it and the dependency on PIL
might be a negative but I believe this is a very common use case. How
many apps have an image field and don't use some sort of thumbnail? I
bet very few.

Having a standard integrated in Django would be a big plus IMHO.

-Chrus

Jacob Kaplan-Moss

unread,
Apr 18, 2007, 9:28:00 PM4/18/07
to django-d...@googlegroups.com
On 4/18/07, chris....@gmail.com <chris....@gmail.com> wrote:
> Would you consider adding a thumbnail capability to Django? I know
> there are contributions out there that do it and the dependency on PIL
> might be a negative but I believe this is a very common use case. How
> many apps have an image field and don't use some sort of thumbnail? I
> bet very few.

I'd be +1 on adding something as a contrib app. I've got some code we
use at work, but it'll likely be some time before I'm able to
generalize it enough for public consumption, so I'd be thrilled to see
an effort by a few committed community members...

Jacob

Michel Thadeu Sabchuk

unread,
Apr 19, 2007, 9:20:22 AM4/19/07
to Django developers
Hi Jacob, how are you?

> I'd be +1 on adding something as a contrib app. I've got some code we
> use at work, but it'll likely be some time before I'm able to
> generalize it enough for public consumption, so I'd be thrilled to see
> an effort by a few committed community members...

I done some code to implement it. Look at the following snippet:
http://www.djangosnippets.org/snippets/192/

I used filters to implement this task, did you like the filter
approach or do you think to have a method like
object.get_image_thumbnail on the model is better? I must confess that
use filter was easier to implement and it's easier to use too, I don't
realize how to specify the limits of the image once I can't send
parameters to the get_image_thumbnail method:

Now the questions (not about usage but about directioning :P):

1) What could be the name of the contrib package? Could it be in
webdesign?
2) What is the better approach? Do a filter or a custom method on the
model?
3) Should I create a ticket?

Best regards!

Michel Thadeu Sabchuk

unread,
Apr 19, 2007, 9:38:22 AM4/19/07
to Django developers
Hi guys,

On the user list I found a more complete solution:
http://code.google.com/p/django-utils/wiki/Thumbnail

Maybe this could be add as a contrib package?
Best regards!

Brett Parker

unread,
Apr 19, 2007, 10:32:38 AM4/19/07
to django-d...@googlegroups.com

I've got a chunk of code that's reasonably generic but needs some
tidying up and decoupling... it's just a template tag... can be found:

http://arch.sommitrealweird.co.uk/viewarch/iDu...@sommitrealweird.co.uk--websites/alug--mainline--0.1--patch-32/alug/general/helpers.py

for the main code and:

http://arch.sommitrealweird.co.uk/viewarch/iDu...@sommitrealweird.co.uk--websites/alug--mainline--0.1--patch-32/alug/general/templatetags/thumbnail.py

there for the actual template tag.

It saves the thumbnail to the filesystem when it needs to regenerate it,
and so should even be reasonably fast after the first access.

Thanks,
Brett Parker.

chris....@gmail.com

unread,
Apr 20, 2007, 11:42:25 AM4/20/07
to Django developers
I've started a page to discuss the different options here.

http://code.djangoproject.com/wiki/ThumbNails

-Chris

SmileyChris

unread,
Apr 22, 2007, 5:41:20 AM4/22/07
to Django developers
I put together my take on django.contib.thumbnails and posted it as a
patch
http://code.djangoproject.com/ticket/4115

Please read through the documentation and give some feedback.

chris....@gmail.com

unread,
Apr 22, 2007, 5:25:06 PM4/22/07
to Django developers
This is a really great patch. I read the patch but have not attempted
to use yet. Here are a couple of thoughts:
- I think the patch file itself may be a little messed up. I see that
several of the files are repeated. I could just be reading it wrong.
- Big positive in that you documented it so well!
- I like the fact that it's simple to create your own thumbnail
classes if necessary.
- Squash, crop and thumbnail are all very useful and I think it's
great to have all these available.
- This syntax looks just fine:
<img src="{{ object.imagefield|thumbnail:"150x100" }}" />

However, this feels a little bit clunky:
{% with object.imagefield|thumbnail:"150x100" as thumb %}
<img src="{{ thumb.url }}" width="{{ thumb.thumbnail.size.0 }}"
height="{{ thumb.size.1 }}" />
{% endwith %}

What if we had a shortcut like this:
{{ object.imagefield|thumbnail_full_tag:"150X100" }}

Which would generate:
<img src="source/file" width="150" height="100" />

- Also, one thing that is nice in Nesh's version is that it is easy to
cache thumbnails in memory. I think this would be a nice & fairly
simple thing to add.

Once again, really nice work. I look forward to seeing this in
Django. I think it would be really really useful.

-Chris


SmileyChris

unread,
Apr 22, 2007, 5:35:33 PM4/22/07
to Django developers
On Apr 23, 9:25 am, "chris.moff...@gmail.com"

<chris.moff...@gmail.com> wrote:
> This is a really great patch. I read the patch but have not attempted
> to use yet. Here are a couple of thoughts:
> - I think the patch file itself may be a little messed up. I see that
> several of the files are repeated. I could just be reading it wrong.
Probably is messed up. I use tortoiseSVN and have noticed that it
seems to mess up added files like that.

> - Big positive in that you documented it so well!

This is usually the way to a submitter's heart. ;)

> - I like the fact that it's simple to create your own thumbnail
> classes if necessary.
> - Squash, crop and thumbnail are all very useful and I think it's
> great to have all these available.

I made crop recently for another project - squash isn't quite so nice
but people may want it ;)

> - This syntax looks just fine:
> <img src="{{ object.imagefield|thumbnail:"150x100" }}" />
>
> However, this feels a little bit clunky:
> {% with object.imagefield|thumbnail:"150x100" as thumb %}
> <img src="{{ thumb.url }}" width="{{ thumb.thumbnail.size.0 }}"
> height="{{ thumb.size.1 }}" />
> {% endwith %}
>
> What if we had a shortcut like this:
> {{ object.imagefield|thumbnail_full_tag:"150X100" }}

I felt a bit hesitant to even add that to documentation - it was more
to show you can access the attributes of the thumbnail object (it's
probably superfluous).
Perhaps it would be better just provide an thumbnail_tag filter to
handle it.
I'd suggest a separate tag to handle it:
{{ object.imagefield|thumbnail_crop:"150X100"|thumbnail_tag }}

> - Also, one thing that is nice in Nesh's version is that it is easy to
> cache thumbnails in memory. I think this would be a nice & fairly
> simple thing to add.

I thought about this, started implementing it and then scrapped the
idea. IMO this is getting in to serving of static files, which
historically Django has tried to steer very clear of.
It wouldn't be difficult to do if it was deemed important enough.

> Once again, really nice work. I look forward to seeing this in
> Django. I think it would be really really useful.

Thanks for the feedback, greatly appreciated. Anyone else (especially
real testing)?

chris....@gmail.com

unread,
Apr 22, 2007, 10:08:30 PM4/22/07
to Django developers
I downloaded the patch and got it to work. I have a couple of
observations based on usage.

- If we continue to use the format "150x200" to specify the size, we
may want to do a string.lower() on the input. I originally had a
capital X and couldn't figure out what the problem was. Yeah, it's a
stupid mistake on my part but still....

- I'm a little fuzzy on the different methods and how they treat size
constraints. I understand if I set the width and leave height blank,
it should automatically calculate it once the thumb is created. I
would also expect that if I put in both, it's going to scale it and
lose the original aspect ratio.

In other words, I'd like to see some thing like:
picture|thumbnail"width=75"

which would create a picture with the same aspect ratio of width to
height.

If I entered
picture|thumbnail"width=75 height=25"
It should force the image to that size (I think that's what squish
does).

I hope this makes sense. I think the by product of making this
semantic change is that one tag would do thumbnail and crop.

Otherwise it all appeared to work well for me.

Oh yeah, upon thinking more about my comment on caching the image, I
think you're probably right. We should leave that in the category of
serving static media.

-Chris

Chris Beaven

unread,
Apr 22, 2007, 10:20:55 PM4/22/07
to django-d...@googlegroups.com
On 4/23/07, chris....@gmail.com <chris....@gmail.com> wrote:
>
> I downloaded the patch and got it to work. I have a couple of
> observations based on usage.
>
> - If we continue to use the format "150x200" to specify the size, we
> may want to do a string.lower() on the input. I originally had a
> capital X and couldn't figure out what the problem was. Yeah, it's a
> stupid mistake on my part but still....
Easy fix and good idea.

>
> - I'm a little fuzzy on the different methods and how they treat size
> constraints. I understand if I set the width and leave height blank,
> it should automatically calculate it once the thumb is created. I
> would also expect that if I put in both, it's going to scale it and
> lose the original aspect ratio.
>
> In other words, I'd like to see some thing like:
> picture|thumbnail"width=75"

You can't leave the width or height blank.

"scale" sizes the image down proportionally until it fits inside the
given dimensions so the thumbnail images may differ in their
dimensions (they'll either have the width or height - would you really
want an image to be scaled down to 75px width but still be 10,000px
high?)

"crop" cuts off parts of the image to make it take up exactly the
width and height you specify (but without skewing the image ratio like
"squash" does)

So we can't combine scale and crop, because they do different things.

chris....@gmail.com

unread,
Apr 23, 2007, 1:20:34 PM4/23/07
to Django developers
Ok, I think I'm understanding the distinction in your terminology. I
definitely don't want an image that 75x10,000. Here's my scenario:

Original Image 1 = 750 X 100, I would only like to specify that the
new image was 75 wide and let it figure out that the new height should
be 10 (preserve aspect ratio given the new width constraint).

Original Image 2 = 750 X 250, I'd like to convert it to 75 x 25

In other words, I want the width to always be 75 but the height can
vary based on the specifics of the image. Does this make sense? If
this is what I'd like to do, how would I do it with the tag as it
stands now?

-Chris

Michel Thadeu Sabchuk

unread,
Apr 23, 2007, 4:32:08 PM4/23/07
to Django developers
Hi guys!

I test your application and enjoy it SmileyChris, there is just a
bug :), contrib/thumbnails/templatestags/__init__.py is missing, a
"touch __init__.py" solves the problem ;) I like the way you return a
Thumbnail object reather than just the string.

Congratulations, very thanks to you!

Chris Beaven

unread,
Apr 23, 2007, 5:37:27 PM4/23/07
to django-d...@googlegroups.com
On 4/24/07, chris....@gmail.com <chris....@gmail.com> wrote:
> In other words, I want the width to always be 75 but the height can
> vary based on the specifics of the image. Does this make sense? If
> this is what I'd like to do, how would I do it with the tag as it
> stands now?

Well without specifying a maximum height too, you run the risk of that
75x10,000 image.
Choose a maximum height larger than probable:
<img src="{{ object.imagefield|thumbnail:"75x500" }}" />

chris....@gmail.com

unread,
Apr 23, 2007, 8:10:58 PM4/23/07
to Django developers
Fair enough. I think we've beaten this one to death and the current
solution works fine for me (with the additional minor tweaks we've
already mentioned).

Thanks,
Chris

chris....@gmail.com

unread,
May 15, 2007, 11:00:20 PM5/15/07
to Django developers
Chris,

I've been working on adding unit tests for this patch and hit a little
snag regarding the way the "size" is returned.

Say I have an image that is 640x512 and I create a thumbnail passing
in "240x240". The resulting thumbnail is scaled down to "240x192".
Which causes some confusing naming conventions ("retaining 240x240 in
the name) as well as making the height and width return incorrect
values (240 is returned for both the height and width)

I have a couple of ideas of how to fix this but I wanted to pass it by
you first and make sure I'm not off in the wrong direction here. Any
thoughts you'd have on fixing it the simplest way would be
appreciated.

Thanks,
Chris

Chris Beaven

unread,
May 15, 2007, 11:05:11 PM5/15/07
to django-d...@googlegroups.com
Hrm... I can see how the name could be a bit confusing, but the
reasoning is that that IS what the thumbnail was created with and
that's how it decides whether there is a thumbnail for it or not.

If you were to call it "240x192" then we wouldn't know that there was
an existing cached thumbnail until we did the hard work of recreating
it to get the dimensions.

Remember those values simply relate to the thumbnail method used, not
the output dimensions.

How were you planning on handling it?

chris....@gmail.com

unread,
May 15, 2007, 11:28:15 PM5/15/07
to Django developers
You raise good points about the overhead of computing size of the
file. My solution would have involved adding another property of the
object that would read the image and return the size. Probably very
very inefficient.

Maybe the filename needs to encode the actual size as well as the
specified size. Something like :
sample_pic_240x240_scale:240x192.jpg

It would make some of the file manipulation a little tricky but would
be more efficient by not calling PIL so much.


The other alternative might be to cache the file sizes and return it
that way. The benfit is that the filenames are cleaner but the
downside might be the complexity.

Chris Beaven

unread,
May 16, 2007, 4:58:18 AM5/16/07
to django-d...@googlegroups.com
> The other alternative might be to cache the file sizes and return it
> that way. The benfit is that the filenames are cleaner but the
> downside might be the complexity.

Or we just keep it the way it is ;)

Is there really that much benefit to having the thumbnail image
filename contain the actual dimensions? If someone cared that much,
they can use PIL (on the thumbnailed image) to find them out.

John Sutherland

unread,
May 16, 2007, 6:01:00 AM5/16/07
to django-d...@googlegroups.com
Morning,

Sorry, I'm a little late to join this discussion.

We have some code here (at Mercurytide[1]) which we use to generate
thumbnails by cropping and scaling images, results can be seen on the
bottom of the right column of:
<http://www.naelimits.co.uk/activities/stag-hen/>

I'll see what the chances of getting that code if anyone is interested
in this method.

Something we've also found useful is the ability to add "allow_tags"
to a function which generates an <img> tag to display thumbnails in
the admin listing pages, I'm not sure if that's documented, but it was
handy when we found it.

Cheers,
John.


[1] <http://mercurytide.com/>

--
john sutherland
<http://sneeu.com/>

Chris Beaven

unread,
May 16, 2007, 6:24:16 AM5/16/07
to django-d...@googlegroups.com
Hi John,

Probably the best thing to do is look at the contrib.thumbnails patch
and see if there's something you could add to it:
http://code.djangoproject.com/ticket/4115

chris....@gmail.com

unread,
May 16, 2007, 9:19:46 AM5/16/07
to Django developers
The most common use case is that someone wants to create the <img> tag
with the appropriate height and width. If the incorrect values are
put in, then the browser might try to scale the image which is not
what we want.

I'm not opposed to modifying the tag to return the actual size by
using PIL calls. It's probably not too big of a performance hit and
if people don't really want to use it they don't have to.

On May 16, 3:58 am, "Chris Beaven" <smileych...@gmail.com> wrote:

SmileyChris

unread,
May 17, 2007, 9:26:04 PM5/17/07
to Django developers
Right, check out the ticket again - new patch up.
http://code.djangoproject.com/ticket/4115

On May 17, 1:19 am, "chris.moff...@gmail.com"

chris....@gmail.com

unread,
May 17, 2007, 9:47:57 PM5/17/07
to Django developers
Cool.

I attached a simple patch that shows how I ended up solving the "size"
problem. I just realized there's a small bug in my cut & paste but
you can get the idea.

size_cache.set(self.filename, im.size, _SIZE_CACHE_TIMEOUT)
should be
size_cache.set(self.filename, img.size, _SIZE_CACHE_TIMEOUT)

I think this is a pretty simple solution to what we've discussed.
What do you think?

Also, I took a stab at creating some regression tests. Let me know if
you want to see them.

On May 17, 8:26 pm, SmileyChris <smileych...@gmail.com> wrote:
> Right, check out the ticket again - new patch up.http://code.djangoproject.com/ticket/4115

SmileyChris

unread,
May 20, 2007, 6:07:26 PM5/20/07
to Django developers
If any committer wants to look at it, I consider this patch feature-
complete (and has some unit tests now)

Reply all
Reply to author
Forward
0 new messages