php - 组合不同长度的 GIF
问题描述
我正在尝试使用 PHP GD 和 imagemagick 库将可变长度的 PNG 条组合成一个 GIF。
例如:
当将这些组合成一个 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");
解决方案
最好的解决方案(但图像可能很大)是使用所有帧数的最小公倍数(在这种情况下为 72,所以不是那么多),并根据需要重复每个图像序列多次(18,9, 8,6,2)。
推荐阅读
- precision - 在 KQL 中以 2 的精度表示十进制?
- python - 频率大于1的Python常用词表
- fortran - Fortran 科学记数法 1d0 与 1.d0
- docker - 如何为子图像添加从基础 docker 图像覆盖 arg 的能力?
- python - Matplotlib:如何仅对散点图中的指定点进行动画处理?
- python - 我想在 Ubuntu 中使用 Python 修改系统 PATH,而不是 python sys.path 变量
- swift - 将动态字符串转换为属性字符串
- python - Tabpy:在运行 Tabpy 的 Docker 上功能部署失败
- sql-server - Laravel 开发如何连接运行在 Docker 上的 SQL Server 数据库
- r - R HighCharter - 自定义工具提示标题