当前位置: 首页 > 后端技术 > PHP

使用ImageMagick操作gif图片

时间:2023-03-29 14:12:32 PHP

在上一篇文章中,我们了解了GraphicsMagick中的很多功能。我们也说过GraphicsMagick是ImageMagick的一个分支,所以它们的很多功能的用法和作用都是一样的。我们也有类似的内容我就不多说了,感兴趣的朋友可以直接参考官方文档。本文我们要研究的是一个具体的案例,也是我在实际业务开发中接触到的一个案例。具体作用是,对于微信小游戏和小程序,不能直接使用动态Gif图,Gif图在小游戏和小程序中是不会动的。所以在我们公司的游戏开发中,需要将整个gif动画的每一帧拼接成一个sprite图片交给前端,我们拆帧后他们会利用JS+CSS的能力动态循环图片,从而形成动画效果。业务需求就是如此。当然,最终的解决方案也是使用ImageMagick实现的。话不多说,我们先看代码。GIF分帧的原图是这样一个动画:$imgPath='../img/4.gif';$imagick=new\Imagick($imgPath);$imagick=$imagick->coalesceImages();$imageCount=$imagick->count();echo'图像计数:',$imageCount,PHP_EOL;//图片数量:51$imgAttrs=['width'=>$imagick->getImageWidth(),'height'=>$imagick->getImageHeight(),'frame_count'=>$imageCount,];$列=5;如果($imageCount<$column){$column=$imageCount;}$row=ceil($imageCount/$column);$spImgWidth=$imgAttrs['width']*$column;$spImgHeight=$imgAttrs['高度']*$row;//创建图像$spImg=new\Imagick();$spImg->setSize($spImgWidth,$spImgHeight);$spImg->newImage($spImgWidth,$spImgHeight,new\ImagickPixel('#ffffff00'));$spImg->setImageFormat('png');$i=0;$h=0;$cursor=0;do{如果($i==$column){$i=0;$h++;}if($cursor==0){//保存第一帧图像$imagick->writeImage($imgPath.'.first.png');}//将所有图像帧保存为png图像$spImg->compositeImage($imagick,\Imagick::COMPOSITE_DEFAULT,$i*$imgAttrs['宽度'],$h*$imgAttrs['高度']);$i++;$cursor++;}while($imagick->nextImage());$spImg->writeImage($imgPath.'.png');不用多说,实例化Imagick对象,我们首先调用coalesceImages()这个方法来返回合成的Imagick对象。通过这种方法,我们得到了整张GIF图片中每一帧的所有信息。这时使用count()方法获取图片中所有图片的帧数。比如我们测试的图片有51帧。然后计算sprite图片的行数和列数以及对应的需要的宽高。比如我们以5列为基准,也就是将5张拆解后的图片排成一行,那么一共需要11行来拟合最终生成的精灵图。同理,宽高也乘以拆解图的宽高乘以对应的列数和行数。然后,根据计算出的宽高生成一张新的图片,并使用newImage()函数设置图片的宽高和背景透明度作为精灵图片的背景图片。使用setImageFormat()方法将图像的格式设置为PNG格式。PNG的使用主要是为了透明。其实根据我们紧密排列的图片,不一定要透明,但是有些应用比如网站前端需要的sprite图片可能会不一样。图片之前需要有一定的间隔,所以一般使用透明底图。然后就是循环,就是循环遍历已经去帧的51张图片,使用nextImage()不断获取下一帧原GIF图片,存入上面新建的背景图片中,每一帧的图片的position也是通过单帧图片的宽高和行列来计算的。在这段代码中,我们还保存了第一帧的图片。当然,这也是业务需求。您可以随时保存每一帧的任何图片。最后,使用writeImage()保存图像。输出图片如下:组合成动态GIF。以上业务功能是我在开发中实际使用过的功能。当然,除了分解GIF,我们还可以将多张图片组合起来。转换为动态GIF图像。$gifImagek=newImagick();$gifImagek->setFormat('GIF');for($i=1;$i<=5;$i++){$img=newImagick('../img/3'.$i.'.jpeg');$img->setImageDelay(100);$gifImagek->addImage($img);}$gifImagek->writeImages("../img/5.gif",true);$gifImagek->writeImages("../img/52.gif",false);这段代码比较简单,还是创建一张图片,并指定格式为GIF图片。然后循环添加图片。这里我们使用上一篇文章中已经在GraphicsMagick中操作过的图片。setImageDelay()用于设置图片显示间隔,这里我们设置为100毫秒,然后使用addImage()将图片添加到我们新建的GIF图片画布中。最后保存图片的时候,需要用writeImages()来保存。它的作用就是保存这个连续的多张图片。它的第二个参数是指定是否将图片保存为一张图片。如果为false,则类似于解框的效果,但是会一张一张保存图片,比如52-1.gif,52-2.gif这样。最终生成的动图是这样的:总结今天的内容很有意思,不是那些烂大街的缩放、水印、验证码等功能,而是对GIF图片的更有趣的操作。说实话,业务开发中类似的业务场景还有很多。比如自动生成sprite图片的功能可以用ImageMagick来实现,用ImageMagick扩展自带的函数就可以搞定,非常方便。测试代码:https://github.com/zhangyue0503/dev-blog/blob/master/php/202012/source/5。使用ImageMagick来操作gif图像。PHP参考文档:https://www.php.net/manual/zh/book.imagick.php各媒体平台均可搜索【硬核项目经理】