Search code examples
ruby-on-railsruby-on-rails-4carrierwaveminimagick

Rails + Carrierwave + MiniMagick: How to preserve gif animation?


When I upload gif images via Carrierwave and MiniMagick, the animation is removed. I tried a lot of solutions...

This upload has a curiosity thing. If I put the image type, it returns "image/png", but I sended a gif. I tried with other files too.

file app/uploaders/image_uploader.rb

class ImageUploader < CarrierWave::Uploader::Base

    include CarrierWave::MiniMagick

    storage :aws

    def store_dir
        "#{model.class.to_s.underscore}/#{mounted_as}/"
    end

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

    version :thumb do
        process resize_to_limit: [150, 100000]
        process :quality => 90
        process :fix_exif_rotation
    end

    version :original do
        process :quality => 90
        process :fix_exif_rotation
    end

    def extension_white_list
        %w(jpg jpeg gif png)
    end

    def filename
        "#{secure_token}.#{file.extension}" if original_filename.present?
    end

    private

    def secure_token
        var = :"@#{mounted_as}_secure_token"
        model.instance_variable_get(var) || model.instance_variable_set(var, SecureRandom.uuid)
    end

end

If I change the version original to:

version :original do
    process :get_image_type
    process :quality => 90
    process :fix_exif_rotation
end

def get_image_type
    puts @file.content_type
end

In console (rails s), it returns "image/png". I'm trying to apply this solution, but not works and I suspect the problem is with the wrong content_type.

My env

rails -v: Rails 4.2.1
ruby -v: ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-linux]
carrierwave-aws: 1.2.0
mini_magick: 4.8.0
OS: Ubuntu 16.04.5 LTS

Solution

  • The problem is with DropzoneJS. All uploaded files wi resized locally. When a GIF is resized by DropzoneJS, it will be flatted and converted to an PNG.

    Then, Carrierwave sent to server an PNG file with GIF extension.

    My final DropzoneJS settings (which works) is:

    $('.dropzone').dropzone({
        paramName: 'attachment[image]',
        maxFilesize: 3,
        thumbnailWidth: 189,
        previewsContainer: '#sended-images',
        previewTemplate: $('#preview').html(),
        timeout: 360000,
        acceptedFiles: 'image/*,.jpg,.png,.jpeg,.gif',
        accept: function(file, done) {
            var mime_type = file.type;
            if ( mime_type != 'image/gif' ){
                this.options.resizeWidth = 1800;
                this.options.resizeQuality = 90;
                done();
            } else {
                this.options.resizeWidth = null;
                this.options.resizeQuality = null;
                done();
            }
            file.status = Dropzone.ADDED;
            done();
        },
        init:function(){
            this.on('success',function(f,d){
                ...
            });
            this.on('sending',function(f,x,d){
                ...
            });
            this.on('addedfile',function(f,x,d){
                ...
            });
            this.on('error', function(f, response) {
                ...
            });
            this.on("maxfilesexceeded", function(file){
                ...
            });
        }
    });
    

    My unique problem here is:

    If I send multiples files which GIF is processed first, next files will not be resized. If the first file processed is not a GIF, next files will be resized and the GIFs will not work.