Search code examples
ruby-on-rails-3image-processingimagemagickcarrierwavermagick

Carrierwave pdf to jpg thumbnail, works in either Safari +iOS or IE, Firefox, Chrome but not both


I am pulling my hair out and have been searching for a solution for days. I am trying to take an uploaded pdf document and create a thumbnail that is viewable on all browsers. I can get it to work on Safari/iOS or Firefox/IE7+/Chrome but not one version that works everywhere. I've tried setting the colorspace to rgb(no effect), converting to png instead of jpg(no effect) and setting :set_content_type(no effect). I am getting the same result on my local machine and on production(Heroku).

pdfdoc_uploader.rb

include ImageManipulators
include CarrierWave::RMagick
include CarrierWave::MimeTypes

version :thumb do

 process :convert => 'jpg'  #<---This works in Safari and iOS
 process :resize_to_fit => [200, 200]
 process :paper_shape
 process :strip
 process :convert => 'jpg'  #<---Move it here and it works everywhere else

 def full_filename (for_file = model.logo.file)
   super.chomp(File.extname(super)) + '.jpg'
 end     
end

image_manipulators.rb

module ImageManipulators

# creates an image with a 3x4 aspect ratio
def paper_shape
  manipulate! do |img|
if img.rows*4 != img.columns*3
  width=img.columns
  height=img.columns/3*4
  img.crop!(0,0,width,height,true)
else
  img
end
  end
 end

def set_content_type(*args)
   self.file.instance_variable_set(:@content_type, "image/jpeg")
end

# Autoorients image according to exif
 def auto_orient
   manipulate! {|img| img.auto_orient! || img }
 end

 # Crops the biggest possible square from the image
 def biggest_square
   manipulate! do |img|
     if img.rows != img.columns
       max = img.rows > img.columns ? img.columns : img.rows
       img.crop!(0,0,max,max,true)
     else
       img
     end
   end
 end

def paper_shape
  manipulate! do |img|
     if img.rows*4 != img.columns*3
       width=img.columns
       height=img.columns/3*4
       img.crop!(0,0,width,height,true)
     else
       img
     end
  end
 end

 # Create rounded corners for the image
 def rounded_corners
   radius = 10
   manipulate! do |img|
     #create a masq of same size
     masq = Magick::Image.new(img.columns, img.rows)
     d = Magick::Draw.new
     d.roundrectangle(0, 0, img.columns - 1, img.rows - 1, radius, radius)
     d.draw(masq)
     img.composite(masq, 0, 0, Magick::LightenCompositeOp)
   end
 end

 # Rotates the image based on the EXIF Orientation
     def fix_exif_rotation
       manipulate! do |img|
         img.auto_orient!
         img = yield(img) if block_given?
         img
       end
     end

     # Strips out all embedded information from the image
     def strip
       manipulate! do |img|
         img.strip!
         img = yield(img) if block_given?
         img
       end
     end

     def colorspace(cs)
         manipulate! do |img|
           case cs
           when 'rgb'
             img.colorspace = Magick::RGBColorspace
           when 'cmyk'
             img.colorspace = Magick::CMYKColorspace
           end
           img = yield(img) if block_given?
           img
         end
       end
end

Solution

  • I eventually gave up and just created two versions and used useragent to determine which one to display. While not an attractive option it is working. I hope someone comes up with a better solution.

    version :thumb_safari do #special version for safari and ios
      process :resize_to_fit => [200,200]
      process :convert => 'jpg'
      process :paper_shape
      def full_filename (for_file = model.logo.file)
         super.chomp(File.extname(super)) + '.jpg'
      end     
    end
    
    version :thumb do #all browsers except safari
      process :resize_to_fit => [200,200]
      process :convert => 'jpg' #must convert to jpg before running paper shape
      process :paper_shape
      process :convert => 'jpg' #after running paper_shape it will default to original file type
      def full_filename (for_file = model.logo.file)
        super.chomp(File.extname(super)) + '.jpg'
      end
    end
    
    def paper_shape
       manipulate! do |img|
         if img.rows*4 != img.columns*3
           width=img.columns
           height=img.columns/3*4
           img.crop!(0,0,width,height,true)
         else
           img
         end
       end
     end
    

    In the controller/view I used the useragent gem and did this:

    documents_controller.rb

    def index
      @user_agent=UserAgent.parse(request.user_agent)
      @search = Document.search(params[:q])
    end
    

    index.html.rb

    <% if @user_agent.browser.downcase == 'safari' %>
    <%= link_to(image_tag(doc.pdfdoc_url(:thumb_safari).to_s, :class=>"dropshadow", :size => "150x225"), doc.pdfdoc_url)%>
    <% else %>
    <%= link_to(image_tag(doc.pdfdoc_url(:thumb).to_s, :class=>"dropshadow", :size => "150x225"), doc.pdfdoc_url)%>
    <% end %>
    

    No doubt there is a better way to do this but this is working for now.