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?
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 }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With