If in your image gallery or website home page, or even for a user profile image you have a fixed dimensions box to show thumbnails for the uploaded image.
consider this:
<div style="width:200px; height:200px; max-width:200px; overflow:hidden;"> <img src="{{=URL('default', 'download', args=article.image)}}" /> </div>
You will have a fixed 200x200 box to show the image, but what if the uploaded image is 1024x768 ?
An image with 1024x768
Obviously if you resize that to fit the 200x200 box, you will end with a streched image:
The same image as above, but redimensioned to 200x200, aspect is streched.
How to solve this using PIL
For this example I am going to use a fixed, hardcoded centered position. But with a cropper Javascript plugin you can pass coordinates to crop in another position.
1. Install PIL
pip install pil or sudo apt-get install python-imaging
2. In a module create a function to crop the image.
yourapp/modules/smarthumb.py
from gluon import current import os try: from PIL import Image except: import Image def SMARTHUMB(image, box, fit=True, name="thumb"): '''Downsample the image. @param img: Image - an Image-object @param box: tuple(x, y) - the bounding box of the result image @param fit: boolean - crop the image to fill the box ''' if image: request = current.request img = Image.open(request.folder + 'uploads/' + image) #preresize image with factor 2, 4, 8 and fast algorithm factor = 1 while img.size[0] / factor > 2 * box[0] and img.size[1] * 2 / factor > 2 * box[1]: factor *= 2 if factor > 1: img.thumbnail((img.size[0] / factor, img.size[1] / factor), Image.NEAREST) #calculate the cropping box and get the cropped part if fit: x1 = y1 = 0 x2, y2 = img.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) img = img.crop((x1, y1, x2, y2)) #Resize the image with best quality algorithm ANTI-ALIAS img.thumbnail(box, Image.ANTIALIAS) root, ext = os.path.splitext(image) thumb = '%s_%s%s' % (root, name, ext) img.save(request.folder + 'uploads/' + thumb) return thumb
3. Now take this sample model.
yourapp/models/db.py
db = DAL('youconnectionstring') Article = db.define_table('article', Field("title"), Field("article_text", "text"), Field("picture", "upload"), Field("thumbnail", "upload") )
Note that in the model we defined an Article object, which points us to a dal Table db.article, this table has two fields of type "upload", the idea is that the user will upload the file in "picture" fields and we are going to create the thumbnail authomatically.
4. Define the computation for "thumbnail" field in the same file, right after the table definition
from smarthumb import SMARTHUMB box = (200, 200) Article.thumbnail.compute = lambda row: SMARTHUMB(row.picture, box)
In the above code we are defining that when the FORM gets processed, DAL will compute the value for "thumbnail" field. The computed value will be the result of the "lambda' function we passed to field's compute attribute, in that case we are taking the submitted row and passing the uploaded picture (note that web2py will pass in the path to uploaded image) and also we are passing a box tuple of 200x200 to fit our thumbs div.
5. Create a form and test the result
yourapp/controllers/default.py
def addarticle(): form = SQLFORM(Article).process() return dict(form=form) def showarticle(): id = request.args(0) or redirect(URL('default', 'index')) article = Article[id] return dict(article=article)
6. Now you can create a view or just use the generic view for that.
yourapp/views/default/addarticle.html
<h1> Add an article </1> {{=form}}
7. A view to show the article
yourapp/views/default/showarticle.html
<article> <h1> {{=article.title}}</h1> <div style="width:200px; height:200px; max-width:200px; overflow:hidden;"> <img src="{{=URL('default', 'download', args=article.image)}}" /> </div> <p>{{=MARKMIN(article.article_text)}}</p> </article>
Now the end result will be:
Original uploaded 1024x768 image
The generated cropped and centered 200x200 thumbnail keeping the aspect of image.
So much better than the streched version no?
** also you can use http://src.sencha.io to improve the image exhibition
** web2py now includes gluon/contrib/imagetools.py maybe that function will go there also
Does anybody wants to contribute creating a plugin using JqueryCropper or anither JavaScript Crop plugin?
REFERENCE: http://united-coders.com/christian-harms/image-resizing-tips-general-and-for-python
Comments (12)
- Login to post
order by: newest oldest upvoted downvoted
- rochacbruno 12 years ago
show more comments0
adriano 12 years ago
Hi,
nice slice. I have been trying to do something like this for a couple of time.
Thanks
0
adriano 12 years ago
Questions:
Will it work on GAE?
on the 7th part of yout article, shouldn´t it be <img src="{{=URL('default', 'download', args=article.thumbnail)}}
0
rochacbruno 12 years ago
I guess it will not work on GAE, since PIL does not runs on GAE. GAE has its own image lib.
0
christian-harms-10713 12 years ago
If you copy shameless python code for other sites - the internet never forget. Please add a link to the original article:
http://united-coders.com/christian-harms/image-resizing-tips-general-and-for-python
And here a copy + link on stackoverflow:
http://stackoverflow.com/questions/273946/how-do-i-resize-an-image-using-pil-and-maintain-its-aspect-ratio
Thanx!
replies (1)
0
rochacbruno 12 years ago
I did not copied this code form that site. I got parts of the code from a student which has sent for me via e-mail.
I am going to include your links on the post.
Thanks