We have lots of user-generated images on our site. When users upload their images, we only store the original. However, depending on the page, we show different sizes of those images (small, medium, large, original). Is it necessary to store all sizes of these images or is there a better way? Currently, we are resizing them with CSS but this is really slow.
-
3Disk space is relatively cheap; why don't you want to store multiple copies?Mike Partridge– Mike Partridge2013年04月18日 17:14:03 +00:00Commented Apr 18, 2013 at 17:14
-
3To add to Mike's Partridge comment, there is not much processing power needed for generating smaller versions of images.Jalayn– Jalayn2013年04月18日 17:16:09 +00:00Commented Apr 18, 2013 at 17:16
-
2To add to Jalayn's comment on Mike's comment, you'll save on bandwidth if you can send a smaller image (i.e., the page only requires a thumbnail)Dan Pichelman– Dan Pichelman2013年04月18日 17:22:50 +00:00Commented Apr 18, 2013 at 17:22
-
1@FrustratedWithFormsDesigner maybe we could suggest to SO meta the possibility to add "collegial" answers :-)Jalayn– Jalayn2013年04月18日 17:35:40 +00:00Commented Apr 18, 2013 at 17:35
-
1@hugo yes, in fact maybe you could check out webdesign.tutsplus.com/tutorials/workflow-tutorials/… ? There is a mention on image scaling, thumbnails, CDN, minifying CSS/JS, etc.Jalayn– Jalayn2013年04月18日 17:46:09 +00:00Commented Apr 18, 2013 at 17:46
3 Answers 3
Storing multiple copies of the image at the required sizes is probably your best bet, for a few reasons:
Disk space is relatively cheap,
As @Jalayn commented, downsizing images doesn't require much processing power,
As @Dan Pichelman commented, serving smaller images when possible will save on bandwidth costs.
Once a file is uploaded, kick off an async process to generate the various copies so the user doesn't have to wait.
-
3From my experience-- 1. Have a table of allowed sizes - prevents DOS attack requesting different sizes. 2. Instead of the async process, create the downsized file on the fly when a page requests it, then retain the downsized file for future use.Pete Klein– Pete Klein2013年04月18日 18:16:25 +00:00Commented Apr 18, 2013 at 18:16
-
1Having to process the image on demand will add latency to getting the page served up that may be unacceptable. Processing the image once per page load will add up to a lot of expended cycles if the page is loaded millions of times.Blrfl– Blrfl2013年04月18日 18:39:01 +00:00Commented Apr 18, 2013 at 18:39
-
I assume that @hugo knows what sizes he'll need. Creating the downsized images lazily would save on space at the expense of load time, whether it happens before the page is sent to the browser, or when the browser tries to download the image. Good point, but it depends on his needs.Mike Partridge– Mike Partridge2013年04月18日 19:04:40 +00:00Commented Apr 18, 2013 at 19:04
Update in 2024: now SSD is dirt cheap as well, to store original images thus the request-resize-response process can be much faster.
I disagree on the file storage, if possible, those interim images should never be stored as they always create clutter.
Disk space is dirt cheap, but serving files from disk is slow, and SSDs - that are fast - are not that dirt cheap yet. This "generate all image size we can think of" model is not future proof and it works until you can predefine all the image resolutions that you need to display. There is always the problem of leftover content that is a pain to maintain, but at least it is the same problem always. Business specification can ruin this model quite easily. If it requires that you need a new resolution of the images, you have to write resizing scripts that walks through your entire existing image library and creates the new resolution so your old images can work in a new design. It is doable, but it needs system admins. However if business specification requires you to be very responsive and always changing image size, which cannot be predefined, this model is screwed.
We have been there and done that, now instead we use varnish cache and a resizing application combination to serve arbitrarily resized images without explicitly storing them on disk. As the images are served from cache, their delivery is lightning fast. With this solution there is no need to:
- create every image version, especially when you don't know what to create
- delete leftover images
- running async processes to resize the image
- re-resize old images to new resolutions
- create differently named files because of file system restrictions.
In our model resize happens in the request-response process when the visitor requests the resized image. In other words, the visitor who loads a resized image into the browser - an image that has never been displayed - will have to wait a little extra time, while the system creates the new, resized image.
Bonus feature: everything is testable by calling a simple URL, no need to run the image resizer app to create the different versions of the image. The image will be created on-the-fly.
- Original image: http://myserver.com/imagename.jpg
- Resized image: http://myserver.com/imagename.jpg?w=317 (creating a 317 pixels wide image)
Every request to http://myserver.com will arrive to a Varnish that handles those incoming requests. Varnish is configured so that when it gets a request that has no query parameters, serves the request from static filesystem without caching the content. Turning off cache in this case is a good idea only if the original image will never be shown to visitors, only the resized ones (maybe because the original is a fairly large one).
If the incoming request has query parameters, Varnish dispatches the request to the resizing application. The application gets the base image by re-running the original request without the query string, which means Varnish will serve the original image to the application. As Varnish can act as a load-balancer, it can even mitigate problems, like application timeout.
The application then does the appropriate resizing (checking parameter validity, rules, etc.), and makes a response with the resized image. The response goes back in the response chain, which is Varnish, and that caches the resized image, and serves it back to the client.
Any subsequent request to the same size image (aka: the same URL with the same query parameters) will be served from cache until the cache expires.
This way Varnish is used as the storage device, with the added bonus of being a cache.
There's a lot of way you can handle this, and I think the "right way" depends.
However I think we can all agree that storing the different sizes is the best way.
Your site might not be setup in a way that 3 sizes work for you though (such as small, medium, large) and of course storing every possible combination is unpractical. So with that being said I would store a few different sizes based on the most common sizes you serve.
If you happen to store a 100px x 100px image most of the time and need a 90px x 90px image just serve the 100x100 and scale it down with css, that's not as big of a deal as having to serve the 900x900px image and scaling it down. It's a good compromise.