使用ImageMagick扩展gif

时间:2014-12-20 12:40:09

标签: ruby imagemagick rmagick

我正在开发一个有多个插件的项目,其中一个插件需要将两个动画图像合在一起。问题是其中一个将是用户定义的,很可能不会与另一个相匹配。

我现在如何解决这个问题是通过加载两个图像,找到它们帧数的最低公倍数,然后一遍又一遍地提取它们直到我点击它们的LCM,然后将提取的图像重新组合成单​​独的gif文件,然后将这两者合成在一起。以下是扩展的相关代码:

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

问题在于它部署在具有1GB内存的服务器上,并且在ruby中运行此代码需要500MB或更多,具体取决于用户定义的gif有多少帧或多大,不包括内存转换过程需要。因此,我希望不再使用rmagick和ruby,而是将流程放到我可用的外部工具上,这可以在一定程度上限制内存使用。

这让我想到了一个问题:如何使用imagemagick命令行工具复制此过程?

编辑:

根据要求,这里有一些示例图像和输出。这应该适用于任何两个图像,假设一个人具有透明背景。

背景图片(3帧):

前景图像(11帧):

结果(前景重复3次,背景重复11次)。

3 个答案:

答案 0 :(得分:1)

刚开始,但要和孩子们一起出去: - )

稍后会回来......

#!/bin/bash
# Get filenames from params or use defaults if none supplied
im1=${1:-http://i.imgur.com/C9IT9SY.gif}
im2=${2:-http://i.imgur.com/MlFOzAE.gif}

# Coalesce them
convert "$im1" -coalesce i1.gif
convert "$im2" -coalesce i2.gif

# Get number of frames in each sequence
nframes1=$(identify -format "%n" i1.gif)
nframes2=$(identify -format "%n" i2.gif)
echo DEBUG: nframes1:$nframes1
echo DEBUG: nframes2:$nframes2

# Calculate lcm using awk
lcm=$(awk -v n1=$nframes1 -v n2=$nframes2 '
    function gcd(m,n,t) {
    while (n != 0) {
        t = m
        m = n
        n = t % n
    }
    return m
    }
    function lcm(m,n,r) {
    if (m == 0 || n == 0)
        return 0
    r = m * n / gcd(m, n)
    return r < 0 ? -r : r
    }
    BEGIN {print lcm(n1,n2)}')

echo $lcm

i=0
while [[ $i -lt $lcm ]]; do
    f1=$((i % nframes1))
    f2=$((i % nframes2))
    n1=$(printf "1_#%04d" $i)
    n2=$(printf "2_#%04d" $i)
    echo $i,$f1,$f2,$n1,$n2
    ((i++))
done

<强>输出

DEBUG: nframes1:3
DEBUG: nframes2:11
LCM:33
0,0,0,1_#0000,2_#0000
1,1,1,1_#0001,2_#0001
2,2,2,1_#0002,2_#0002
3,0,3,1_#0003,2_#0003
4,1,4,1_#0004,2_#0004
5,2,5,1_#0005,2_#0005
6,0,6,1_#0006,2_#0006
7,1,7,1_#0007,2_#0007
8,2,8,1_#0008,2_#0008
9,0,9,1_#0009,2_#0009
10,1,10,1_#0010,2_#0010
11,2,0,1_#0011,2_#0011
12,0,1,1_#0012,2_#0012
13,1,2,1_#0013,2_#0013
14,2,3,1_#0014,2_#0014
15,0,4,1_#0015,2_#0015
16,1,5,1_#0016,2_#0016
17,2,6,1_#0017,2_#0017
18,0,7,1_#0018,2_#0018
19,1,8,1_#0019,2_#0019
20,2,9,1_#0020,2_#0020
21,0,10,1_#0021,2_#0021
22,1,0,1_#0022,2_#0022
23,2,1,1_#0023,2_#0023
24,0,2,1_#0024,2_#0024
25,1,3,1_#0025,2_#0025
26,2,4,1_#0026,2_#0026
27,0,5,1_#0027,2_#0027
28,1,6,1_#0028,2_#0028
29,2,7,1_#0029,2_#0029
30,0,8,1_#0030,2_#0030
31,1,9,1_#0031,2_#0031
32,2,10,1_#0032,2_#0032

答案 1 :(得分:0)

因此,经过一些麻烦并查看其他一些不相关的问题后,我发现你可以多次指定相同的图像来继续提取。我的更新代码尚未清理,但现在是:

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

答案 2 :(得分:0)

这不是您需要处理的 帧数 的LCM,它是 周期时间的LCM

只要周期时间 相同 ,就可以将3帧GIF和11帧GIF组合在一起产生单个11,12,13或14帧GIF,通过交织它们的帧并在必要时分割帧间延迟。

相反,如果你想组合两个简单的2帧GIF,循环时间分别为1000毫秒和1001毫秒,你得到的组合GIF将有1,001,000帧!

最好的方法是在浏览器中叠加动画。我知道你在定位和覆盖两个图像时有结构限制。您仍然可以使用单个IMG标记在浏览器中将它们组合在一起,如下所示:

  <img src="foreground.gif" style="background-image: url(background.gif)" />

然后,您需要在服务器上执行的操作是调整用户选择的foreground.gif的非常简单的任务,因此它与预定义的background.gif大小相同。

ps:如果你想将GIF与ImageMagick或其他工具结合起来,你可以通过分析原始调色板并创建一个用于所有帧的单个全局调色板来大大减小文件大小,它们可以优化去除多余的像素。在帧对之间改变。您的450KB组合动画无法真正优化,因为每个帧都有自己独立的调色板,这些调色板来自两个原始帧的两个调色板。