Files
David Eisinger 09fdb667ee spelling fix
2024-11-18 14:19:34 -05:00

90 lines
3.8 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: "Large Images in Rails"
date: 2012-09-18T00:00:00+00:00
draft: false
canonical_url: https://www.viget.com/articles/large-images-in-rails/
---
The most visually striking feature on the new
[WWF](http://worldwildlife.org/) site, as well as the source of the
largest technical challenges, is the photography. The client team is
working with gorgeous, high-fidelity photographs loaded with metadata,
and it was up to us to make them work in a web context. Here are a few
things we did to make the site look and perform like a veritable [snow
leopard](http://worldwildlife.org/species/snow-leopard).
## Optimize Images
The average uploaded photo into this system is around five megabytes, so
the first order of business was to find ways to get filesize down. Two
techniques turned out to be very effective:
[jpegtran](http://jpegclub.org/jpegtran/) and
[ImageMagick](http://www.imagemagick.org/script/index.php)'s `quality`
option. We run all photos through a custom
[Paperclip](https://github.com/thoughtbot/paperclip) processor that
calls out to jpegtran to losslessly optimize image compression and strip
out metadata. In some cases, we were seeing thumbnailed images go from
60k to 15k by removing unused color profile data. We save the resulting
images out at 75% quality with the following Paperclip directive:
```ruby
has_attached_file :image,
:convert_options => { :all => "-quality 75" },
:styles => { # ...
```
Enabling this option has a huge impact on filesize (about a 90%
reduction) with no visible loss of quality. Be aware that we're working
with giant, unoptimized images; if you're going to be uploading images
that have already been saved out for the web, this level of compression
is probably too aggressive.
## Process in Background
Basic maths: large images × lots of crop styles = long processing time.
As the site grew, the delay after uploading a new photo increased until
it became unacceptable. It was time to implement background processing.
[Resque](https://github.com/defunkt/resque) and
[delayed_paperclip](https://github.com/jstorimer/delayed_paperclip) to
the ... rescue (derp). These two gems make it super simple to process
images outside of the request/response flow with a simple
`process_in_background :image` in your model.
A few notes: as of this writing, delayed_paperclip hasn't been updated
recently. [Here's a fork that
works](https://github.com/tommeier/delayed_paperclip) from tommeier. I
recommend using the
[rescue-ensure-connected](https://github.com/socialcast/resque-ensure-connected)
gem if you're going to run Resque in production to keep your
long-running processes from losing their DB connections.
## Server Configuration
You'll want to put [far-future expires
headers](http://developer.yahoo.com/performance/rules.html#expires) on
these photos so that browsers know not to redownload them. If you
control the servers from which they'll be served, you can configure
Apache to send these headers with the following bit of configuration:
```
ExpiresActive On
ExpiresByType image/png "access plus 1 year"
ExpiresByType image/gif "access plus 1 year"
ExpiresByType image/jpeg "access plus 1 year"
```
([Similarly, for
nginx](http://www.agileweboperations.com/far-future-expires-headers-for-ruby-on-rails-with-nginx).)
When working with a bunch of large files, though, you're probably better
served by uploading them to S3 or RackSpace Cloud Files and serving them
from there.
------------------------------------------------------------------------
Another option to look at might be
[Dragonfly](https://github.com/markevans/dragonfly), which takes a
different approach to photo processing than does Paperclip, resizing on
the fly rather than on upload. This might obviate the need for Resque
but at unknown (by me) cost. We hope that some of this will be helpful
in your next photo-intensive project.