Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Resizing Animated GIF images with ruby?

I am trying to resize a GIF image to different sizes. I am using RMagick library in ruby. But it seems for some gif images the file size increases even when I am downsizing GIF. And I am resizing the image image in same aspect ratio. Here is the my code.

require 'rmagick'
path = "/path/to/file/"
s_image = "image.gif" # image is 320*320
t_image = "t.gif"
file_name = path+s_image
file = File.new(file_name)
list = Magick::ImageList.new.from_blob file.read
list = list.coalesce.remap
list.each do |x|
  x.resize_to_fill!(256,256)
end
File.open("#{path+t_image}", 'wb') { |f| f.write list.to_blob }

What am I missing?

like image 796
Narendra Rajput Avatar asked Mar 21 '23 12:03

Narendra Rajput


1 Answers

The image you linked consisted of 35 frames. It had also been optimised, so that after than the first frame, each frame only contains the pixels that are different. Most of the pixels are transparent, because very little moves. This is common situation with animated gifs - they can be made relatively efficient (in terms of file size) if there are not too many changes or camera movement.

In addition, each frame size is the minimum rectangle necessary to contain all the changing pixels, so it varies from frame-to-frame.

You can see this clearly, if you load the original image in e.g. The GIMP, and inspect the individual layers.

If you do that with your converted image, can also see that your code renders out each frame in full, in order to re-size accurately. As a side effect of this, it increases the file size. Reducing the image x,y to half should mean your output file size is roughly 1/4 of the original. However, turning each frame from just a few pixels difference to the full frame multiplies the size dramatically. As there are 35 frames, this more than makes up for the smaller width and height.

Luckily, ImageMagick (and Rmagick bindings in Ruby) includes a function for re-optimising the GIF back to layers with only the differences stored as visible pixels. You need to add a call to this optimize_layers method to allow your code to have a lower file size. In addition, for best file size you need to stop using .remap which is altering pixel values enough that the optimiser does not work.

require 'rmagick'
path = "/path/to/file/"
s_image = "s_image.gif" # image is 320*320
t_image = "t_image.gif"
file_name = path+s_image
file = File.new(file_name)
list = Magick::ImageList.new.from_blob file.read

# This renders out each GIF frame in full, prior to re-sizing
# Note I have removed the .remap because it alters pixel values
# between frames, making it hard to optimise
list = list.coalesce

list.each do |x|
  x.resize_to_fill!(256,256)
end

# Re-optimize the GIF frames
list = list.optimize_layers( Magick::OptimizeLayer )

File.open("#{path+t_image}", 'wb') { |f| f.write list.to_blob }
like image 140
Neil Slater Avatar answered Mar 28 '23 15:03

Neil Slater