exif image rotation issue using carrierwave and rmagick to upload to s3

12,649

Solution 1

Well I got this working using fog instead or carrierwave_direct.

Below is the code that ended up working for me:

app/uploaders/image_uploader.rb

class ImageUploader < CarrierWave::Uploader::Base
   include CarrierWave::MiniMagick

   include Sprockets::Helpers::RailsHelper
   include Sprockets::Helpers::IsolatedHelper

   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


  def fix_exif_rotation #this is my attempted solution
    manipulate! do |img|
      img.tap(&:auto_orient)
    end
  end

  process :fix_exif_rotation
end

app/models/s3_image.rb

class S3Image < ActiveRecord::Base
  attr_accessible :image, :name, :user_id, :image_cache
  mount_uploader :image, ImageUploader

  belongs_to :user
end

initializers/carrierwave.rb

CarrierWave.configure do |config|
  config.fog_credentials = {
    provider: "AWS",
    aws_access_key_id: " ... ",
    aws_secret_access_key: " ... ",
    region: 'us-west-2'
  }
  config.fog_directory = " ... "
end

Solution 2

I had a similar problem and fixed it with an approach nearly identical to yours.

# In the uploader:
def auto_orient
  manipulate! do |img|
    img = img.auto_orient
  end
end

(Note that I am not calling auto_orient! - just auto_orient, without the bang.)

Then I have process :auto_orient as the first line of any version I create. For example:

version :square do
  process :auto_orient
  process :resize_to_fill => [600, 600]
end

Solution 3

My solution (quite similar to Sumeet) :

# painting_uploader.rb
process :right_orientation
def right_orientation
  manipulate! do |img|
    img.auto_orient
    img
  end
end

It's really important to return an image. Otherwise, you'll get an

NoMethodError (undefined method `write' for "":String):

Solution 4

Lando2319's answer was not working for me.

I am using RMagick.

I managed to make ImageMagick apply the correct orientation (and to reset the EXIF rotation data in order to avoid a double rotation by the viewer) by using :

def fix_exif_rotation # put this before any other process in the Carrierwave uploader

manipulate! do |img|
  img.tap(&:auto_orient!)
end

The difference between my solution & Lando's is the bang (!). In my case it was absolutely necessary.

Share:
12,649
lando2319
Author by

lando2319

Co-Founder | CTO at ChangEd Software Dev, Swift, JS, Kotlin Curious, Vim Fanatic

Updated on June 05, 2022

Comments

  • lando2319
    lando2319 almost 2 years

    I've got a photo upload feature in my rails app. The app uploads direct to s3 through carrierwave via rmagick and fog. The issue I am having is when a photo is uploaded via mobile through the "take a photo option" in portrait (note this is with iphone but I believe android has the same issue). Once uploaded the image appears fine on mobile, however when viewed on desktop the image appears rotated 90 degrees.

    Through my research it looks to be an issue with exif. This stackoverflow responder outlines 2 potential solutions. This gist also looks promising as well.

    So far I have found a few solutions posted but none have worked. Ideally I would like the photo to be saved to s3 as a portrait, then just display the image as is.

    Any suggestions are well appreciated.

    Below is my code

    app/uploaders/image_uploader.rb

    class ImageUploader < CarrierWave::Uploader::Base
      include CarrierWaveDirect::Uploader
    
      include CarrierWave::RMagick
    
      # Include the Sprockets helpers for Rails 3.1+ asset pipeline compatibility:
      include Sprockets::Helpers::RailsHelper
      include Sprockets::Helpers::IsolatedHelper
    
      include CarrierWave::MimeTypes
      process :fix_exif_rotation
      process :set_content_type
    
    
      version :thumb do
        process resize_to_fill: [200, 200]
      end
    
      def extension_white_list
        %w(jpg jpeg png)
      end
    
    
      def fix_exif_rotation #this is my attempted solution
        manipulate! do |img|
          img = img.auto_orient!
        end
      end
    
    
    end
    

    app/models/s3_image.rb

    class S3Image < ActiveRecord::Base
      attr_accessible :image, :name, :user_id
      mount_uploader :image, ImageUploader
    
      belongs_to :user
    
    
      def image_name
        File.basename(image.path || image.filename) if image
      end
    
    
      class ImageWorker
        include Sidekiq::Worker
    
        def perform(id, key)
          s3_image = S3Image.find(id)
          s3_image.key = key
          s3_image.remote_image_url = s3_image.image.direct_fog_url(with_path: true)
          s3_image.save!
          s3_image.update_column(:image_processed, true)
        end
      end
    end
    

    config/initializers/carrierwave.rb

    CarrierWave.configure do |config|
      config.fog_credentials = {
        provider: "AWS",
        aws_access_key_id: " ... ",
        aws_secret_access_key: " ... "
      }
      config.fog_directory = " ... "
    end
    

    btw I used this Railscast as a guide for setting up my s3 upload.

  • lando2319
    lando2319 over 10 years
    Thank you for the suggestion, unfortunately this didn't fix my issue.
  • benizi
    benizi over 10 years
    @JonathanAllard the manipulate! block wants an image, but image.auto_orient returns an empty string. image.tap(&:auto_orient) roughly corresponds to image.auto_orient ; image.
  • wuliwong
    wuliwong about 10 years
    I added this to my versions then recreated the versions and it has fixed the sideways image issues. So far I've only tested it with images uploaded via safari on ios 7. hopefully it works across the board. thanks.
  • user664833
    user664833 over 9 years
    Your solution worked for me, whereas @Sumeet's did not, despite how similar. Also, thanks for the tip about the need to return an image. For the record, I had a similar error NoMethodError (undefined method 'destroy!' for "":String).
  • Sandro L
    Sandro L about 8 years
    Worked for me only when using img.tap(&:auto_orient!) (note the bang!). But I am also using CarrierWave::RMagick instead of CarrierWave::MiniMagick
  • jcuervo
    jcuervo over 7 years
    Sumeet's solution only works for the versions. The uploaded original image is still rotated. This solution from @lando2319 works for both the original image and the thumbnails.
  • hoitomt
    hoitomt over 7 years
    I needed to add the bang as well img.tap(&:auto_orient!). Thanks for the fix_exif_rotation method.
  • Hafiz Abdul Rehman
    Hafiz Abdul Rehman over 2 years
    I was also facing the same issue using RMagick with iPhone images which got fixed as I call it at the start of my name_uploaded.rb file after include CarrierWave::ImageRounder like this process :fix_exif_rotation