davideisinger.com

My personal website
Log | Files | Refs | README

index.md (3879B)


      1 ---
      2 title: "Large Images in Rails"
      3 date: 2012-09-18T00:00:00+00:00
      4 draft: false
      5 canonical_url: https://www.viget.com/articles/large-images-in-rails/
      6 ---
      7 
      8 The most visually striking feature on the new
      9 [WWF](http://worldwildlife.org/) site, as well as the source of the
     10 largest technical challenges, is the photography. The client team is
     11 working with gorgeous, high-fidelity photographs loaded with metadata,
     12 and it was up to us to make them work in a web context. Here are a few
     13 things we did to make the site look and perform like a veritable [snow
     14 leopard](http://worldwildlife.org/species/snow-leopard).
     15 
     16 ## Optimize Images
     17 
     18 The average uploaded photo into this system is around five megabytes, so
     19 the first order of business was to find ways to get filesize down. Two
     20 techniques turned out to be very effective:
     21 [jpegtran](http://jpegclub.org/jpegtran/) and
     22 [ImageMagick](http://www.imagemagick.org/script/index.php)'s `quality`
     23 option. We run all photos through a custom
     24 [Paperclip](https://github.com/thoughtbot/paperclip) processor that
     25 calls out to jpegtran to losslessly optimize image compression and strip
     26 out metadata. In some cases, we were seeing thumbnailed images go from
     27 60k to 15k by removing unused color profile data. We save the resulting
     28 images out at 75% quality with the following Paperclip directive:
     29 
     30 ```ruby
     31 has_attached_file :image,
     32   :convert_options => { :all => "-quality 75" },
     33   :styles => { # ...
     34 ```
     35 
     36 Enabling this option has a huge impact on filesize (about a 90%
     37 reduction) with no visible loss of quality. Be aware that we're working
     38 with giant, unoptimized images; if you're going to be uploading images
     39 that have already been saved out for the web, this level of compression
     40 is probably too aggressive.
     41 
     42 ## Process in Background
     43 
     44 Basic maths: large images × lots of crop styles = long processing time.
     45 As the site grew, the delay after uploading a new photo increased until
     46 it became unacceptable. It was time to implement background processing.
     47 [Resque](https://github.com/defunkt/resque) and
     48 [delayed_paperclip](https://github.com/jstorimer/delayed_paperclip) to
     49 the ... rescue (derp). These two gems make it super simple to process
     50 images outside of the request/response flow with a simple
     51 `process_in_background :image` in your model.
     52 
     53 A few notes: as of this writing, delayed_paperclip hasn't been updated
     54 recently. [Here's a fork that
     55 works](https://github.com/tommeier/delayed_paperclip) from tommeier. I
     56 recommend using the
     57 [rescue-ensure-connected](https://github.com/socialcast/resque-ensure-connected)
     58 gem if you're going to run Resque in production to keep your
     59 long-running processes from losing their DB connections.
     60 
     61 ## Server Configuration
     62 
     63 You'll want to put [far-future expires
     64 headers](http://developer.yahoo.com/performance/rules.html#expires) on
     65 these photos so that browsers know not to redownload them. If you
     66 control the servers from which they'll be served, you can configure
     67 Apache to send these headers with the following bit of configuration:
     68 
     69 ```
     70 ExpiresActive On
     71 ExpiresByType image/png "access plus 1 year"
     72 ExpiresByType image/gif "access plus 1 year"
     73 ExpiresByType image/jpeg "access plus 1 year"
     74 ```
     75 
     76 ([Similarly, for
     77 nginx](http://www.agileweboperations.com/far-future-expires-headers-for-ruby-on-rails-with-nginx).)
     78 When working with a bunch of large files, though, you're probably better
     79 served by uploading them to S3 or RackSpace Cloud Files and serving them
     80 from there.
     81 
     82 ------------------------------------------------------------------------
     83 
     84 Another option to look at might be
     85 [Dragonfly](https://github.com/markevans/dragonfly), which takes a
     86 different approach to photo processing than does Paperclip, resizing on
     87 the fly rather than on upload. This might obviate the need for Resque
     88 but at unknown (by me) cost. We hope that some of this will be helpful
     89 in your next photo-intensive project.