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.