1. <?php
  2.  
  3. //namespace gifCreator;
  4.  
  5. /**
  6. * Create an animated GIF from multiple images
  7. */
  8. class gifcreator
  9. {
  10. /**
  11. * @var string The gif string source (old: this->GIF)
  12. */
  13. private $gif;
  14.  
  15. /**
  16. * @var string Encoder version (old: this->VER)
  17. */
  18. private $version;
  19.  
  20. /**
  21. * @var boolean Check the image is build or not (old: this->IMG)
  22. */
  23. private $imgBuilt;
  24.  
  25. /**
  26. * @var array Frames string sources (old: this->BUF)
  27. */
  28. private $frameSources;
  29.  
  30. /**
  31. * @var integer Gif loop (old: this->LOP)
  32. */
  33. private $loop;
  34.  
  35. /**
  36. * @var integer Gif dis (old: this->DIS)
  37. */
  38. private $dis;
  39.  
  40. /**
  41. * @var integer Gif color (old: this->COL)
  42. */
  43. private $colour;
  44.  
  45. /**
  46. * @var array (old: this->ERR)
  47. */
  48. private $errors;
  49.  
  50. // Methods
  51. // ===================================================================================
  52.  
  53. /**
  54. * Constructor
  55. */
  56. public function __construct()
  57. {
  58. $this->reset();
  59.  
  60. // Static data
  61. $this->version = 'GifCreator: Under development';
  62. $this->errors = array(
  63. 'ERR00' => 'Does not supported function for only one image.',
  64. 'ERR01' => 'Source is not a GIF image.',
  65. 'ERR02' => 'You have to give resource image variables, image URL or image binary sources in $frames array.',
  66. 'ERR03' => 'Does not make animation from animated GIF source.',
  67. );
  68. }
  69.  
  70. /**
  71. * Create the GIF string (old: GIFEncoder)
  72. *
  73. * @param array $frames An array of frame: can be file paths, resource image variables, binary sources or image URLs
  74. * @param array $durations An array containing the duration of each frame
  75. * @param integer $loop Number of GIF loops before stopping animation (Set 0 to get an infinite loop)
  76. *
  77. * @return string The GIF string source
  78. */
  79. public function create($frames = array(), $durations = array(), $loop = 0)
  80. {
  81. if (!is_array($frames) && !is_array($durations)) {
  82.  
  83. throw new \Exception($this->version.': '.$this->errors['ERR00']);
  84. }
  85.  
  86. $this->loop = ($loop > -1) ? $loop : 0;
  87. $this->dis = 2;
  88.  
  89. for ($i = 0; $i < count($frames); $i++) {
  90.  
  91. if (is_resource($frames[$i])) { // Resource var
  92.  
  93. $resourceImg = $frames[$i];
  94.  
  95. ob_start();
  96. imagegif($frames[$i]);
  97. $this->frameSources[] = ob_get_contents();
  98. ob_end_clean();
  99.  
  100. } elseif (is_string($frames[$i])) { // File path or URL or Binary source code
  101.  
  102. if (file_exists($frames[$i]) || filter_var($frames[$i], FILTER_VALIDATE_URL)) { // File path
  103.  
  104. $frames[$i] = file_get_contents($frames[$i]);
  105. }
  106.  
  107. $resourceImg = imagecreatefromstring($frames[$i]);
  108.  
  109. ob_start();
  110. imagegif($resourceImg);
  111. $this->frameSources[] = ob_get_contents();
  112. ob_end_clean();
  113.  
  114. } else { // Fail
  115.  
  116. throw new \Exception($this->version.': '.$this->errors['ERR02']);
  117. }
  118.  
  119. if ($i == 0) {
  120.  
  121. $colour = imagecolortransparent($resourceImg);
  122. }
  123.  
  124. if (substr($this->frameSources[$i], 0, 6) != 'GIF87a' && substr($this->frameSources[$i], 0, 6) != 'GIF89a') {
  125.  
  126. throw new \Exception($this->version.': '.$i.' '.$this->errors['ERR01']);
  127. }
  128.  
  129. for ($j = (13 + 3 * (2 << (ord($this->frameSources[$i] { 10 }) & 0x07))), $k = TRUE; $k; $j++) {
  130.  
  131. switch ($this->frameSources[$i] { $j }) {
  132.  
  133. case '!':
  134.  
  135. if ((substr($this->frameSources[$i], ($j + 3), 8)) == 'NETSCAPE') {
  136.  
  137. throw new \Exception($this->version.': '.$this->errors['ERR03'].' ('.($i + 1).' source).');
  138. }
  139.  
  140. break;
  141.  
  142. case ';':
  143.  
  144. $k = false;
  145. break;
  146. }
  147. }
  148.  
  149. unset($resourceImg);
  150. }
  151.  
  152. if (isset($colour)) {
  153.  
  154. $this->colour = $colour;
  155.  
  156. } else {
  157.  
  158. $red = $green = $blue = 0;
  159. $this->colour = ($red > -1 && $green > -1 && $blue > -1) ? ($red | ($green << 8) | ($blue << 16)) : -1;
  160. }
  161.  
  162. $this->gifAddHeader();
  163. //d(count($this->frameSources));
  164. for ($i = 0; $i < count($this->frameSources); $i++) {
  165. $this->addGifFrames($i, $durations[$i]);
  166. }
  167.  
  168. $this->gifAddFooter();
  169.  
  170. return $this->gif;
  171. }
  172.  
  173. // Internals
  174. // ===================================================================================
  175.  
  176. /**
  177. * Add the header gif string in its source (old: GIFAddHeader)
  178. */
  179. public function gifAddHeader()
  180. {
  181. $cmap = 0;
  182.  
  183. if (ord($this->frameSources[0] { 10 }) & 0x80) {
  184.  
  185. $cmap = 3 * (2 << (ord($this->frameSources[0] { 10 }) & 0x07));
  186.  
  187. $this->gif .= substr($this->frameSources[0], 6, 7);
  188. $this->gif .= substr($this->frameSources[0], 13, $cmap);
  189. $this->gif .= "!\377\13NETSCAPE2.0\3\1".$this->encodeAsciiToChar($this->loop)."\0";
  190. }
  191. }
  192.  
  193. /**
  194. * Add the frame sources to the GIF string (old: GIFAddFrames)
  195. *
  196. * @param integer $i
  197. * @param integer $d
  198. */
  199. public function addGifFrames($i, $d)
  200. {
  201.  
  202. $Locals_str = 13 + 3 * (2 << (ord($this->frameSources[ $i ] { 10 }) & 0x07));
  203.  
  204. $Locals_end = strlen($this->frameSources[$i]) - $Locals_str - 1;
  205. $Locals_tmp = substr($this->frameSources[$i], $Locals_str, $Locals_end);
  206.  
  207. $Global_len = 2 << (ord($this->frameSources[0 ] { 10 }) & 0x07);
  208. $Locals_len = 2 << (ord($this->frameSources[$i] { 10 }) & 0x07);
  209.  
  210. $Global_rgb = substr($this->frameSources[0], 13, 3 * (2 << (ord($this->frameSources[0] { 10 }) & 0x07)));
  211. $Locals_rgb = substr($this->frameSources[$i], 13, 3 * (2 << (ord($this->frameSources[$i] { 10 }) & 0x07)));
  212.  
  213. $Locals_ext = "!\xF9\x04".chr(($this->dis << 2) + 0).chr(($d >> 0 ) & 0xFF).chr(($d >> 8) & 0xFF)."\x0\x0";
  214.  
  215. if ($this->colour > -1 && ord($this->frameSources[$i] { 10 }) & 0x80) {
  216.  
  217. for ($j = 0; $j < (2 << (ord($this->frameSources[$i] { 10 } ) & 0x07)); $j++) {
  218.  
  219. if (ord($Locals_rgb { 3 * $j + 0 }) == (($this->colour >> 16) & 0xFF) &&
  220. ord($Locals_rgb { 3 * $j + 1 }) == (($this->colour >> 8) & 0xFF) &&
  221. ord($Locals_rgb { 3 * $j + 2 }) == (($this->colour >> 0) & 0xFF)
  222. ) {
  223. $Locals_ext = "!\xF9\x04".chr(($this->dis << 2) + 1).chr(($d >> 0) & 0xFF).chr(($d >> 8) & 0xFF).chr($j)."\x0";
  224. break;
  225. }
  226. }
  227. }
  228.  
  229. switch ($Locals_tmp { 0 }) {
  230.  
  231. case '!':
  232.  
  233. $Locals_img = substr($Locals_tmp, 8, 10);
  234. $Locals_tmp = substr($Locals_tmp, 18, strlen($Locals_tmp) - 18);
  235.  
  236. break;
  237.  
  238. case ',':
  239.  
  240. $Locals_img = substr($Locals_tmp, 0, 10);
  241. $Locals_tmp = substr($Locals_tmp, 10, strlen($Locals_tmp) - 10);
  242.  
  243. break;
  244. }
  245.  
  246. if (ord($this->frameSources[$i] { 10 }) & 0x80 && $this->imgBuilt) {
  247.  
  248. if ($Global_len == $Locals_len) {
  249.  
  250. if ($this->gifBlockCompare($Global_rgb, $Locals_rgb, $Global_len)) {
  251.  
  252. $this->gif .= $Locals_ext.$Locals_img.$Locals_tmp;
  253.  
  254. } else {
  255.  
  256. $byte = ord($Locals_img { 9 });
  257. $byte |= 0x80;
  258. $byte &= 0xF8;
  259. $byte |= (ord($this->frameSources[0] { 10 }) & 0x07);
  260. $Locals_img { 9 } = chr($byte);
  261. $this->gif .= $Locals_ext.$Locals_img.$Locals_rgb.$Locals_tmp;
  262. }
  263.  
  264. } else {
  265.  
  266. $byte = ord($Locals_img { 9 });
  267. $byte |= 0x80;
  268. $byte &= 0xF8;
  269. $byte |= (ord($this->frameSources[$i] { 10 }) & 0x07);
  270. $Locals_img { 9 } = chr($byte);
  271. $this->gif .= $Locals_ext.$Locals_img.$Locals_rgb.$Locals_tmp;
  272. }
  273.  
  274. } else {
  275.  
  276. $this->gif .= $Locals_ext.$Locals_img.$Locals_tmp;
  277. }
  278.  
  279. $this->imgBuilt = true;
  280. }
  281.  
  282. /**
  283. * Add the gif string footer char (old: GIFAddFooter)
  284. */
  285. public function gifAddFooter()
  286. {
  287. $this->gif .= ';';
  288. }
  289.  
  290. /**
  291. * Compare two block and return the version (old: GIFBlockCompare)
  292. *
  293. * @param string $globalBlock
  294. * @param string $localBlock
  295. * @param integer $length
  296. *
  297. * @return integer
  298. */
  299. public function gifBlockCompare($globalBlock, $localBlock, $length)
  300. {
  301. for ($i = 0; $i < $length; $i++) {
  302.  
  303. if ($globalBlock { 3 * $i + 0 } != $localBlock { 3 * $i + 0 } ||
  304. $globalBlock { 3 * $i + 1 } != $localBlock { 3 * $i + 1 } ||
  305. $globalBlock { 3 * $i + 2 } != $localBlock { 3 * $i + 2 }) {
  306.  
  307. return 0;
  308. }
  309. }
  310.  
  311. return 1;
  312. }
  313.  
  314. /**
  315. * Encode an ASCII char into a string char (old: GIFWord)
  316. *
  317. * $param integer $char ASCII char
  318. *
  319. * @return string
  320. */
  321. public function encodeAsciiToChar($char)
  322. {
  323. return (chr($char & 0xFF).chr(($char >> 8) & 0xFF));
  324. }
  325.  
  326. /**
  327. * Reset and clean the current object
  328. */
  329. public function reset()
  330. {
  331. $this->frameSources;
  332. $this->gif = 'GIF89a'; // the GIF header
  333. $this->imgBuilt = false;
  334. $this->loop = 0;
  335. $this->dis = 2;
  336. $this->colour = -1;
  337. }
  338.  
  339. // Getter / Setter
  340. // ===================================================================================
  341.  
  342. /**
  343. * Get the final GIF image string (old: GetAnimation)
  344. *
  345. * @return string
  346. */
  347. public function getGif()
  348. {
  349. return $this->gif;
  350. }
  351. }
  352.  
  353. //图片资源写入数组,支持如下图片资源。
  354. $frames = array(
  355. "http://pic27.nipic.com/20130313/9252150_092049419327_2.jpg",
  356. "http://pic27.nipic.com/20130324/9252150_152129329000_2.jpg",
  357. "http://pic44.nipic.com/20140723/18505720_094503373000_2.jpg",
  358. "http://pic18.nipic.com/20120103/8993051_170340691334_2.jpg"
  359. );
  360.  
  361. // 设置图片转换快慢,数值越小越快,数组个数和frames对应。
  362. $durations = array(40, 80, 40, 20);
  363.  
  364. $gc = new GifCreator();
  365. $gifBinary = $gc->create($frames, $durations, 0);
  366.  
  367. 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. 使用说明(2S)

    [Build Status] 功能 系统代理设置 PAC 模式和全局模式 [GFWList] 和用户规则 支持 HTTP 代理 支持多服务器切换 支持 UDP 代理 支持插件 下载 下载 [最新版]. ...

  2. Rhino脚本引擎技术介绍

    引用:http://p.primeton.com/articles/54c1e255be20aa4735000001 http://blog.csdn.net/u013292493/article/d ...

  3. nginx+keepalived主从高可用配置

    上面有4台web服务器  我们实验条件限制,就开两台web服务器1.117  1.119 一.环境准备: 系统环境:CentOS 6.5 x86_64 Nginx版本:nginx v1.6.2 Kee ...

  4. jqGrid取消所有选中

    // 获取所有选中行id var jqGridRowid=$("#jqGrid").jqGrid("getGridParam","selarrrow& ...

  5. Java面试 - final、finally、finalize的区别?

    final:用于声明属性, 方法和类,分别表示属性不可变.方法不可覆盖.被其修饰的类不可继承. finally:异常处理语句结构的一部分,表示总是执行. finalize:Object 类的一个方法, ...

  6. Apache Commons Lang 学习栏目

    Apache Commons Lang 学习栏目 Apache Commons Lang 3.8.1 API https://mvnrepository.com/artifact/org.apache ...

  7. if("\v"=="v")来判断IE浏览器

    if(!+"\v1"){ IE代码}else{ 其他浏览器代码} if("\v"=="v"){//true为IE浏览器, document. ...

  8. HikariCP连接池及其在springboot中的配置

    主要配置如下: 配置项 描述 构造器默认值 默认配置validate之后的值 validate重置 autoCommit 自动提交从池中返回的连接 true true - connectionTime ...

  9. CSP-S初赛

    初赛都过了好几天了,现在才想起来写点关于初赛的博客也真是...... 我是福建人,是在福建的赛点参加的CSP-S组的初赛,能力其实很弱,估分只能60多一点点.真是害怕一不小心这篇博客就变成了我的退役博 ...

  10. python并发编程之IO模型(实践篇)

    一.阻塞IO 介绍略(请看概念篇) 二.非阻塞IO 在非阻塞式IO中,用户进程需要不断的主动询问kernel数据准备好了没有 # 服务端 import socket import time serve ...