<?php

//namespace gifCreator;

/**
* Create an animated GIF from multiple images
*/
class gifcreator
{
/**
* @var string The gif string source (old: this->GIF)
*/
private $gif; /**
* @var string Encoder version (old: this->VER)
*/
private $version; /**
* @var boolean Check the image is build or not (old: this->IMG)
*/
private $imgBuilt; /**
* @var array Frames string sources (old: this->BUF)
*/
private $frameSources; /**
* @var integer Gif loop (old: this->LOP)
*/
private $loop; /**
* @var integer Gif dis (old: this->DIS)
*/
private $dis; /**
* @var integer Gif color (old: this->COL)
*/
private $colour; /**
* @var array (old: this->ERR)
*/
private $errors; // Methods
// =================================================================================== /**
* Constructor
*/
public function __construct()
{
$this->reset(); // Static data
$this->version = 'GifCreator: Under development';
$this->errors = array(
'ERR00' => 'Does not supported function for only one image.',
'ERR01' => 'Source is not a GIF image.',
'ERR02' => 'You have to give resource image variables, image URL or image binary sources in $frames array.',
'ERR03' => 'Does not make animation from animated GIF source.',
);
} /**
* Create the GIF string (old: GIFEncoder)
*
* @param array $frames An array of frame: can be file paths, resource image variables, binary sources or image URLs
* @param array $durations An array containing the duration of each frame
* @param integer $loop Number of GIF loops before stopping animation (Set 0 to get an infinite loop)
*
* @return string The GIF string source
*/
public function create($frames = array(), $durations = array(), $loop = 0)
{
if (!is_array($frames) && !is_array($durations)) { throw new \Exception($this->version.': '.$this->errors['ERR00']);
} $this->loop = ($loop > -1) ? $loop : 0;
$this->dis = 2; for ($i = 0; $i < count($frames); $i++) { if (is_resource($frames[$i])) { // Resource var $resourceImg = $frames[$i]; ob_start();
imagegif($frames[$i]);
$this->frameSources[] = ob_get_contents();
ob_end_clean(); } elseif (is_string($frames[$i])) { // File path or URL or Binary source code if (file_exists($frames[$i]) || filter_var($frames[$i], FILTER_VALIDATE_URL)) { // File path $frames[$i] = file_get_contents($frames[$i]);
} $resourceImg = imagecreatefromstring($frames[$i]); ob_start();
imagegif($resourceImg);
$this->frameSources[] = ob_get_contents();
ob_end_clean(); } else { // Fail throw new \Exception($this->version.': '.$this->errors['ERR02']);
} if ($i == 0) { $colour = imagecolortransparent($resourceImg);
} if (substr($this->frameSources[$i], 0, 6) != 'GIF87a' && substr($this->frameSources[$i], 0, 6) != 'GIF89a') { throw new \Exception($this->version.': '.$i.' '.$this->errors['ERR01']);
} for ($j = (13 + 3 * (2 << (ord($this->frameSources[$i] { 10 }) & 0x07))), $k = TRUE; $k; $j++) { switch ($this->frameSources[$i] { $j }) { case '!': if ((substr($this->frameSources[$i], ($j + 3), 8)) == 'NETSCAPE') { throw new \Exception($this->version.': '.$this->errors['ERR03'].' ('.($i + 1).' source).');
} break; case ';': $k = false;
break;
}
} unset($resourceImg);
} if (isset($colour)) { $this->colour = $colour; } else { $red = $green = $blue = 0;
$this->colour = ($red > -1 && $green > -1 && $blue > -1) ? ($red | ($green << 8) | ($blue << 16)) : -1;
} $this->gifAddHeader();
//d(count($this->frameSources));
for ($i = 0; $i < count($this->frameSources); $i++) {
$this->addGifFrames($i, $durations[$i]);
} $this->gifAddFooter(); return $this->gif;
} // Internals
// =================================================================================== /**
* Add the header gif string in its source (old: GIFAddHeader)
*/
public function gifAddHeader()
{
$cmap = 0; if (ord($this->frameSources[0] { 10 }) & 0x80) { $cmap = 3 * (2 << (ord($this->frameSources[0] { 10 }) & 0x07)); $this->gif .= substr($this->frameSources[0], 6, 7);
$this->gif .= substr($this->frameSources[0], 13, $cmap);
$this->gif .= "!\377\13NETSCAPE2.0\3\1".$this->encodeAsciiToChar($this->loop)."\0";
}
} /**
* Add the frame sources to the GIF string (old: GIFAddFrames)
*
* @param integer $i
* @param integer $d
*/
public function addGifFrames($i, $d)
{ $Locals_str = 13 + 3 * (2 << (ord($this->frameSources[ $i ] { 10 }) & 0x07)); $Locals_end = strlen($this->frameSources[$i]) - $Locals_str - 1;
$Locals_tmp = substr($this->frameSources[$i], $Locals_str, $Locals_end); $Global_len = 2 << (ord($this->frameSources[0 ] { 10 }) & 0x07);
$Locals_len = 2 << (ord($this->frameSources[$i] { 10 }) & 0x07); $Global_rgb = substr($this->frameSources[0], 13, 3 * (2 << (ord($this->frameSources[0] { 10 }) & 0x07)));
$Locals_rgb = substr($this->frameSources[$i], 13, 3 * (2 << (ord($this->frameSources[$i] { 10 }) & 0x07))); $Locals_ext = "!\xF9\x04".chr(($this->dis << 2) + 0).chr(($d >> 0 ) & 0xFF).chr(($d >> 8) & 0xFF)."\x0\x0"; if ($this->colour > -1 && ord($this->frameSources[$i] { 10 }) & 0x80) { for ($j = 0; $j < (2 << (ord($this->frameSources[$i] { 10 } ) & 0x07)); $j++) { if (ord($Locals_rgb { 3 * $j + 0 }) == (($this->colour >> 16) & 0xFF) &&
ord($Locals_rgb { 3 * $j + 1 }) == (($this->colour >> 8) & 0xFF) &&
ord($Locals_rgb { 3 * $j + 2 }) == (($this->colour >> 0) & 0xFF)
) {
$Locals_ext = "!\xF9\x04".chr(($this->dis << 2) + 1).chr(($d >> 0) & 0xFF).chr(($d >> 8) & 0xFF).chr($j)."\x0";
break;
}
}
} switch ($Locals_tmp { 0 }) { case '!': $Locals_img = substr($Locals_tmp, 8, 10);
$Locals_tmp = substr($Locals_tmp, 18, strlen($Locals_tmp) - 18); break; case ',': $Locals_img = substr($Locals_tmp, 0, 10);
$Locals_tmp = substr($Locals_tmp, 10, strlen($Locals_tmp) - 10); break;
} if (ord($this->frameSources[$i] { 10 }) & 0x80 && $this->imgBuilt) { if ($Global_len == $Locals_len) { if ($this->gifBlockCompare($Global_rgb, $Locals_rgb, $Global_len)) { $this->gif .= $Locals_ext.$Locals_img.$Locals_tmp; } else { $byte = ord($Locals_img { 9 });
$byte |= 0x80;
$byte &= 0xF8;
$byte |= (ord($this->frameSources[0] { 10 }) & 0x07);
$Locals_img { 9 } = chr($byte);
$this->gif .= $Locals_ext.$Locals_img.$Locals_rgb.$Locals_tmp;
} } else { $byte = ord($Locals_img { 9 });
$byte |= 0x80;
$byte &= 0xF8;
$byte |= (ord($this->frameSources[$i] { 10 }) & 0x07);
$Locals_img { 9 } = chr($byte);
$this->gif .= $Locals_ext.$Locals_img.$Locals_rgb.$Locals_tmp;
} } else { $this->gif .= $Locals_ext.$Locals_img.$Locals_tmp;
} $this->imgBuilt = true;
} /**
* Add the gif string footer char (old: GIFAddFooter)
*/
public function gifAddFooter()
{
$this->gif .= ';';
} /**
* Compare two block and return the version (old: GIFBlockCompare)
*
* @param string $globalBlock
* @param string $localBlock
* @param integer $length
*
* @return integer
*/
public function gifBlockCompare($globalBlock, $localBlock, $length)
{
for ($i = 0; $i < $length; $i++) { if ($globalBlock { 3 * $i + 0 } != $localBlock { 3 * $i + 0 } ||
$globalBlock { 3 * $i + 1 } != $localBlock { 3 * $i + 1 } ||
$globalBlock { 3 * $i + 2 } != $localBlock { 3 * $i + 2 }) { return 0;
}
} return 1;
} /**
* Encode an ASCII char into a string char (old: GIFWord)
*
* $param integer $char ASCII char
*
* @return string
*/
public function encodeAsciiToChar($char)
{
return (chr($char & 0xFF).chr(($char >> 8) & 0xFF));
} /**
* Reset and clean the current object
*/
public function reset()
{
$this->frameSources;
$this->gif = 'GIF89a'; // the GIF header
$this->imgBuilt = false;
$this->loop = 0;
$this->dis = 2;
$this->colour = -1;
} // Getter / Setter
// =================================================================================== /**
* Get the final GIF image string (old: GetAnimation)
*
* @return string
*/
public function getGif()
{
return $this->gif;
}
} //图片资源写入数组,支持如下图片资源。
$frames = array(
"http://pic27.nipic.com/20130313/9252150_092049419327_2.jpg",
"http://pic27.nipic.com/20130324/9252150_152129329000_2.jpg",
"http://pic44.nipic.com/20140723/18505720_094503373000_2.jpg",
"http://pic18.nipic.com/20120103/8993051_170340691334_2.jpg"
); // 设置图片转换快慢,数值越小越快,数组个数和frames对应。
$durations = array(40, 80, 40, 20); $gc = new GifCreator();
$gifBinary = $gc->create($frames, $durations, 0); file_put_contents('./ceshi.gif',$gifBinary);

php 生成gif 动图,可控制每张图时间的更多相关文章

  1. android安卓生成密钥keystore(命令控制)

    android安卓生成密钥keystore(命令控制) • 配置JDK 详细教程 https://blog.csdn.net/u012934325/article/details/73441617/ ...

  2. S​Q​L​_​S​e​r​v​e​r​_​2​0​0​8​定​期​自​动​备​份​详​细​图​解

    S​Q​L​_​S​e​r​v​e​r​_​2​0​0​8​定​期​自​动​备​份​详​细​图​解 设置自动数据库的定期备份计划. http://wenku.baidu.com/link?url=Tu ...

  3. EA逆向生成数据库E-R图(mysql数据库-->ER图)

    [1]选择 工具-->ODBC-Data-Sources [2]ODBC数据源管理器  ,点击添加 [3]选择一个mysql驱动  ,点击MySQL ODBC 5.1 Driver(其它同理), ...

  4. Shader中贴图知识汇总: 漫反射贴图、凹凸贴图、高光贴图、 AO贴图、环境贴图、 光照纹理及细节贴图

    原文过于冗余,精读后做了部分简化与测试实践,原文地址:http://www.j2megame.com/html/xwzx/ty/2571.html   http://www.cnblogs.com/z ...

  5. PS-前端切图教程(切jpg图和切png图)

    微微一运功,把家底都抖出来了. 不过,作为一个设计出身的前端来说,摸ps就和摸键盘一样了 所以可能教程中还是有没用过ps的人看不懂的地方, 欢迎加群讨论:613512106... ---------- ...

  6. 【UML 建模】UML建模语言入门 -- 静态图详解 类图 对象图 包图 静态图建模实战

    发现个好东西思维导图, 最近开始用MindManager整理博客 . 作者 :万境绝尘  转载请注明出处 : http://blog.csdn.net/shulianghan/article/deta ...

  7. (转)Unity3D 游戏贴图(法线贴图,漫反射贴图,高光贴图)

    原帖网址http://www.u3dpro.com/read.php?tid=207  感谢jdk900网友的辛苦编写 我们都知道,一个三维场景的画面的好坏,百分之四十取决于模型,百分之六十取决于贴图 ...

  8. UML建模语言入门 -- 静态图详解 类图 对象图 包图 静态图建模实战

    发现个好东西思维导图, 最近开始用MindManager整理博客 . 作者 :万境绝尘  转载请注明出处 : http://blog.csdn.net/shulianghan/article/deta ...

  9. D3.js系列——布局:弦图和集群图/树状图

    一.弦图 1.弦图是什么 弦图(Chord),主要用于表示两个节点之间的联系的图表.两点之间的连线,表示谁和谁具有联系. 2.数据 初始数据为: var city_name = [ "北京& ...

随机推荐

  1. 【c# 学习笔记】接口与抽象类

    抽象类经常与接口一起使用,共同服务于面向对象的编程,这里简单地分析一下接口与抽象类的区别,如下: 1.抽象类使用abstract关键字进行定义,而接口使用interface进行定义:它们都不能进行实例 ...

  2. SpringCloud入门01之基础知识

    一.Spring Cloud 什么是spring cloud, 为什么要使用微服务架构? 参考度娘 Spring Cloud是一系列框架的有序集合, 它利用Spring Boot的开发便利性巧妙地简化 ...

  3. 三节课MINI计划第三周

    第一部分     微信读书的产品分析 一.任务背景 二.做什么 三.TASK8     业务流程图 四.TASK9 五.周会 六.周报

  4. TiKV事务实现浅析

    TiKV事务实现浅析 Percolator事务的理论基础 Percolator的来源 Percolator事务来源于Google在设计更新网页索引的系统时提出的论文Large-scale Increm ...

  5. linux环境上报异常java.lang.NoSuchMethodError

    23-Apr-2019 18:11:35.545 INFO [http-nio-10052-exec-10] org.apache.catalina.core.ApplicationContext.l ...

  6. Fiddler之打断点

    1..Fiddler可以修改以下请求 --Fiddler设置断点,可以修改HTTP请求头信息,如修改Cookie,User-Agent等 --可以修改请求数据,突破表单限制,提交任意数字,如充值最小1 ...

  7. 抽象类 and 接口

    目录 抽象类 抽象类的域和方法的权限: 接口 接口中的域和方法的权限: 实现多个接口 接口继承 接口嵌套 抽象类 一个类,如果有抽象方法(没有方法体),则该类必须被限定为抽象类(abstract):当 ...

  8. VC++操作注册表(创建,读取,更改,删除)

    #include "stdafx.h" #include <Windows.h> #include <iostream> using namespace s ...

  9. SDOI2010_大陆争霸(邻接表存图)

    题目描述 在一个遥远的世界里有两个国家:位于大陆西端的杰森国和位于大陆东端的 克里斯国.两个国家的人民分别信仰两个对立的神:杰森国信仰象征黑暗和毁灭 的神曾·布拉泽,而克里斯国信仰象征光明和永恒的神斯 ...

  10. yii2中 选择布局的方式,可以设置不使用布局

    ###yii2中 选择布局的方式,可以设置不使用布局 控制器内成员变量 public $layout = false; //不使用布局 public $layout = "main" ...