I am working on a project that has multiple plugins, and one of the plugins needs to composite two animated images on top of one another. The problem is that one of these will be user-defined and will most likely not match up frame-wise to the other.
How I get around this currently is by loading both images, finding the lowest common multiple of their frame count, then extracting them over and over until I hit their LCM, then re-combining the extracted images into separate gif files, then compositing those two together. Here is the relevant code as far as the extending goes:
def self.extend_gifs(one, two)
img_one = Magick::ImageList.new(one).coalesce
img_two = Magick::ImageList.new(two).coalesce
lcm = img_one.length.lcm(img_two.length)
i = 0
while i < lcm
img_one[i % img_one.length].write("tmp/1_#{i.to_s.rjust(4, "0")}.png")
img_two[i % img_two.length].write("tmp/2_#{i.to_s.rjust(4, "0")}.png")
i += 1
end
%x{convert -limit memory 256MiB -dispose Background tmp/1_*.png tmp/extend_1.gif}
%x{convert -limit memory 256MiB -dispose Background tmp/2_*.png tmp/extend_2.gif}
Dir["tmp/*.png"].each { |f| File.delete f }
end
The problem is that this is deployed on a server with 1GB of memory, and running this code in ruby takes upwards of 500MB or more depending on how many frames or how big the user defined gif is, not including the memory that the convert process takes. Because of this, I want to move away from using rmagick and ruby and drop the process onto the external tools I have available which can limit memory usage to some degree.
This brings me to my question: How would I replicate this process using the imagemagick command line tools?
Edit:
By request, here are some example images and output. This should work for any two images though, assuming one has a transparent background.
Background image (3 frames):
Foreground image (11 frames):
Result (foreground repeated 3 times, background repeated 11 times).
So after some messing around and viewing some other questions that were unrelated I found out that you can specify the same image multiple times to continue extraction. My updated code isn't cleaned yet, but here it is:
def self.extend_gifs(one, two)
img_one = Magick::ImageList.new(one)
img_two = Magick::ImageList.new(two)
# Get the lcm of the frame counts
lcm = img_one.length.lcm(img_two.length)
# Get how many times to extract for each
mult_one = lcm / img_one.length
mult_two = lcm / img_two.length
# Multiply the image + coalecence out that many times
string_one = (" #{one} -coalesce ") * mult_one
string_two = (" #{two} -coalesce ") * mult_two
# Split images up so their frames match
%x{convert -limit memory 256MiB #{string_one} tmp/1_%04d.png}
%x{convert -limit memory 256MiB #{string_two} tmp/2_%04d.png}
# Merge gifs back together
%x{convert -limit memory 256MiB -dispose Background tmp/1_*.png tmp/extend_1.gif}
%x{convert -limit memory 256MiB -dispose Background tmp/2_*.png tmp/extend_2.gif}
# Delete temp files
Dir["tmp/*.png"].each { |f| File.delete f }
end