首页 > 解决方案 > 组合不同长度的 GIF

问题描述

我正在尝试使用 PHP GD 和 imagemagick 库将可变长度的 PNG 条组合成一个 GIF。

例如:

第一条= 4 帧

第二条= 8 帧

第三条= 9 帧

第四条= 12 帧

在此处输入图像描述= 36 帧

当将这些组合成一个 GIF 时,最长的动画必须有足够的帧,但是较短的动画没有足够的帧。

现在,如果没有足够的帧,我只是重复第一帧,但是正如您所料,这会导致动画停止,直到它们全部重新启动:

结合

帧数不是完全随机的,但并不总是像示例那样干净。有一对夫妇25帧,最高36帧,有的帧数为1、3、4、9、5、12、16、26等。

想要这样做的原因是将所有条带组合成一个大图像,展示一组条带(上面有关于这些条带本身的信息)。

有没有办法解决我错过的这个问题?还是我最好只是尝试将条带加倍,直到它们都处于最高帧数并在这里和那里删除几帧并希望没有人注意到?

这是一个 MCVE,它显示了我现在在做什么:

<?php
$pngStrips = [
    "happy" => "https://i.stack.imgur.com/oq3Ex.png",
    "shocked" => "https://i.stack.imgur.com/AeoEs.png",
    "mk" => "https://i.stack.imgur.com/Ka6ho.png",
    "dance" => "https://i.stack.imgur.com/lZan3.png",
    "bored" => "https://i.stack.imgur.com/JiIN9.png"
];

$height = 130 * ceil(count($pngStrips) / 6);
$width = 150 * count($pngStrips);

// Set up the showase background gif (simplified to blank white for MCVE)
$background = imagecreatetruecolor($width, $height);
imagealphablending($background, true);
imagefill($background, 0, 0, imagecolorallocatealpha($background, 255, 255, 255, 0));

// Download from external source and split into frames and resize
$highestFrames = 0;
foreach($pngStrips as $name => $URL){    
    file_put_contents("./mcve/" . $name . ".png", file_get_contents($URL));

    $dim = getimagesize("./mcve/" . $name . ".png");

    exec("convert -crop " . $dim[1] . "x" . $dim[1] . " ./mcve/" . $name . ".png ./mcve/" . $name . "_frame_%02d.png");
    exec("convert ./mcve/" . $name . "_frame_*.png -thumbnail 90x90^ -gravity center -extent 90x90 ./mcve/" . $name . "_frame_%02d_resized.png");

    $frames = $dim[0] / $dim[1];

    if($frames > $highestFrames) $highestFrames = $frames;
}

// Every frame of the main gif
for($i = 0; $i < $highestFrames; $i++ ){
    $xcoord = 20;
    $ycoord = 5;
    $count = 1;

    // Make a new frame
    $frame = imagecrop($background, array('x'=>0,'y'=>0,'width'=>imagesx($background),'height'=>imagesy($background)));

    // Add the appropriate frame to this frame of the main gif
    foreach($pngStrips as $name => $URL) {
        $frameFile = "./mcve/" . $name . "_frame_" . sprintf("%02d", $i) . "_resized.png";
        if(!file_exists($frameFile)){
            $frameFile = "./mcve/" . $name . "_frame_00_resized.png";
        }

        $powerImage = imagecreatefrompng($frameFile);

        imagecopymerge($frame, $powerImage, $xcoord, $ycoord, 0, 0, 90, 90, 100);

        $xcoord += 145;

        if($count % 6 == 0){
            $xcoord = 20;
            $ycoord += 130;
        }
        $count++;
    }

    // Save frame
    imagepng($frame, "./mcve/final_frame_" . sprintf("%02d", $i) . ".png");
}

// Into 1 big gif
exec("convert -loop 0 ./mcve/final_frame_*.png ./mcve/final.gif");

header('Content-Type: image/gif');
echo file_get_contents("./mcve/final.gif");

标签: phpimagemagickphp-gd

解决方案


最好的解决方案(但图像可能很大)是使用所有帧数的最小公倍数(在这种情况下为 72,所以不是那么多),并根据需要重复每个图像序列多次(18,9, 8,6,2)。


推荐阅读