image resizing

288 views
Skip to first unread message

Warner Onstine

unread,
Feb 11, 2011, 6:42:49 PM2/11/11
to grails-startup...@googlegroups.com
Question for the other members out there. For my game I have the
ability for players to upload their profile pictures. I had waited to
develop a image resizing thing until we needed it, now we do. I
grabbed this one:
http://stackoverflow.com/questions/362360/image-resize-in-grails (the
very first answer)

I must say it is dog-slow on my laptop so I can only imagine what it
will be like on the server. Is the image tools plugin
(http://grails.org/ImageTools+plugin) faster?

Also, I'm trying to figure this next part out. Some players have
already uploaded pics, but now I want to use the smaller, scaled
version instead. Should I:
a) force them to reupload and I can scale and store the original and
the scaled copy
b) on subsequent calls to get the image look for a scaled image and if
it doesn't exist create, store and return?

We're only talking a few at this point. So a) might be a good option
and something to use going forward.

Thanks!

-warner

Pete Doyle

unread,
Feb 11, 2011, 7:45:37 PM2/11/11
to grails-startup-support-group
Hi Warner,
I've used the ImageTools plugin and not noticed any major performance
issues during development.  To be honest, I've never timed it so maybe
it is slow and I just haven't noticed.

Unfortunately, I've been really disappointed in the output quality of
anything using JAI (including ImageTool).  Here's a blog post which
shows an example the quality issues I'm seeing:
http://www.darcynorman.net/2005/03/15/jai-vs-imagemagick-image-resizing/.

In the end, I'll probably end up using ImageMagick, GraphicsMagick, or
possibly a service like TransloadIt.

For regenerating your images at a different size, maybe a quick Grails
Console script would help?
http://www.grails.org/plugin/console

Assuming you already have higher resolution copies, you could create a
script to walk through all your users, resize the photos, and store
both copies.

Good luck :)
Pete

> --
> You received this message because you are subscribed to the Google Groups "Grails Startup Support Group" group.
> To post to this group, send email to grails-startup...@googlegroups.com.
> To unsubscribe from this group, send email to grails-startup-suppo...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/grails-startup-support-group?hl=en.
>

Tomas Lin

unread,
Feb 11, 2011, 8:33:25 PM2/11/11
to grails-startup...@googlegroups.com
Hi Warner,

There is also a burningimage plugin which seeks to improve image
quality from imagetools. In our tests, Imagetools simply did not give
us the right quality of image.

http://www.grails.org/plugin/burning-image

If you decide to go the imagemagick route, be aware that it requires a
bit of configuration and installing this on your server is
non-trivial. For www.cruiselinefans.com, we found that since we were
mostly writing the code in Windows machines and our server was a
Solaris box, there was a lot of pain getting settings that were
compatible across both versions.

For our current app, image quality was absolutely important, so I
rewrote some proof-of-concept code to resize using the google app
engine imageservice and call a remote service in a gaelyk app -
http://fbflex.wordpress.com/2010/05/03/manipulating-images-on-the-google-app-engine-with-gaelyk/

This is going to be slower than doing it on the local machine, but
guarantees portability across operating systems and no server setup.

Guillarme did some refactoring on the image service stuff in gaelyk,
so our resizing code that simply takes a jpq and makes an avatar out
of it looks like this:

https://gist.github.com/823374

Note that this is just a 'bake your own webservice' mechanism. It
gives me the best image results with the least amount of work, I don't
integrate with an API and it guarantees that my images are cropped /
resized the way I want.

Warner Onstine

unread,
Feb 12, 2011, 9:43:42 AM2/12/11
to grails-startup...@googlegroups.com
Thanks for the suggestions everyone! We might go with ImageMagick (I
have a friend who has set that up before and wants to tackle this fun
little project :P).

Here's what is weird, the first half of the image renders in the first
5 seconds, the rest takes 55 seconds to finish and spit out. So
something odd is definitely going on. Something to investigate.

Thanks again!

-warner

t.dave

unread,
Feb 15, 2011, 3:19:10 PM2/15/11
to Grails Startup Support Group
thanks all for the info on this. i was just about to create automatic
image resize functionality for thumbnails and avatars and whatnot.

i wanted to ask if anyone is using a queue to process their images?
i'm concerned that if a number of files get uploaded simultaneously
and the server is trying to process them all at once it could be
problematic. unless there's some kind of "concurrent = false" setting
in any of these plugins and i just haven't seen it yet.

also, is anyone using Amazon S3 for their image store? any gotchas
anyone has experienced with that? i like the idea of using Google App
Engine to do the image processing as it would offload that work from
my current server, but i haven't used GAE before and am a little
hesitant to get too crazy distributed. currently my images are
uploaded directly from the browser to S3 using SWFUpload so i can
bypass bandwidth and processing on the grails server. my thought is
that i'll have to change that to now upload the original image to the
server, create the thumbnail and/or other sizes, and then upload both
from there to S3. any better suggestions?

thanks all!

dave


On Feb 12, 8:43 am, Warner Onstine <warn...@gmail.com> wrote:
> Thanks for the suggestions everyone! We might go with ImageMagick (I
> have a friend who has set that up before and wants to tackle this fun
> little project :P).
>
> Here's what is weird, the first half of the image renders in the first
> 5 seconds, the rest takes 55 seconds to finish and spit out. So
> something odd is definitely going on. Something to investigate.
>
> Thanks again!
>
> -warner
>
> On Fri, Feb 11, 2011 at 6:33 PM, Tomas Lin <tomas...@gmail.com> wrote:
> > Hi Warner,
>
> > There is also a burningimage plugin which seeks to improve image
> > quality from imagetools. In our tests, Imagetools simply did not give
> > us the right quality of image.
>
> >http://www.grails.org/plugin/burning-image
>
> > If you decide to go the imagemagick route, be aware that it requires a
> > bit of configuration and installing this on your server is
> > non-trivial. Forwww.cruiselinefans.com, we found that since we were
> > mostly writing the code in Windows machines and our server was a
> > Solaris box, there was a lot of pain getting settings that were
> > compatible across both versions.
>
> > For our current app, image quality was absolutely important, so I
> > rewrote some proof-of-concept code to resize using the google app
> > engine imageservice and call a remote service in a gaelyk app -
> >http://fbflex.wordpress.com/2010/05/03/manipulating-images-on-the-goo...
>
> > This is going to be slower than doing it on the local machine, but
> > guarantees portability across operating systems and no server setup.
>
> > Guillarme did some refactoring on the image service stuff in gaelyk,
> > so our resizing code that simply takes a jpq and makes an avatar out
> > of it looks like this:
>
> >https://gist.github.com/823374
>
> > Note that this is just a 'bake your own webservice' mechanism. It
> > gives me the best image results with the least amount of work, I don't
> > integrate with an API and it guarantees that my images are cropped /
> > resized the way I want.
>
> >> For more options, visit this group athttp://groups.google.com/group/grails-startup-support-group?hl=en.

Tomas Lin

unread,
Feb 15, 2011, 3:34:14 PM2/15/11
to grails-startup...@googlegroups.com
Yes, I use both S3 and GAE / Gaelyk.

The obvious tip here is to also use S3 and Cloudfront. Cloudfront is
the content distribution layer on top of S3 and you can set expiry
dates and headers on the files you upload. It tends to make your
downloads faster since images are pushed to edge locations.

The basic workflow we go through is as follows -

- Upload original image to S3 with JetS3t.
- Schedule an image resize with Gaelyk by calling the resize groovlet
and passing in the S3 url.
- Download the processed image from Gaelyk
- Upload the processed image into S3 - this sets expiry headers.
- Putting the image into a cloudfront bucket exposes it to the CDN, so
it becomes served from Amazon edge locations.

We use the Executor plugin to offset the image resizing so the image
uploaded returns right away.
We also warm up the Gaelyk instance before we call the actual resize.

If I was to write this again, I would have the image be uploaded
directly into the google app engine and store the different image
sizes into the blobstore. GAE then becomes our CDN.

Be aware that if you choose the app engine route, Jets3t is not
compatible with the App Engine, but there are a few libraries out
there that will do the same work.

To give you an idea of the quality of the images in the google app
engine, here are a few samples -

Large - http://static.secretescapes.com/sales/33/4018af66_ae40_47e2_bdd7_b6254d093d6f_large.jpg
Medium - http://static.secretescapes.com/sales/33/4018af66_ae40_47e2_bdd7_b6254d093d6f_medium.jpg
Small - http://static.secretescapes.com/sales/33/4018af66_ae40_47e2_bdd7_b6254d093d6f_thumb.jpg

Warner Onstine

unread,
Feb 15, 2011, 4:43:58 PM2/15/11
to grails-startup...@googlegroups.com
All of this type of stuff wrapped up into a plugin might be nice. I
didn't quite understand what you meant about using Gaelyk until you
posted the full workflow - nice work! Very interesting take on things.
If we get a ton more users this may be the route we take - for now
Burning Image seems to be working on our local box just fine.

-warner

Tomas Lin

unread,
Feb 15, 2011, 6:36:47 PM2/15/11
to grails-startup...@googlegroups.com
I'm not quite sure how I would package a gaelyk app as a grails
plugin, though...

Warner Onstine

unread,
Feb 15, 2011, 6:38:06 PM2/15/11
to grails-startup...@googlegroups.com
Maybe not the app itself but probably more of the config stuff for s3,
gaelyk etc. Hmm, dunno.

-warner

t.dave

unread,
Feb 15, 2011, 6:53:40 PM2/15/11
to Grails Startup Support Group
tomas -

you, sir, are a prince among men. :) this afternoon i've gone from
never having used GAE or gaelyk to following your examples and
implementing and deploying an image resizing service. badass! i
still need to plug it in to my application but hopefully that will be
straightforward.

note that we are not yet using cloudfront but thanks for the tip on
that.

also, you have your workflow above as:

- Upload original image to S3 with JetS3t.
- Schedule an image resize with Gaelyk by calling the resize groovlet
and passing in the S3 url.
- Download the processed image from Gaelyk
- Upload the processed image into S3 - this sets expiry headers.
- Putting the image into a cloudfront bucket exposes it to the CDN, so
it becomes served from Amazon edge locations.

i'm thinking of doing the following:

- original image is uploaded from browser directly to S3 via SWFUpload
- on complete, S3 url is sent via GWT to grails server and stored
- grails server calls/schedules thumbnail creation with GAE/Gaelyk
service
- GAE/Gaelyk downloads image from S3 and performs resize
- GAE/Gaelyk uploads thumbnail back to S3
- GAE/Gaelyk notifies grails server of thumbnail image url
- grails server stores thumbnail image url

if i can pull this off the nice thing is that the grails server is
only notified of the various image URLs and doesn't even handle any of
the image uploading. looking at your post again i suppose i could
store the thumbnail images in the GAE blobstore as you suggested but i
suppose i do like the idea of having all the images on S3 for
consistency's sake if nothing else.

now i just need to figure out how to interface GAE/Gaelyk and S3...
> Large -http://static.secretescapes.com/sales/33/4018af66_ae40_47e2_bdd7_b625...
> Medium -http://static.secretescapes.com/sales/33/4018af66_ae40_47e2_bdd7_b625...
> Small -http://static.secretescapes.com/sales/33/4018af66_ae40_47e2_bdd7_b625...

Tomas Lin

unread,
Feb 16, 2011, 3:26:55 AM2/16/11
to grails-startup...@googlegroups.com

Warner Onstine

unread,
Feb 16, 2011, 7:46:39 AM2/16/11
to grails-startup...@googlegroups.com
Very cool! Thanks for sharing this.

-warner

t.dave

unread,
Feb 18, 2011, 12:21:11 AM2/18/11
to Grails Startup Support Group
FYI for anyone who finds this later, there is also an unofficial build
of the AWS SDK for Java that is compatible with GAE.

https://github.com/apcj/aws-sdk-for-java-on-gae


On Feb 16, 2:26 am, Tomas Lin <tomas...@gmail.com> wrote:
> jclouds -http://code.google.com/p/jclouds/
> ...
>
> read more »

Deluan Quintão

unread,
Mar 24, 2011, 11:03:50 PM3/24/11
to grails-startup...@googlegroups.com
Found this great conversation, with lots of good tips. I'm implementing this functionality right now on my app, and this information is being precious.

But I think there are one point not covered here: what to show to the user after the image submission but before the thumbnails are ready? Do you serve the original image during this period?

Thanks in advance.
Deluan. 

t.dave

unread,
Mar 25, 2011, 1:56:10 PM3/25/11
to Grails Startup Support Group
glad to see it's helping - my initial reaction above was the same. :)

yes, i'm serving the original image until the thumbnail has been
created. in the domain object that's keeping track of the images i
have fields like "imageFileName" and "thumbFileName". when i
initially upload the file i just put the same file name in both
fields, say "original_image.jpg". that's then served as the thumbnail
until the thumbnail has actually been created. (it just gets scaled
to the thumbnail size in the view.)

then, when the thumbnail creation returns it updates the
"thumbFileName" field to "original_image.jpg.resized.jpg". that way i
can see specifically that it's been resized to a thumbnail and it also
retains the original image name in case i need to do it over again or
there's any other problems later on. (i suppose the original image
name is also in the "imageFileName" field, but guess you can't be too
careful.) :)

hope that helps!

dave
> ...
>
> read more »
Reply all
Reply to author
Forward
0 new messages