用php将动态gif拆分成单帧
程序员文章站
2022-05-13 14:43:00
...
我想把一个动态gif拆分成一帧一帧的 然后对单帧进行修改后再合并起来 在网上找了一段代码 但是在拆分成单帧的时候就出了问题 但是不知道错在哪里了 请各位大虾帮忙看看 代码如下
buffer, 0, $len);
$this->buffer = substr($this->buffer, $len);
if($len == 1)
return ord($ch);
return $ch;
}
/**
* 内部方法 get_number
* 从图片数据缓冲区读取一个整数
* 参数 无
* 返回 整数
**/
function get_number() {
$t = unpack("Sn", $this->next(2));
return $t['n'];
}
/**
* 构造函数
* 参数 $imagename 字符串,图片文件名或图片数据
* 返回 无
**/
function TGif($imagename="images/xzn.gif") {
$this->image = array();
$this->frame = 0;
if(is_file($imagename)) {
$this->imagename = $imagename;
$this->buffer = @file_get_contents($imagename)
or trigger_error("$imagename 打不开", E_USER_ERROR);
}else {
substr($imagename, 0, 3) == 'GIF' or
trigger_error("$imagename 不存在或不是GIF格式图片", E_USER_ERROR);
$this->buffer = $imagename;
$this->imagename = '未命名';
}
$this->get_header();
while(strlen($this->buffer)) {
switch($this->next()) {
case 0x21: //图象扩展描述符
$this->get_extension_introducer();
break;
case 0x2c: //图象描述符
$this->get_image_descriptor();
break;
case 0x3b: //GIF数据流结束
return;
}
}
}
/**
* 内部方法 get_color_table
* 读取调色板数据
**/
function get_color_table($num) {
return $this->next(3*pow(2,$num+1));
}
/**
* 内部方法 get_header
* 读取头信息
**/
function get_header() {
$this->signature = $this->next(3); //类型标识gif
if($this->signature != 'GIF')
trigger_error("$this->imagename 不是GIF格式图片", E_USER_ERROR);
$this->version = $this->next(3); //版本标识
$this->logical_screen_width = $this->get_number(); //逻辑屏幕宽
$this->logical_screen_height = $this->get_number(); //逻辑屏幕高
$this->flag = $flag = $this->next();
$this->global_color_table_flag = ($flag & 0x80) > 0; //是否有全局调色板
$this->color_resolution = (($flag >> 4) & 0x07) + 1; //彩色分辨率
$this->sort_flag = ($flag & 0x08) > 0; //调色板是否排序
$this->size_of_global_color_table = $flag & 0x07; //全局色板大小,2的乘方的指数
$this->background_color_index = $this->next(); //背景色索引
$this->pixel_aspect_ratio = $this->next(); //像素纵横比
if($this->global_color_table_flag)
$this->global_color_table = $this->get_color_table($this->size_of_global_color_table);
}
/**
* 内部方法 get_image_descriptor
* 读取图片信息
**/
function get_image_descriptor() {
$image['left_position'] = $this->get_number();
$image['top_position'] = $this->get_number();
$image['width'] = $this->get_number();
$image['height'] = $this->get_number();
$image['flag'] = $flag = $this->next();
$image['local_color_table_flag'] = ($flag & 0x80) > 0; //局部色表
$image['interlace_flag'] = ($flag & 0x40) > 0; //交错
$image['local_sort_flag'] = ($flag & 0x20) > 0; //色表是否排序
$image['size_of_local_color_table'] = $flag & 0x07; //局部色表大小
if($image['local_color_table_flag'])
$image['local_color_table'] = $this->get_color_table($image['size_of_local_color_table']);
$image['data'] = $this->get_table_based_image_data();
$this->image[$this->frame] = array_merge($this->image[$this->frame], $image);
$this->frame++;
}
/**
* 内部方法 get_table_based_image_data
* 读取图象数据
**/
function get_table_based_image_data() {
$table_based_image_data_size = 0;
$table_based_image_data = chr($this->next());
while($n = $this->next()) {
$table_based_image_data_size += $n;
$table_based_image_data .= chr($n);
$table_based_image_data .= $this->next($n);
}
$table_based_image_data .= chr(0);
return $table_based_image_data;
}
/**
* 内部方法 get_extension_introducer
* 读取图象扩展
**/
function get_extension_introducer() {
switch($this->next()) {
case 0xf9:
$size = $this->next(); //固定为4
$flag = $this->next();
$this->image[$this->frame]['disposal_method'] = ($flag >> 2) & 0x07;
$this->image[$this->frame]['transparent_flag'] = $flag & 0x01;
$this->image[$this->frame]['delay_time'] = $this->get_number();
$this->image[$this->frame]['transparecy_index'] = $this->next();
$this->next();
break;
case 0xfe:
while($this->next() != 0);
break;
case 0x01:
$this->next();
$delay_time = $this->get_number();
$delay_time = $this->get_number();
$delay_time = $this->get_number();
$delay_time = $this->get_number();
$this->next();
$this->next();
$this->next();
$this->next();
while($this->next() != 0);
break;
case 0xff:
$this->application_extension = $this->next($this->next());
while($this->next() != 0);
break;
}
}
/**
* 公共方法 info
* 产生图片信息报告
**/
function info() {
if(isset($_GET['frame'])) {
echo $this->withdraw($_GET['frame']);
exit;
}
$dict = array(
'logical_screen_width' => '图片宽度',
'logical_screen_height' => '图片高度',
'global_color_table_flag' => '全局色表',
'color_resolution' => '彩色分辨率',
'sort_flag' => '排序标志',
'size_of_global_color_table' => '全局色表大小',
'background_color_index' => '背景色索引',
'pixel_aspect_ratio' => '像素纵横比',
'frame' => '帧数',
'application_extension' => '应用程序扩展',
);
$image_dict = array(
'left_position' => '图象左边距',
'top_position' => '图象上边距',
'width' => '图象宽',
'height' => '图象高',
'local_color_table_flag' => '局部色表',
'interlace_flag' => '交错',
'local_sort_flag' => '排序标志',
'size_of_local_color_table' => '局部色表大小',
'delay_time' => '停顿时间',
'disposal_method' => '处置方式',
'transparecy_index' => '透明色索引',
);
echo '';
printf("图片文件名 %s ", $this->imagename);
echo '
';
foreach($dict as $key => $value)
printf("
%s
%s
",$value,$this->$key);
printf("
", $this->imagename);
for($i=0; $iframe; $i++) {
printf("帧号 %s ",$i);
echo '
';
foreach($image_dict as $key => $value)
printf("
%s
%s
",$value,$this->image[$i][$key]);
printf("
", $i);
}
echo "
";
}
/**
* 内部方法 control_extension,由withdraw方法调用
* 输出图象扩展控制段
* 参数
* $frame 数值,图片帧号
* $delay_time 数值,图象停顿时间,单位为百分秒(10ms)
* $disposal_mothod 数值,处置方式
* 返回 无
**/
function control_extension($frame=0, $delay_time=10, $disposal_mothod=0) {
$transparent = $this->image[$frame]['transparecy_index'];
$flag = ($disposal_mothod image[$frame]['transparent_flag'];
echo pack("CCCCSCC", 0x21, 0xf9, 4, $flag, $delay_time, $transparent, 0);
}
/**
* 内部方法 image_frame,由withdraw方法调用
* 输出一帧图象
* 参数
* $frame 数值,图片帧号
* $left 数值,图象左边距
* $top 数值,图象上边距
* $colortab 字符串,对比用的全局调色板数据
* 返回 无
**/
function image_frame($frame=0, $left=null, $top=null, $colortab=null) {
if($left == null) $left = $this->image[$frame]['left_position'];
if($top == null) $top = $this->image[$frame]['top_position'];
$flag = $this->image[$frame]['flag'];
$color_table = '';
if($this->image[$frame]['local_color_table_flag']) {
//如图象有局部调色板则取局部调色板
$color_table = $this->image[$frame]['local_color_table'];
}elseif($colortable != null && $colortable != $this->global_color_table) {
//如图象没有局部调色板且全局调色板与对比调色板不同,就把全局调色板设置为局部调色板
$flag &= 0x40; //保留交错标志
$flag |= $this->sort_flag ? 0x20 : 0x00; //设置排序标志
$flag |= 0x80; //设置局部色表标志
$flag |= $this->size_of_global_color_table;
$color_table = $this->global_color_table;
}
$width = $this->image[$frame]['width'];
$height = $this->image[$frame]['height'];
echo pack("CSSSSC", 0x2c, $left, $top, $width, $height, $flag);
echo $color_table;
echo $this->image[$frame]['data'];
}
/**
* 内部方法 image_header,由withdraw方法调用
* 输出图片头
* 参数
* $width 数值,图片宽
* $height 数值,图片高
* 返回 无
**/
function image_header($width=0, $height=0) {
ob_start();
printf("GIF89a%s%s%c%c%c"
, pack("S", $this->logical_screen_width)
, pack("S", $this->logical_screen_height)
, $this->flag
, $this->background_color_index
, $this->pixel_aspect_ratio
);
if($this->global_color_table_flag)
echo $this->global_color_table;
}
/**
* 内部方法 image_end,由withdraw方法调用
* 输出图片尾,并返回图片数据
* 返回 字符串,图片数据
**/
function image_end() {
echo chr(0x3b);
$buf = ob_get_clean();
return $buf;
}
/**
* 公共方法 withdraw
* 生成单帧的图片[文件]
* 参数
* $frame 数值,提取的帧号
* $filename 字符串,目标文件名,缺省为空(不生成文件)
* 返回 字符串,图片数据
**/
function withdraw($frame=0, $filename='') {
if($frame > $this->frame-1) $frame = 0;
$this->image_header();
$this->control_extension($frame);
$this->image_frame($frame);
$buf = $this->image_end();
if(!empty($filename))
file_put_contents($filename, $buf);
return $buf;
}
}
$p = new TGif('old.gif');
//$p->info();
echo $p->withdraw(0, 'hello.gif');
//print_r($p->image);
?>
回复内容:
我想把一个动态gif拆分成一帧一帧的 然后对单帧进行修改后再合并起来 在网上找了一段代码 但是在拆分成单帧的时候就出了问题 但是不知道错在哪里了 请各位大虾帮忙看看 代码如下
buffer, 0, $len);
$this->buffer = substr($this->buffer, $len);
if($len == 1)
return ord($ch);
return $ch;
}
/**
* 内部方法 get_number
* 从图片数据缓冲区读取一个整数
* 参数 无
* 返回 整数
**/
function get_number() {
$t = unpack("Sn", $this->next(2));
return $t['n'];
}
/**
* 构造函数
* 参数 $imagename 字符串,图片文件名或图片数据
* 返回 无
**/
function TGif($imagename="images/xzn.gif") {
$this->image = array();
$this->frame = 0;
if(is_file($imagename)) {
$this->imagename = $imagename;
$this->buffer = @file_get_contents($imagename)
or trigger_error("$imagename 打不开", E_USER_ERROR);
}else {
substr($imagename, 0, 3) == 'GIF' or
trigger_error("$imagename 不存在或不是GIF格式图片", E_USER_ERROR);
$this->buffer = $imagename;
$this->imagename = '未命名';
}
$this->get_header();
while(strlen($this->buffer)) {
switch($this->next()) {
case 0x21: //图象扩展描述符
$this->get_extension_introducer();
break;
case 0x2c: //图象描述符
$this->get_image_descriptor();
break;
case 0x3b: //GIF数据流结束
return;
}
}
}
/**
* 内部方法 get_color_table
* 读取调色板数据
**/
function get_color_table($num) {
return $this->next(3*pow(2,$num+1));
}
/**
* 内部方法 get_header
* 读取头信息
**/
function get_header() {
$this->signature = $this->next(3); //类型标识gif
if($this->signature != 'GIF')
trigger_error("$this->imagename 不是GIF格式图片", E_USER_ERROR);
$this->version = $this->next(3); //版本标识
$this->logical_screen_width = $this->get_number(); //逻辑屏幕宽
$this->logical_screen_height = $this->get_number(); //逻辑屏幕高
$this->flag = $flag = $this->next();
$this->global_color_table_flag = ($flag & 0x80) > 0; //是否有全局调色板
$this->color_resolution = (($flag >> 4) & 0x07) + 1; //彩色分辨率
$this->sort_flag = ($flag & 0x08) > 0; //调色板是否排序
$this->size_of_global_color_table = $flag & 0x07; //全局色板大小,2的乘方的指数
$this->background_color_index = $this->next(); //背景色索引
$this->pixel_aspect_ratio = $this->next(); //像素纵横比
if($this->global_color_table_flag)
$this->global_color_table = $this->get_color_table($this->size_of_global_color_table);
}
/**
* 内部方法 get_image_descriptor
* 读取图片信息
**/
function get_image_descriptor() {
$image['left_position'] = $this->get_number();
$image['top_position'] = $this->get_number();
$image['width'] = $this->get_number();
$image['height'] = $this->get_number();
$image['flag'] = $flag = $this->next();
$image['local_color_table_flag'] = ($flag & 0x80) > 0; //局部色表
$image['interlace_flag'] = ($flag & 0x40) > 0; //交错
$image['local_sort_flag'] = ($flag & 0x20) > 0; //色表是否排序
$image['size_of_local_color_table'] = $flag & 0x07; //局部色表大小
if($image['local_color_table_flag'])
$image['local_color_table'] = $this->get_color_table($image['size_of_local_color_table']);
$image['data'] = $this->get_table_based_image_data();
$this->image[$this->frame] = array_merge($this->image[$this->frame], $image);
$this->frame++;
}
/**
* 内部方法 get_table_based_image_data
* 读取图象数据
**/
function get_table_based_image_data() {
$table_based_image_data_size = 0;
$table_based_image_data = chr($this->next());
while($n = $this->next()) {
$table_based_image_data_size += $n;
$table_based_image_data .= chr($n);
$table_based_image_data .= $this->next($n);
}
$table_based_image_data .= chr(0);
return $table_based_image_data;
}
/**
* 内部方法 get_extension_introducer
* 读取图象扩展
**/
function get_extension_introducer() {
switch($this->next()) {
case 0xf9:
$size = $this->next(); //固定为4
$flag = $this->next();
$this->image[$this->frame]['disposal_method'] = ($flag >> 2) & 0x07;
$this->image[$this->frame]['transparent_flag'] = $flag & 0x01;
$this->image[$this->frame]['delay_time'] = $this->get_number();
$this->image[$this->frame]['transparecy_index'] = $this->next();
$this->next();
break;
case 0xfe:
while($this->next() != 0);
break;
case 0x01:
$this->next();
$delay_time = $this->get_number();
$delay_time = $this->get_number();
$delay_time = $this->get_number();
$delay_time = $this->get_number();
$this->next();
$this->next();
$this->next();
$this->next();
while($this->next() != 0);
break;
case 0xff:
$this->application_extension = $this->next($this->next());
while($this->next() != 0);
break;
}
}
/**
* 公共方法 info
* 产生图片信息报告
**/
function info() {
if(isset($_GET['frame'])) {
echo $this->withdraw($_GET['frame']);
exit;
}
$dict = array(
'logical_screen_width' => '图片宽度',
'logical_screen_height' => '图片高度',
'global_color_table_flag' => '全局色表',
'color_resolution' => '彩色分辨率',
'sort_flag' => '排序标志',
'size_of_global_color_table' => '全局色表大小',
'background_color_index' => '背景色索引',
'pixel_aspect_ratio' => '像素纵横比',
'frame' => '帧数',
'application_extension' => '应用程序扩展',
);
$image_dict = array(
'left_position' => '图象左边距',
'top_position' => '图象上边距',
'width' => '图象宽',
'height' => '图象高',
'local_color_table_flag' => '局部色表',
'interlace_flag' => '交错',
'local_sort_flag' => '排序标志',
'size_of_local_color_table' => '局部色表大小',
'delay_time' => '停顿时间',
'disposal_method' => '处置方式',
'transparecy_index' => '透明色索引',
);
echo '';
printf("图片文件名 %s ", $this->imagename);
echo '
';
foreach($dict as $key => $value)
printf("
%s
%s
",$value,$this->$key);
printf("
", $this->imagename);
for($i=0; $iframe; $i++) {
printf("帧号 %s ",$i);
echo '
';
foreach($image_dict as $key => $value)
printf("
%s
%s
",$value,$this->image[$i][$key]);
printf("
", $i);
}
echo "
";
}
/**
* 内部方法 control_extension,由withdraw方法调用
* 输出图象扩展控制段
* 参数
* $frame 数值,图片帧号
* $delay_time 数值,图象停顿时间,单位为百分秒(10ms)
* $disposal_mothod 数值,处置方式
* 返回 无
**/
function control_extension($frame=0, $delay_time=10, $disposal_mothod=0) {
$transparent = $this->image[$frame]['transparecy_index'];
$flag = ($disposal_mothod image[$frame]['transparent_flag'];
echo pack("CCCCSCC", 0x21, 0xf9, 4, $flag, $delay_time, $transparent, 0);
}
/**
* 内部方法 image_frame,由withdraw方法调用
* 输出一帧图象
* 参数
* $frame 数值,图片帧号
* $left 数值,图象左边距
* $top 数值,图象上边距
* $colortab 字符串,对比用的全局调色板数据
* 返回 无
**/
function image_frame($frame=0, $left=null, $top=null, $colortab=null) {
if($left == null) $left = $this->image[$frame]['left_position'];
if($top == null) $top = $this->image[$frame]['top_position'];
$flag = $this->image[$frame]['flag'];
$color_table = '';
if($this->image[$frame]['local_color_table_flag']) {
//如图象有局部调色板则取局部调色板
$color_table = $this->image[$frame]['local_color_table'];
}elseif($colortable != null && $colortable != $this->global_color_table) {
//如图象没有局部调色板且全局调色板与对比调色板不同,就把全局调色板设置为局部调色板
$flag &= 0x40; //保留交错标志
$flag |= $this->sort_flag ? 0x20 : 0x00; //设置排序标志
$flag |= 0x80; //设置局部色表标志
$flag |= $this->size_of_global_color_table;
$color_table = $this->global_color_table;
}
$width = $this->image[$frame]['width'];
$height = $this->image[$frame]['height'];
echo pack("CSSSSC", 0x2c, $left, $top, $width, $height, $flag);
echo $color_table;
echo $this->image[$frame]['data'];
}
/**
* 内部方法 image_header,由withdraw方法调用
* 输出图片头
* 参数
* $width 数值,图片宽
* $height 数值,图片高
* 返回 无
**/
function image_header($width=0, $height=0) {
ob_start();
printf("GIF89a%s%s%c%c%c"
, pack("S", $this->logical_screen_width)
, pack("S", $this->logical_screen_height)
, $this->flag
, $this->background_color_index
, $this->pixel_aspect_ratio
);
if($this->global_color_table_flag)
echo $this->global_color_table;
}
/**
* 内部方法 image_end,由withdraw方法调用
* 输出图片尾,并返回图片数据
* 返回 字符串,图片数据
**/
function image_end() {
echo chr(0x3b);
$buf = ob_get_clean();
return $buf;
}
/**
* 公共方法 withdraw
* 生成单帧的图片[文件]
* 参数
* $frame 数值,提取的帧号
* $filename 字符串,目标文件名,缺省为空(不生成文件)
* 返回 字符串,图片数据
**/
function withdraw($frame=0, $filename='') {
if($frame > $this->frame-1) $frame = 0;
$this->image_header();
$this->control_extension($frame);
$this->image_frame($frame);
$buf = $this->image_end();
if(!empty($filename))
file_put_contents($filename, $buf);
return $buf;
}
}
$p = new TGif('old.gif');
//$p->info();
echo $p->withdraw(0, 'hello.gif');
//print_r($p->image);
?>
try imagemagick
使用 imagemagick就很简单了