I am trying to combine variable length PNG strips into a single GIF using the PHP GD and imagemagick libraries.
For example:
When combining these into one GIF there has to be enough frames for the longest animation, however the shorter animations do not have enough frames.
Right now, if there's not enough frames I just repeat the first frame, however as you would expect this leads to the animations stalling until they all restart:
The number of frames isn't totally random, however it's not always as clean as the examples. There are sets with a couple with 25 frames and the highest 36, and some with frames of 1, 3, 4, 9, 5, 12, 16, 26, etc.
The reasoning for wanting this is to combine all the strips into one big image that showcases a set of strips (with information about the sets themselves on it).
Is there a way of tackling this that I am missing? Or am I best just trying to double the strips until they're all at the highest frame count and removing a few frames here and there and hope no one notices?
Here's a MCVE that shows what I am doing now:
<?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");