利用Imagick+php对图片进行优化(一)
微wx笑
2022-03-21【编程语言】
184
2
0关键字:
php imagick
严格图片缩放顾名思义,将图片进行严格缩放到规定尺寸,允许图片变形。 严格切图 严格按照指定尺寸进行切图 大头贴举例说明,原图尺寸(1500*1000),需求尺寸(1000*800),利用该方法进行处
目录
严格图片缩放
顾名思义,将图片进行严格缩放到规定尺寸,允许图片变形。 严格切图 严格按照指定尺寸进行切图 大头贴
举例说明,原图尺寸(1500*1000),需求尺寸(1000*800),利用该方法进行处理时首先将图片以最小缩放的方式缩放,然后再将图片切割到需求尺寸,即先将图片缩成1200*800,再进行切割。
自定义缩放
调用人员指定需求尺寸,同时指定缩放模式(按较大边进行缩放还是按照较小边进行缩放)……
添加水印
顾名思义……
实现示例
添加水印
代码
方案1(处理动态gif有问题):
1 | 1 $im = new Imagick();//初始化一个IM对象 |
1 | 2 $im->readImage("/home/ben/xiao2.gif");//将带处理图片读入IM对象 |
1 | 3 $water = new Imagick();//再初始化一个IM对象,用于临时存储水印图 |
1 | 4 $water->readImage("/home/ben/watermark.png");//读入水印图 |
1 | 5 for($i = 0;$i < $im->getNumberImages();$i++)//由于gif是多帧图片,需要一帧帧处理 |
1 | 6 { |
1 | 7 $im->setImageIndex($i);//设定当前待处理帧 |
1 | 8 $im->compositeimage($water,Imagick::COMPOSITE_OVER,0,0);//合并水印 |
1 | 9 } |
1 | 10 //file_put_contents("/home/ben/result.gif",$im->getImagesBlob(),FILE_APPEND);//输出方案1 |
1 | 11 $im->writeImages("/home/ben/result3.gif",true);//输出方案2 |
1 | <br> |
1 | 2 function addWatermarkOnAllImgs($im,$water,$x,$y) |
1 | 3 { |
1 | 4 $format = strtolower($im->getImageFormat()); |
1 | 5 $color_transparent = new ImagickPixel("transparent"); //透明色 |
1 | 6 7 $dest = new Imagick(); |
1 | 8 foreach($im as $img) |
1 | 9 { |
1 | 10 $page = $img->getImagePage();//获得当前图片属性 |
1 | 11 $tmp = new Imagick(); |
1 | 12 $tmp->newImage($page['width'], $page['height'], $color_transparent, $format);//生成一张同大小的透明图片 |
1 | 13 $tmp->compositeImage($img, Imagick::COMPOSITE_OVER, $page['x'], $page['y']);//合并当前图片 |
1 | 14 $tmp->compositeImage($water,Imagick::COMPOSITE_OVER,$x,$y);//合并水印 |
1 | 15 16 $dest->addImage($tmp);//将图片添加进新的IM容器 |
1 | 17 $dest->setImagePage($tmp->getImageWidth(), $tmp->getImageHeight(), 0, 0);//设定图片的几何属性 |
1 | 18 $dest->setImageDelay($img->getImageDelay());//设定图片延迟 |
1 | 19 $dest->setImageDispose($img->getImageDispose());//设定动画处理方式 |
1 | 20 } |
1 | 21 $dest->coalesceImages();//合并IM容器中的所有图片 |
1 | 22 $dest->writeImages("/home/ben/addwater.gif",true); |
1 | 23 return true; |
1 | 24 } |
1 | 25 $src = new Imagick(); |
1 | 26 $src->readImage("/home/ben/xiao2.gif"); |
1 | 27 $water = new Imagick(); |
1 | 28 $water->readImage("/home/ben/watermark.png"); |
1 | 29 addWatermarkOnAllImgs($src,$water,0,0); |
处理结果
1.原始图片
2.处理结果
2.1 方案一
2.2 方案二
注意事项
从以上处理结果可以看出,如果不逐帧进行处理会造成水印时隐时现的现象,为此在处理多帧图片时必须注意以下几点:
(1)处理多帧图片时必须循环得到各帧图片,然后进行相关处理;
(2)输出图片时(writeImages或getImagesBlob)一定注意image的复数形式,不然只会得到当前一帧静态图片,而非动态gif动画。
(3)动画处理方式(disposal method):
a)None--不进行处理。选择此方式时,下一帧的内容会直接覆盖在当前帧的内容上面。
b)Restore to Background--恢复背景色。此选项会首先擦除当前帧的图像内容,然后恢复到背景色或背景图案(如果背景是透明的,就恢复成透明),接下来在显示下一帧的内容。此选项常用在背景透明的动画上。
c)Restore to Previous--恢复上一帧。此选项会擦除当前帧的内容,然后恢复上一帧的内容,接下来在显示下一帧的内容。
两种方案的比较:
从处理结果可以清楚的看出不同,其原因正如http://wxw850227.iteye.com/blog/402085中所述------动画的每一帧图片大小不一定相同,采用方案一会造成图片因添加水印位置的不统一而发生错乱
gif图片调整大小
代码
1 | function resizeImage($filename,$width,$height) |
1 | { |
1 | $src = new Imagick(); |
1 | $src->readImage($filename); |
1 | $framenum = $src->getNumberImages(); |
1 | if($framenum>1) |
1 | { |
1 | $format = strtolower($src->getImageFormat());//获得图片格式,备用 |
1 | $dest = new Imagick(); |
1 | $color_transparent = new ImagickPixel("transparent"); //透明色 |
1 | foreach($src as $img) |
1 | { |
1 | $page = $img->getImagePage(); |
1 | $tmp = new Imagick(); |
1 | $tmp->newImage($page['width'], $page['height'], $color_transparent, $format);//在临时IM对象中生成一张同大小透明新图 |
1 | $tmp->compositeImage($img, Imagick::COMPOSITE_OVER, $page['x'], $page['y']);//合并原图 |
1 | $tmp->resizeimage($width,$height,Imagick::FILTER_UNDEFINED,0.75,false);//重设图片大小 |
1 | $dest->addImage($tmp);//将处理后的图片放入输出IM对象中 |
1 | $dest->setImagePage($tmp->getImageWidth(), $tmp->getImageHeight(), 0, 0);//设定当前图片大小 |
1 | $dest->setImageDelay($img->getImageDelay());//设定图片延迟 |
1 | $dest->setImageDispose($img->getImageDispose());//设定动画处理方式 |
1 | } |
1 | $dest->coalesceImages();//合并所有图片 |
1 | $dest->writeImages("/home/ben/resize.gif",true); |
1 | } |
1 | else |
1 | { |
1 | $src->resizeimage($width,$height,Imagick::FILTER_UNDEFINED,0.75,false); |
1 | $src->writeImages("/home/ben/resize.gif",true); |
1 | } |
1 | } |
1 | resizeImage("/home/ben/xiao.gif",200,200); |
处理结果
注意事项
也许有人会说,简单的缩放干嘛搞这么复杂直接采用如下的方式逐帧缩放不就完了?
1 | for($i=0;$i<$framenum;$i++) |
1 | { |
1 | $src->setImageIndex($i); |
1 | $src->resizeimage($width,$height,Imagick::FILTER_UNDEFINED,0.75,false); |
1 | } |
有人提出了对gif动画逐帧缩放时存在的问题:
(1)透明动画的问题
(2)帧图片比显示尺寸小,并且有坐标控制的问题,直接缩小会使得动画完全乱掉
并给出了上述解决办法,故借鉴别人的繁琐但有效的处理方式。
附加几点注意事项:
1.resizeimage()可以利用第四个参数来增加模糊效果,=1相当于没有添加效果;<1,相当于锐化图片,使图片更清晰;>1,其值越大就会越模糊;=0时,是无穷大的模糊,也就是变成一片黑……0.75是一个经验值,利用该值可以调整绝大多数图片因缩放所带来的模糊。
2.有关resizeimage与scaleImage():二者均可以用于图片缩放,不同之处在于:Resizing the image changes the dimensions of the image without applying a transformation to the existing contents. Scaling the image will stretch the existing contents to the new dimensions.用事实说话吧:
如下图为用scale处理后的同一张图,与resize处理后的效果非常明显(够恶心的哈):
3.一种错误的处理方式:
3.1 code
1 | $format = strtolower($src->getImageFormat()); |
1 | $dest =new Imagick(); |
1 | $color_transparent = new ImagickPixel("transparent"); //透明色 |
1 | $src_page = $src->getImagePage(); |
1 | $src_width = $src_page['width']; |
1 | $src_height = $src_page['height']; |
1 | $rate_w = $width/$src_width; |
1 | $rate_h = $height/$src_height; |
1 | foreach($src as $img) |
1 | { |
1 | $page = $img->getImagePage(); |
1 | // $img->resizeimage($page['width']*$rate_w,$page['height'] |
1 | *$rate_h,Imagick::FILTER_UNDEFINED,1,false); |
1 | // $img->resizeimage($width,$height,Imagick::FILTER_UNDEFINED,1,false); |
1 | $img->setImagePage($page['width']*$rate_w,$page['height']*$rate_h,$page['x']*$rate_w,$page['y']*$rate_h); |
1 | $page = $img->getImagePage(); |
1 | $tmp = new Imagick(); |
1 | $tmp->newImage($page['width'], $page['height'], $color_transparent, $format); |
1 | $tmp->compositeImage($img, Imagick::COMPOSITE_OVER, $page['x'], $page['y']); |
1 | // $tmp->resizeimage($width,$height,Imagick::FILTER_UNDEFINED,1,false); |
1 | $dest->addImage($tmp); |
1 | $dest->setImagePage($tmp->getImageWidth(), $tmp->getImageHeight(), 0, 0); |
1 | $dest->setImageDelay($img->getImageDelay()); |
1 | $dest->setImageDispose($img->getImageDispose()); |
1 | } |
1 | $dest->coalesceImages(); |
1 | $dest->writeImages("/home/ben/zoomres1.gif",true); |
3.2 处理结果
3.3 原因分析
与可行代码的差异描述:
可行代码是将当前图片合并到一新的IM容器中,然后对该图片进行缩放,最后将该图片合并;上述代码的操作步骤为:先将当前图片进行缩放,再新建一个IM容器,将缩放后的图片合并到IM容器的透明图上,最后将所有图片合并。可以预见这样处理会发生坐标偏移,尝试用setImagePage来控制图片坐标,仍不对……原因未明~~
大头贴效果
明显可以看出缩放切割效果~
转自:http://blog.sina.com.cn/s/blog_6bf82eb20100w5lr.html
本文为转载文章,版权归原作者所有,不代表本站立场和观点。