0

I'm on Ruby 2.4.0 and Ruby on Rails 4.2.8.

I've moved from mini_magick to vips for handling images on my Ruby on Rails uploader. Due to wkhtmltopdf not supporting EXIF data for images, i have to correctly rotate them when they are saved to storage. I run two processes on the Carrierwave uploader, one to rotate and strip exif data, and another to resize.

    class ImageUploader < CarrierWave::Uploader::Base
 
  include CarrierWave::Vips
 
  process :fix_orientation
  process resize_to_fit: [800, 800]
  # Choose what kind of storage to use for this uploader:
  storage :gcloud
  # storage :file
  # storage :fog

  # Override the directory where uploaded files will be stored.
  # This is a sensible default for uploaders that are meant to be mounted:
  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end

Calling process :auto_orient (which is the method provided by Carrierwave-vips) on my image uploader in Ruby on Rails wasn't working. Images weren't being rotated, like nothing was happening. I went into the Carrierwave-vips gem and broke out the code relating to auto_orient into my uploader as fix_orientation. This is the code taken from that library - https://github.com/eltiare/carrierwave-vips/blob/master/lib/carrierwave/vips.rb

    def auto_orient
  manipulate! do |image|
    o = image.get('exif-Orientation').to_i rescue nil
    o ||= image.get('exif-ifd0-Orientation').to_i rescue 1
    case o
      when 1
        # Do nothing, everything is peachy
      when 6
        image.rot270
      when 8
        image.rot180
      when 3
        image.rot90
      else
        raise('Invalid value for Orientation: ' + o.to_s)
    end
    image.set_type GObject::GSTR_TYPE, 'exif-Orientation', ''
    image.set_type GObject::GSTR_TYPE, 'exif-ifd0-Orientation', ''
  end
end

After messing around with it, i found that the code only rotates the images if you take the last sections that are stripping the exif data out:

image.set_type GObject::GSTR_TYPE, 'exif-Orientation',
image.set_type GObject::GSTR_TYPE, 'exif-ifd0-Orientation',

I've tried breaking the function into the part that rotates the images, and into the part that strips the data, to see if that worked, so something like

process :fix_orientation #code checking exif data number and rotating image accordingly
process :fix_orientation_2 #the last two lines stripping the exif data from the image

Still, this makes it not work again. The only away that the images actually become correctly rotated is if the lines from fix_orientation_2 aren't called.

This is quite puzzling behaviour as it's coming straight from the Carrierwave library and i would expect the stripping of the exif data to not negate what was done previously with the rotation. The resize processing still seems to go through fine so it's not like the whole process stack is being reversed either

Any ideas as to what causes this behaviour? Might it be the Ruby version?

  • It could also be your libvips binary -- there have been a few exif rotation issues over the years. What version are you using? Looking ahead, it'd probably be best to move to rails7 if you can -- it has built-in image handling (based on shrine) with libvips as the default backend, so there's no need for carrierwave. – jcupitt Apr 24 '22 at 12:54
  • I did get the libvips just from doing apt-get install, i didn't actually build it from source so very likely something like that might be the case, i could give it a try and build from source to see if fixed i n that case. And thank you very much for the suggestion, it is definitely on my radar to upgrade as soon as possible now – Goncalo Mendes Apr 25 '22 at 13:47

1 Answers1

0

Although i would like to understand how to fix the underlying issue, i did get around this by not calling fix_orientation_2 but instead calling the :strip function which is part of that library, this works fine:

  process :fix_orientation
  process :strip

Also, for me at least, using these example images to test the exif: https://github.com/recurser/exif-orientation-examples

Found that this logic in Carrierwave-vips auto_orient is incorrect:

case o
      when 1
        # Do nothing, everything is peachy
      when 6
        image.rot270
      when 8
        image.rot180
      when 3
        image.rot90

To correctly upload the 1,6,8 and 3 images on that git, the correct logic (for me at least) was this:

      case o
        when 1
         # Do nothing, everything is peachy
        when 6
          image.rot90
        when 8
          image.rot270
        when 3
          image.rot180
  • Just to update, doing it this way was causing a memory leak, what ended up fixing it was building libvips from source to the newest version, then the process :auto_orient worked as intended and didn't need to do anything more for it to work – Goncalo Mendes Apr 29 '22 at 21:45