There are numerous reports that Mobile Safari downsamples very large JPEG images, making it difficult to put out retina-friendly resolutions for the new iPad.
The solution seems to be encoding JPEGs as progressive/interlaced files.
Hence, I'm curious how I might use the CarrierWave plugin, and RMagick by extension, to generate this type of file.
Thanks!
You can use MiniMagick:
manipulate! do |img|
img.strip
img.combine_options do |c|
c.quality "90"
c.depth "8"
c.interlace "plane"
end
img
end
As of today, you will need the repository version of carriewave as options[:write]
support is not yet released.
So in your Gemfile, use the following:
gem 'carrierwave', :github => "jnicklas/carrierwave"
Then, in your uploader you can define something like follow:
version :big do
process :resize_to_limit => [1024, 1024]
process :optimize
end
def optimize
manipulate! do |img, index, options|
options[:write] = {
:quality => 90, # Change the quality to 90%
:depth => 8, # Set the depth to 8 bits
:interlace => "Magick::PlaneInterlace" # Add progressive support for JPEG
}
img.strip! # Remove profile data
end
end
Useful reference : http://www.imagemagick.org/RMagick/doc/constants.html#InterlaceType
Enjoy!
I've packaged a solutions as a gem https://github.com/jhnvz/retina_rails
Al you have to do is:
- Add
gem 'retina_rails'
to your Gemfile.
- Run
bundle install
.
- Add
//= require retina
to your Javascript manifest file (usually found at app/assets/javascripts/application.js).
Carrierwave
Add include RetinaRails::CarrierWave
to the bottom of your uploader
class ExampleUploader < CarrierWave::Uploader::Base
version :small do
process :resize_to_fill => [30, 30]
end
include RetinaRails::CarrierWave
end
Paperclip
Add include RetinaRails::Paperclip
to the bottom of your uploader
class ExampleUploader < ActiveRecord::Base
has_attached_file :image,
:styles => {
:original => ["800x800", :jpg],
:big => ["125x125#", :jpg]
}
include RetinaRails::Paperclip
end
The gem automatically generates retina versions (appends @2x to filename) based on your defined versions in an uploader. The js checks if the users got a retina display and if so appends @2x to the image file name.
I could encode images to Progressive JPEG doing the following thing to my CarrierWave Uploader:
class ImageUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
process :optimize #For the real image
version :version_1 do
# other processes
process :optimize
end
version :version_2, from_version: :version_1 do
# other processes
process :optimize
end
version :version_3, from_version: :version_2 do
# other processes
process :optimize
end
def optimize
manipulate! do |img|
img.combine_options do |c|
c.strip
c.quality '100'
c.depth '8'
c.interlace 'Line'
end
img
end
end
end
You have to put last the process that converts the image to Progressive JPEG otherwise it won't be converted.
Then if you already have uploaded some images and you want to "re-create" them.
Imagine that your model is:
class Picture < ActiveRecord::Base
mount_uploader :image, ImageUploader
end
So you have to do the following to recreate the versions:
Picture.order("id ASC").each do |p|
p.image.recreate_versions!
puts "#{p.id}, #{p.image.url}"
end
I ordered the picture based on the ID because if it fails in the middle of the process I have the ID and I can continue from that ID. Another thing you can do is to rescue any exception, and save in an array the pictures that fails, something like this:
errored = []
Picture.order("id ASC").each do |p|
begin
p.image.recreate_versions!
rescue => e
errored << p.id
end
puts "#{p.id}, #{p.image.url}"
end
Finally, to check that the image was converted to Progressive JPEG, having ImageMagick installed, type the following in the terminal:
identify -verbose PATH_TO_IMAGE | grep Interlace
If the image is Progressive JPEG, the output will be Interlace: JPEG
, if not Interlace: None