Ruby on Rails Carrierwave-vips: Auto Orient not working if exif data is stripped at same time

339 Views Asked by At

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?

1

There are 1 best solutions below

1
On

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