使用CarrierWave和RMagick上传到S3时遇到的Exif图像旋转问题

31

我的Rails应用中有一个照片上传功能。该应用通过CarrierWave通过Rmagick和Fog直接上传到Amazon S3。我的问题是,当用户使用移动设备上的“拍照”选项(注:这是iPhone,但我认为Android也会有同样的问题)拍摄照片时,照片在移动设备上看起来很好,但在桌面浏览器上却旋转了90度。

经过我的调查,看起来似乎是由于Exif引起的问题。这个Stack Overflow回答者提出了两种潜在的解决方案。这个gist看起来也很有前途。

到目前为止,我已经找到了一些发布的解决方案,但都没有奏效。理想情况下,我希望将照片保存为竖屏照片,然后按原样显示图像。

欢迎提出任何建议。

以下是我的代码

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

应用/模型/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

顺便提一下,我使用了这个Railscast作为设置我的s3上传的指南。

4个回答

37

我最终使用fog而不是carrierwave_direct使其正常工作。

下面是最终为我工作的代码:

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

12
@JonathanAllard,“manipulate!”模块需要一张图片,但是image.auto_orient返回一个空字符串。“image.tap(&:auto_orient)”大致相当于“image.auto_orient; image”。 - benizi
只有使用 img.tap(&:auto_orient!)(注意感叹号)才对我起作用。但我也使用了 CarrierWave::RMagick 而不是 CarrierWave::MiniMagick - Sandro L
Sumeet的解决方案只适用于某些版本。上传的原始图像仍然旋转。@lando2319提供的这个解决方案适用于原始图像和缩略图。 - jcuervo
我还需要添加感叹号 img.tap(&:auto_orient!)。感谢您提供的 fix_exif_rotation 方法。 - hoitomt

15

我遇到了类似的问题,并且采用了与你几乎完全相同的方法解决了它。

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

请注意,我并没有调用auto_orient!,而是只调用auto_orient,没有感叹号。

然后,在我创建的任何version的第一行中加入了process :auto_orient。例如:

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

谢谢您的建议,不幸的是这并没有解决我的问题。 - lando2319
我将此添加到我的版本中,然后重新创建了这些版本,这解决了侧面图像问题。到目前为止,我只在iOS 7上通过Safari上传的图像进行了测试。希望它能够适用于所有情况。谢谢。 - wuliwong

6

我提供的解决方案与Sumeet非常相似:

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

返回图像非常重要,否则会收到以下错误:

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

3
你的解决方案对我很有效,而@Sumeet的方案尽管非常相似但却无法解决问题。另外,感谢你提供关于需要“返回一个图片”的提示。记录一下,我遇到了类似的错误:“NoMethodError(针对“”:String没有定义'destroy!'方法)”。 - user664833

2

Lando2319的回答对我没有用。

我正在使用RMagick。

我成功地使ImageMagick应用正确的方向(并重置EXIF旋转数据以避免查看器进行双重旋转),方法如下:

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

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

我的解决方案与Lando的不同之处在于感叹号(!)。在我的情况下,这是绝对必要的。

我也遇到了使用RMagick处理iPhone图片时的同样问题,但在我的name_uploaded.rb文件开头调用它后得到了解决。具体来说,在include CarrierWave::ImageRounder之后添加以下代码:process :fix_exif_rotation - Hafiz Abdul Rehman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接