problème de rotation d'image exif utilisant carrierwave et rmagick pour télécharger vers s3

J'ai une fonction de téléchargement de photos dans mon application rails. L'application télécharge directement sur s3 via carrierwave via rmagick et fog. Le problème que j'ai est quand une photo est téléchargée via mobile via l'option" Prendre une photo " dans portrait (notez que c'est avec iphone mais je crois qu'android a le même problème). Une fois téléchargée, l'image apparaît bien sur mobile, mais lorsqu'elle est vue sur le bureau, l'image apparaît tournée de 90 degrés.

Grâce à mes recherches, il semble être un problème avec exif. Ce StackOverflow responder décrit 2 solutions potentielles. Cette gist semble également prometteuse.

Jusqu'à présent, j'ai trouvé quelques solutions affichées mais aucune n'a fonctionné. Idéalement, je voudrais que la photo soit enregistrée dans s3 en tant que portrait, puis affiche simplement l'image telle quelle.

Toutes les suggestions sont bien appréciées.

Ci-dessous est mon code

App/téléchargements/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 / modèles / 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 / initialisers / carrierwave.rb

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

Btw j'ai utilisé ce Railscast {[7] } comme guide pour configurer mon téléchargement s3.

25
demandé sur Community 2013-08-29 23:07:17

4 réponses

Eh bien, je l'ai fait fonctionner en utilisant fog à la place ou carrierwave_direct.

Voici le code qui a fini par fonctionner pour moi:

App/téléchargements/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 / modèles / s3_image.rb

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

  belongs_to :user
end

Initialiseurs / 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
33
répondu lando2319 2013-09-06 05:29:16

J'ai eu un problème similaire et l'ai corrigé avec une approche presque identique à la vôtre.

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

(notez que je N'appelle pas auto_orient! - juste auto_orient, sans le bang .)

Ensuite, j'ai process :auto_orient comme première ligne de tout version que je crée. Par exemple:

version :square do
  process :auto_orient
  process :resize_to_fill => [600, 600]
end
14
répondu Sumeet Jain 2013-08-30 21:43:34

Ma solution (assez similaire à Sumeet):

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

Il est vraiment important de retourner une image. Sinon, vous obtiendrez un

NoMethodError (undefined method `write' for "":String):
5
répondu Noémien Kocher 2014-01-10 05:54:55

La réponse de Lando2319 ne fonctionnait pas pour moi.

J'utilise RMagick.

J'ai réussi à faire en sorte que ImageMagick applique L'orientation correcte (et à réinitialiser les données de rotation EXIF afin d'éviter une double rotation par le visualiseur) en utilisant:

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

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

La différence entre ma solution et celle de Lando est le bang (!). Dans mon cas, il était absolument nécessaire.

1
répondu Adrien 2017-05-23 11:54:51