Designer
Designer

Reputation: 1111

Rails 5 Carrierwave and MiniMagick breaks gif at resizing for thumbnail

I'm using carrierwave and mini_magick to resize my images, generate thumbnails. It works great for still images such as jpg and png, but when I try gif, it distorts it. You can see original vs the resized example below. Any idea how I make make it generate gif thumb without breaking it?

Original GIF :) https://i.sstatic.net/iCSdl.jpg

Generated Thumbnail GIF :( https://i.sstatic.net/rfEcO.jpg enter image description here


ps how came the thumbnail's size is bigger than the original? Original is 800*600px and thumbnail is 400*300px. The whole point of generating thumbnail is having smaller file size anyways. enter image description here

Thank you!


image_uploader.rb

class ImageUploader < CarrierWave::Uploader::Base

  # Include RMagick or MiniMagick support:
  # include CarrierWave::RMagick
  include CarrierWave::MiniMagick

  # Choose what kind of storage to use for this uploader:
  storage :file
  # 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

  # Provide a default URL as a default if there hasn't been a file uploaded:
  # def default_url(*args)
  #   # For Rails 3.1+ asset pipeline compatibility:
  #   # ActionController::Base.helpers.asset_path("fallback/" + [version_name, "default.png"].compact.join('_'))
  #
  #   "/images/fallback/" + [version_name, "default.png"].compact.join('_')
  # end
  def default_url(*args)
    ActionController::Base.helpers.asset_path("fallback/" + [version_name, "post.jpg"].compact.join('_'))
  end

  # Process files as they are uploaded:
  # process scale: [800, 600]
  # process :resize_to_fit => [800, 600]
  #
  # def scale(width, height)
  #   # do something
  # end

  # Create different versions of your uploaded files:
  # version :thumb do
  #   process resize_to_fit: [50, 50]
  # end
  version :thumb do
    process resize_to_fit: [400, 300]
  end

  # Add a white list of extensions which are allowed to be uploaded.
  # For images you might use something like this:
  def extension_whitelist
    %w(jpg jpeg gif png)
  end

  # Override the filename of the uploaded files:
  # Avoid using model.id or version_name here, see uploader/store.rb for details.
  # def filename
  #   "something.jpg" if original_filename
  # end

end

Upvotes: 1

Views: 1327

Answers (1)

fidgital
fidgital

Reputation: 81

The gif you're trying to resize is optimized so that, after the first frame, each subsequent frame contains only the pixels that need to change. When the gif animates, the frames are stacked on top of one another creating the full animation.

Additionally, each frame is only large enough to contain the pixels that need to change. So, the size of each frame is different. When you resize the gif, Imagemagick is resizing each frame to be 400 by 300px regardless of its original size, which is causing the distortion you see.

You can fix this applying an Imagemagick command (with Minimagick bindings in Ruby) called coalesce. It de-optimizes the original image so that each frame is the full size of the canvas.

Calling coalesce makes the file size much larger, so it's necessary to re-optimize the gif once you're done resizing it.

Here's an example:

version :thumb do
  process my_resize: [400, 300]
end

def my_resize(width, height)
  if @file.content_type == "image/gif"
    gif_safe_transform! do |image|
      image.resize "#{width}x#{height}" # Perform any transformations here.
    end
  else
    # Process other filetypes if necessary.
  end
end

def gif_safe_transform!
  MiniMagick::Tool::Convert.new do |image|
    image << @file.path
    image.coalesce # Remove optimizations so each layer shows the full image.

    yield image

    image.layers "Optimize" # Re-optimize the image.
    image << @file.path
  end
end

I wrote a more in-depth explanation with some examples here

Upvotes: 5

Related Questions