当前位置:Gxlcms > PHP教程 > 用php将动态gif拆分成单帧

用php将动态gif拆分成单帧

时间:2021-07-01 10:21:17 帮助过:29人阅读

我想把一个动态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("", $this->imagename);
    echo '", $this->imagename);
    for($i=0; $i<$this->frame; $i++) {
        printf("",$i);
        echo '", $i);
    }
    echo "
图片文件名 https://www.gxlcms.com/%s
'; foreach($dict as $key => $value) printf("",$value,$this->$key); printf("
https://www.gxlcms.com/%shttps://www.gxlcms.com/%s
帧号 https://www.gxlcms.com/%s
'; foreach($image_dict as $key => $value) printf("",$value,$this->image[$i][$key]); printf("
https://www.gxlcms.com/%shttps://www.gxlcms.com/%s
"; } /** * 内部方法 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 << 2) | $this->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("GIF89ahttps://www.gxlcms.com/%shttps://www.gxlcms.com/%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("", $this->imagename);
    echo '", $this->imagename);
    for($i=0; $i<$this->frame; $i++) {
        printf("",$i);
        echo '", $i);
    }
    echo "
图片文件名 https://www.gxlcms.com/%s
'; foreach($dict as $key => $value) printf("",$value,$this->$key); printf("
https://www.gxlcms.com/%shttps://www.gxlcms.com/%s
帧号 https://www.gxlcms.com/%s
'; foreach($image_dict as $key => $value) printf("",$value,$this->image[$i][$key]); printf("
https://www.gxlcms.com/%shttps://www.gxlcms.com/%s
"; } /** * 内部方法 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 << 2) | $this->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("GIF89ahttps://www.gxlcms.com/%shttps://www.gxlcms.com/%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就很简单了

人气教程排行