GD库是否不能将处理后的gif图片,保持动态效果?

seai 2011-01-14 06:28:43
这几天需要处理图片的问题,发现gd库生成的gif缩略图,全部成了静态的了。

如何解决这个问题呢?
...全文
655 24 打赏 收藏 转发到动态 举报
写回复
用AI写文章
24 条回复
切换为时间正序
请发表友善的回复…
发表回复
seai 2011-01-19
  • 打赏
  • 举报
回复
[Quote=引用 23 楼 luciferstar 的回复:]

暂时没有找到支持5.3.x的imagick扩展:(
[/Quote]

找就有了,正在使用php5.3.2
LuciferStar 2011-01-19
  • 打赏
  • 举报
回复
暂时没有找到支持5.3.x的imagick扩展:(
seai 2011-01-19
  • 打赏
  • 举报
回复
[Quote=引用 19 楼 h2ero 的回复:]

这儿那个别人修改过的
GIFEncoder
http://code.h2ero.cn/code/classes/gif.zip
[/Quote]


GIFEncoder存在的问题已经找出来了,稍后代码整理好考虑与大家分享!
skyaspnet 2011-01-18
  • 打赏
  • 举报
回复
要保持GIF上传后的动画效果,可以考虑使用 PHP ImageMagick MagickWand 无变形缩略图程序


发布一个采用php下ImageMagick的扩展库,MagickWand缩略图程序,以前发过一个GD2的处理程序,图片处理后的效果还可以接受,不过没有MagickWand处理的效果好,在生成的缩略图比较大时,比如有一张照片 2296X1528px的大照片,裁剪为宽度800以内的,使用MagickWand足足耗时10多秒,不知道是不是算法有问题,不过同样的算法采用GD2实现的处理起来非常快速,基本上为1秒多,总之呢,先发布第一版本了,以后再完善,MagickWand最大的好处是支持Gif动画缩放,缩小后保持动画,还有bmp图像处理。调用方法也很简单,本来打算不用类的,不过后来还是觉得类封装一下方便代码书写。但是最后再封装成函数调用比较方便。
由原来的四种缩放裁剪模式修改为三种,去除第一种不常用的模式,
原GD2库的缩放程序在这里:
http://hi.baidu.com/smallchicken/blog/item/3549007716bb4713b151b913.html

<?php
/**
* 基于MagickWand的图片缩略图程序, php magick thumb
* Author: smallchicken
* E-mail: microji@163.com
* Version: 1.0
* 用法:直接调用 magick_thumb函数,传入参数:
* magick_thumb($src_image_dir.$src_image,$dst_thumb_dir.$dst_image,100,100,1);
* $src_file : 原文件路径 , $dst_file :保存文件路径 , $dst_width :生成文件宽 , $dst_height:生成文件高,$mode=1 裁剪方式
* GIF动画缩略到不大于传入的高宽值,并且保留动画效果,GIF非动画格式和其他格式一样处理。
* 参数 $mode 说明:
* $mode=1 :生成固定高宽的图像,图片缩放后铺满,为了铺满,会有部分图像裁剪掉。
* $mode=2 :生成固定高宽的图像,图片缩放后不一定铺满,但保留全部图像信息,即不裁剪,添加补白。
* $mode=3 :生成图像高宽不大于给定高宽,并且以缩放后的实际大小保持。
*
*/
function magick_thumb($src_file,$dst_file,$dst_width,$dst_height,$mode=1) {
$mp = new MagickProcess($src_file);
return $mp->MagickThumb($dst_file,$dst_width,$dst_height,$mode);
}

class MagickProcess {
var $src_mw;
var $src_file;
var $src_width;
var $src_height;
var $src_ext;
var $src_format;
var $is_img;
function MagickProcess($src_file) {
$this->src_file = $src_file;
$this->src_mw = NewMagickWand();
$this->is_img=MagickReadImage($this->src_mw,$src_file);
if(!$this->is_img) return;
$this->format = MagickGetImageFormat($this->src_mw);
$this->src_width =MagickGetImageWidth($this->src_mw);
$this->src_height =MagickGetImageHeight($this->src_mw);
}
function IsAnimation() {
$fp=fopen($this->src_file, 'rb');
$image_head = fread($fp,1024);
fclose($fp);
return preg_match("/".chr(0x21).chr(0xff).chr(0x0b).'NETSCAPE2.0'."/",$image_head) ? true : false;
}
function MagickThumb($dst_file,$dst_width,$dst_height,$mode=1) {
if(!$this->is_img) return false;
$src_width = $this->src_width;
$src_height= $this->src_height;
$ratio_w=1.0 * $dst_width / $src_width;
$ratio_h=1.0 * $dst_height / $src_height;
$ratio=1.0;
if(strtolower($this->format)=='gif') {
if ($this->IsAnimation()) {
$this->ResizeGif($dst_file, $dst_width, $dst_height);return;
}
}
switch($mode) {
case 1: // 生成固定高宽,超过的裁剪掉
if($ratio_w < 1 && $ratio_h < 1) { // 都缩小
$ratio = $ratio_w < $ratio_h ? $ratio_h : $ratio_w;
$crop_width = (int)($dst_width / $ratio);
$crop_height = (int)($dst_height / $ratio);
$crop_x = (int) ($src_width-$crop_width)/2 ;
$crop_y = (int) ($src_height-$crop_height)/2 ;
MagickCropImage($this->src_mw, $crop_width, $crop_height, $crop_x, $crop_y);
$this->ResizeImage($this->src_mw, $dst_width, $dst_height);
$this->SaveImage($this->src_mw, $dst_file);
}elseif($ratio_w > 1 && $ratio_h > 1) {
$dst_mkwd=NewMagickWand();
MagickNewImage($dst_mkwd,$dst_width,$dst_height,'#FFFFFF');
$dst_x = (int) abs($dst_width - $src_width) / 2 ;
$dst_y = (int) abs($dst_height -$src_height) / 2;
MagickCompositeImage($dst_mkwd ,$this->src_mw, MW_OverCompositeOp, $dst_x, $dst_y ) ; // 合并图像,拷贝到目标图像的x,y坐标点
$this->SaveImage($dst_mkwd, $dst_file);
DestroyMagickWand($this->src_mw);
}else {
// 一边长,一边短,先裁去长的边。
$crop_x=$crop_y=0;
$crop_width = min($src_width , $dst_width);
$crop_height = min($src_height, $dst_height);
$crop_x = (int) ($src_width-$crop_width)/2 ;
$crop_y = (int) ($src_height-$crop_height)/2 ;

MagickCropImage($this->src_mw, $crop_width, $crop_height, $crop_x, $crop_y);
$dst_mkwd=NewMagickWand();
MagickNewImage($dst_mkwd,$dst_width,$dst_height,'#FFFFFF');

$dst_x = (int) ($dst_width-$crop_width)/2 ;
$dst_y = (int) ($dst_height-$crop_height)/2 ;
MagickCompositeImage($dst_mkwd ,$this->src_mw, MW_OverCompositeOp, $dst_x, $dst_y ) ; // 合并图像,拷贝到目标图像的x,y坐标点
$this->SaveImage($dst_mkwd, $dst_file);
DestroyMagickWand($this->src_mw);
}
break;
case 2: // 生成固定高宽,保留全部信息,只缩放,不裁剪
if($ratio_w > 1 && $ratio_h > 1) {
$dst_mkwd=NewMagickWand();
MagickNewImage($dst_mkwd,$dst_width,$dst_height,'#FFFFFF');
$dst_x = (int) abs($dst_width - $src_width) / 2 ;
$dst_y = (int) abs($dst_height -$src_height) / 2;
MagickCompositeImage($dst_mkwd ,$this->src_mw, MW_OverCompositeOp, $dst_x, $dst_y ) ;
$this->SaveImage($dst_mkwd, $dst_file);
DestroyMagickWand($this->src_mw);
}else {
$ratio = $ratio_w > $ratio_h ? $ratio_h : $ratio_w;
$tmp_w = (int)($src_width * $ratio);
$tmp_h = (int)($src_height * $ratio);
$this->ResizeImage($this->src_mw, $tmp_w, $tmp_h);
$dst_mkwd=NewMagickWand();
MagickNewImage($dst_mkwd,$dst_width,$dst_height,'#FFFFFF');
$dst_x = (int) abs($tmp_w - $dst_width) / 2 ;
$dst_y = (int) abs($tmp_h - $dst_height) / 2;
MagickCompositeImage($dst_mkwd ,$this->src_mw, MW_OverCompositeOp, $dst_x, $dst_y ) ;
$this->SaveImage($dst_mkwd, $dst_file);
DestroyMagickWand($this->src_mw);
}
break;
case 3: // 超过缩放,不超过直接存图。
if($ratio_w > 1 && $ratio_h > 1) {
$this->SaveImage($this->src_mw, $dst_file);
}else {
$ratio = $ratio_w > $ratio_h ? $ratio_h : $ratio_w;
$tmp_w = (int)($src_width * $ratio);
$tmp_h = (int)($src_height * $ratio);
$this->ResizeImage($this->src_mw, $tmp_w, $tmp_h);
$this->SaveImage($this->src_mw, $dst_file);
}
break;
}
return true;
}
function ResizeGif($dst_file,$dst_width, $dst_height) {
MagickResetIterator($this->src_mw);
do {
$iw = MagickGetImageWidth($this->src_mw);
$ih = MagickGetImageHeight($this->src_mw);
$iratio=1.0;
$iratio_w = doubleval($iw) / doubleval($dst_width);
$iratio_h = doubleval($ih) / doubleval($dst_height);
$iratio = $iratio_w > $iratio_h ? $iratio_w : $iratio_h;
$tmp_w = floor( $iw / $iratio);
$tmp_h = floor( $ih / $iratio);
$this->ResizeImage($this->src_mw, $tmp_w, $tmp_h);
} while(MagickNextImage($this->src_mw));
$this->SaveImage($this->src_mw, $dst_file);
}

function ResizeImage($mgk, $dst_width, $dst_height) {
MagickResizeImage( $mgk, $dst_width, $dst_height, MW_LanczosFilter, 1.0);
//MagickSampleImage($mw, $dst_width, $dst_height); // Resize的效果好于Sample
//MagickScaleImage($mw, $dst_width, $dst_height);
/*
*
MW_PointFilter MW_BoxFilter
MW_TriangleFilter MW_HermiteFilter
MW_HanningFilter MW_HammingFilter
MW_BlackmanFilter MW_GaussianFilter
MW_QuadraticFilter MW_CubicFilter
MW_CatromFilter MW_MitchellFilter
MW_LanczosFilter MW_BesselFilter
MW_SincFilter
*/
}
function SaveImage($mgk,$dst_file) {
MagickSetFormat($mgk, $this->format);
MagickWriteImages($mgk, $dst_file, MagickTrue);
DestroyMagickWand($mgk);
unset($mgk);
}
}// end class
?>
skyaspnet 2011-01-18
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 seai 的回复:]
引用 6 楼 h2ero 的回复:

引用 1 楼 luciferstar 的回复:

gif应该不可以。
感觉可以将每一帧都读出来然后全部重新缩略,然后重新生成?
gif的没弄过。
如同一楼所说的,楼主可以先将其每一帧处理后在生成,上次我也在弄个这个问题,有两个类
分别是解码GIFDecoder.class.php和编码GIFEncoder.class.php的楼主自己研究下 h……
[/Quote]

GD库确实不可以
seai 2011-01-18
  • 打赏
  • 举报
回复
toh2ero

我csdn的空间不能批准加好友,加QQ35513767聊吧,谢谢
seai 2011-01-18
  • 打赏
  • 举报
回复
[Quote=引用 19 楼 h2ero 的回复:]

这儿那个别人修改过的
GIFEncoder
http://code.h2ero.cn/code/classes/gif.zip
[/Quote]


你下我的文件去试试看好吗?我用的就是这个包,但某些gif就是合并后差异明显。我分析过,提取每一帧没问题。但吧提取出来的帧重新合并就变化了。不是说总是这样,我也试过有些gif合并后,起码肉眼看不出毛病。但我上面包里面给的gif文件,提取、合并就是有问题。但我用imagick合并是没问题(码肉眼看问题)。
h2ero 2011-01-18
  • 打赏
  • 举报
回复
这个处理效率还是比较高,反正貌似比使用im简单点点,当初自己弄这个问题最后还是没有用im处理,
h2ero 2011-01-18
  • 打赏
  • 举报
回复
这儿有个演示,解码gif为帧,添加新帧,然后再生成gif;
http://code.h2ero.cn/temp/gifs/decode_a_gif.php
楼主那两个类你没有下来看看~~~
呜呜呜呜~~~~~
h2ero 2011-01-18
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 skyaspnet 的回复:]

引用 7 楼 seai 的回复:
引用 6 楼 h2ero 的回复:

引用 1 楼 luciferstar 的回复:

gif应该不可以。
感觉可以将每一帧都读出来然后全部重新缩略,然后重新生成?
gif的没弄过。
如同一楼所说的,楼主可以先将其每一帧处理后在生成,上次我也在弄个这个问题,有两个类
分别是解码GIFDecoder.class.php和编码GIFEncoder.……
[/Quote]
囧~~ 那个是别人写的类,先解码提取每一帧,然后再对每一帧处理,处理了将这些帧重新生成gif,im是挺简单不过要安装扩展,
h2ero 2011-01-18
  • 打赏
  • 举报
回复
这儿那个别人修改过的
GIFEncoder
http://code.h2ero.cn/code/classes/gif.zip
h2ero 2011-01-18
  • 打赏
  • 举报
回复
楼上的这儿,无损的,我觉得比较简单,不过对gif的文件编码不懂,
http://code.h2ero.cn/temp/gifs/gif.php
h2ero 2011-01-18
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 seai 的回复:]

引用 14 楼 h2ero 的回复:

这儿有个演示,解码gif为帧,添加新帧,然后再生成gif;
http://code.h2ero.cn/temp/gifs/decode_a_gif.php
楼主那两个类你没有下来看看~~~
呜呜呜呜~~~~~



下来试过了。有个麻烦的问题,楼上用过的朋友能否解决?

就是分离出来的帧,使用GIFEncoder合并后,动画中有几个帧……
[/Quote]

那个问题是存在,不过后来又有人写了个,就是在那个GIFEncoder的基础上面修改了下,基本上解决了,你看我生成的那个都没有画质问题,
当时看别人的demo基本上是无损的,我在弄几张随机生成的大图给你看看,
seai 2011-01-18
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 h2ero 的回复:]

这儿有个演示,解码gif为帧,添加新帧,然后再生成gif;
http://code.h2ero.cn/temp/gifs/decode_a_gif.php
楼主那两个类你没有下来看看~~~
呜呜呜呜~~~~~
[/Quote]


下来试过了。有个麻烦的问题,楼上用过的朋友能否解决?

就是分离出来的帧,使用GIFEncoder合并后,动画中有几个帧出现严重的画质问。但使用imagick合并那些帧就不会有这种现象。可见GIFEncoder的合并算法似乎存在问题。


http://u.115.com/file/t5a016496b#gifmerge.zip

里面test.gif是原图。testXX.gif是分离的各帧。
在-云端 2011-01-17
  • 打赏
  • 举报
回复
呵呵!!每个人工作涉及到的扩展不同!!有熟悉的,也有不熟悉的!lz要蛋定!@

------------------测试哥的签名--------------------------
哥默默的低下头,不是哥修养好,而是哥在找砖头!(哥又回来了)
--------------------------------------------------------
LuciferStar 2011-01-17
  • 打赏
  • 举报
回复
哈哈,每个扩展都有其擅长的部分,正如每个人都有自己擅长的部分。
seai 2011-01-15
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 h2ero 的回复:]

引用 1 楼 luciferstar 的回复:

gif应该不可以。
感觉可以将每一帧都读出来然后全部重新缩略,然后重新生成?
gif的没弄过。
如同一楼所说的,楼主可以先将其每一帧处理后在生成,上次我也在弄个这个问题,有两个类
分别是解码GIFDecoder.class.php和编码GIFEncoder.class.php的楼主自己研究下 http://code.h2ero.cn/……
[/Quote]


你们非常不靠谱。。。

起码我知道用im非常简单。

看来真正熟悉的人都不愿意来说。
h2ero 2011-01-15
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 luciferstar 的回复:]

gif应该不可以。
感觉可以将每一帧都读出来然后全部重新缩略,然后重新生成?
gif的没弄过。
[/Quote]如同一楼所说的,楼主可以先将其每一帧处理后在生成,上次我也在弄个这个问题,有两个类
分别是解码GIFDecoder.class.php和编码GIFEncoder.class.php的楼主自己研究下 http://code.h2ero.cn/code/classes/gif.zip
seai 2011-01-15
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 skyaspnet 的回复:]

gif是无法生成缩略图的,因为它是一帧一帧的,缩略后就会失去动画的效果的
[/Quote]

你话未免过于绝对吧?使用im库就可以,我只是不确定GD库是否可以。在这里向大家求证,竟然一个个懒得回答。。。
skyaspnet 2011-01-14
  • 打赏
  • 举报
回复
gif是无法生成缩略图的,因为它是一帧一帧的,缩略后就会失去动画的效果的
加载更多回复(2)

20,359

社区成员

发帖
与我相关
我的任务
社区描述
“超文本预处理器”,是在服务器端执行的脚本语言,尤其适用于Web开发并可嵌入HTML中。PHP语法利用了C、Java和Perl,该语言的主要目标是允许web开发人员快速编写动态网页。
phpphpstorm 技术论坛(原bbs)
社区管理员
  • 开源资源社区
  • phpstory
  • xuzuning
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧