CarrierWave and correct file extension depending on its contents

前端 未结 2 1386
野性不改
野性不改 2021-01-19 04:51

How can I make CarrierWave add correct extension to filename depending on its contents? For example, if I upload file \"logo\" (PNG file without extension) CarrierWave shoul

相关标签:
2条回答
  • 2021-01-19 05:10

    The problem is in determining the correct content in the first place. Carrierwave uses the MimeType gem which determines its mime-type from the extension. Since, in your case the extension is incorrect you need an alternate way of getting the correct mime-type. This is the best solution I was able to come up with, but it depends on the ability to read the image file using the RMagick gem.

    I ran into this same problem and had to override the default set_content_type method for my uploader. This assumes you have Rmagick gem in your Gemfile, so that you can get the correct mime-type from reading the image, as opposed to making a best guess.

    Note: This is particularly useful if the image is being used by Prawn which supports only JPG and PNG images.

    Uploader Class:

    process :set_content_type
    
    def set_content_type #Note we are overriding the default set_content_type_method for this uploader
      real_content_type = Magick::Image::read(file.path).first.mime_type
      if file.respond_to?(:content_type=)
        file.content_type = real_content_type
      else
        file.instance_variable_set(:@content_type, real_content_type)
      end
    end
    

    Image Model:

    class Image < ActiveRecord::Base
      mount_uploader :image, ImageUploader
    
      validates_presence_of :image
      validate :validate_content_type_correctly
    
      before_validation :update_image_attributes
    
    private
      def update_image_attributes
        if image.present? && image_changed?
          self.content_type = image.file.content_type
        end
      end
    
      def validate_content_type_correctly
        if not ['image/png', 'image/jpg'].include?(content_type)
          errors.add_to_base "Image format is not a valid JPEG or PNG."
          return false
        else
          return true
        end
      end
    end
    

    In your case you can add an additional method that changes the extension based on this correct mime-type (content_type).

    0 讨论(0)
  • 2021-01-19 05:15

    There's a couple of things you can do, depending on if you're using process or version to do this.

    If it's a version, the carrierwave wiki has a way to do conditional versions. https://github.com/jnicklas/carrierwave/wiki/How-to%3A-Do-conditional-processing

    version :big, :if => :png? do
      process ...
    end
    
    protected
    def png?(new_file)
      new_file.content_type.include? 'png'
    end
    

    If you're using the process method, you might want to take a look at this: https://gist.github.com/995663.

    Add these into your code to get around the constraints that process has

    # create a new "process_extensions" method.  It is like "process", except
    # it takes an array of extensions as the first parameter, and registers
    # a trampoline method which checks the extension before invocation
    def self.process_extensions(*args)
      extensions = args.shift
      args.each do |arg|
        if arg.is_a?(Hash)
          arg.each do |method, args|
            processors.push([:process_trampoline, [extensions, method, args]])
          end
        else
          processors.push([:process_trampoline, [extensions, arg, []]])
        end
      end
    end
    
    # our trampoline method which only performs processing if the extension matches
    def process_trampoline(extensions, method, args)
      extension = File.extname(original_filename).downcase
      extension = extension[1..-1] if extension[0,1] == '.'
      self.send(method, *args) if extensions.include?(extension)
    end
    

    You can then use this to call what used to be process, selectively on each file type

    PNG = %w(png)
    JPG = %w(jpg jpeg)
    GIF = %w(gif)
    def extension_white_list
      PNG + JPG + GIF
    end
    
    process_extensions PNG, :resize_to_fit => [1024, 768]
    process_extensions JPG, :... 
    process_extensions GIF, :...
    
    0 讨论(0)
提交回复
热议问题