PageRenderTime 67ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/A2/GIF/Decoder.php

https://bitbucket.org/mediastuttgart/image-resize
PHP | 265 lines | 195 code | 32 blank | 38 comment | 40 complexity | 8c1cfce0c47039a9c7d2d7a3784f6590 MD5 | raw file
  1. <?php
  2. /*
  3. * based on GIFDecoder by Lรกszlรณ Zsidi
  4. * http://www.phpclasses.org/package/3163-PHP-Generate-GIF-animations-from-a-set-of-GIF-images.html
  5. * http://www.phpclasses.org/package/3234-PHP-Split-GIF-animations-into-multiple-images.html
  6. * http://www.gifs.hu
  7. *
  8. *
  9. * Copyright (c) 2012, webvariants GbR, http://www.webvariants.de
  10. *
  11. * This file is released under the terms of the MIT license. You can find the
  12. * complete text in the attached LICENSE file or online at:
  13. *
  14. * http://www.opensource.org/licenses/mit-license.php
  15. *
  16. */
  17. class A2_GIF_Decoder {
  18. private $transparentR = -1;
  19. private $transparentG = -1;
  20. private $transparentB = -1;
  21. private $transparentI = 0;
  22. private $buffer = array();
  23. private $arrays = array();
  24. private $delays = array();
  25. private $dispos = array();
  26. private $offset = array();
  27. private $stream = '';
  28. private $string = '';
  29. private $bfseek = 0;
  30. private $anloop = 0;
  31. private $screen = array();
  32. private $screenWidth = null;
  33. private $screenHeight = null;
  34. private $global = array();
  35. private $sorted;
  36. private $colorS;
  37. private $colorC;
  38. private $colorF;
  39. public function __construct($gifFileContent) {
  40. $this->stream = $gifFileContent;
  41. $this->getByte( 6 ); // GIF89a
  42. $this->getByte( 7 ); // Logical Screen Descriptor
  43. $packed = $this->buffer[4]; // Packed Fields
  44. $this->screen = $this->buffer;
  45. $this->screenWidth = $this->buffer[0]; // Logical Screen Width
  46. $this->screenHeight = $this->buffer[2]; // Logical Screen Height
  47. $this->colorF = $packed & 0x80 ? 1 : 0; // Global Color Table Flag
  48. $this->colorC = $packed & 0x07; // Color Resulution
  49. $this->sorted = $packed & 0x08 ? 1 : 0; // Sort Flag
  50. $this->colorS = 2 << $this->colorC; // Size of Global Color Table
  51. // read global color table
  52. if ( $this->colorF == 1 ) {
  53. $this->getByte(3*$this->colorS);
  54. $this->global = $this->buffer;
  55. }
  56. for ($cycle = 1; $cycle; ) {
  57. if ($this->getByte( 1 )) {
  58. switch ($this->buffer[0]) {
  59. case 0x21:
  60. $this->readExtensions();
  61. break;
  62. case 0x2C:
  63. $this->readDescriptor();
  64. break;
  65. case 0x3B:
  66. $cycle = 0;
  67. break;
  68. }
  69. }
  70. else {
  71. $cycle = 0;
  72. }
  73. }
  74. }
  75. private function readExtensions() {
  76. $this->getByte(1);
  77. // application extension
  78. if ( $this->buffer [ 0 ] == 0xff ) {
  79. for ( ; ; ) {
  80. $this->getByte(1);
  81. // if byte size is zero, return
  82. if (($u = $this->buffer[0]) == 0x00) return false;
  83. // get bytes in length of byte size
  84. $this->getByte($u);
  85. // if byte size is 3
  86. if ($u == 0x03) {
  87. // get loop counter (0 to 65535), zero means infinite
  88. $this->anloop = ($this->buffer[1] | $this->buffer[2] << 8);
  89. }
  90. }
  91. }
  92. // other applications
  93. else {
  94. for ( ; ; ) {
  95. $this->getByte(1);
  96. // if byte size is zero, return
  97. if (($u = $this->buffer[0]) == 0x00) {
  98. return false;
  99. }
  100. $this->getByte($u);
  101. // if graphics control extension
  102. if ($u == 0x04) {
  103. // disposal method
  104. if (isset($this->buffer[4]) && $this->buffer[4] & 0x80 ) {
  105. $this->dispos[] = ( $this->buffer[0] >> 2 ) - 1;
  106. }
  107. else {
  108. $this->dispos[] = ( $this->buffer[0] >> 2 ) - 0;
  109. }
  110. // delay
  111. $this->delays[] = ( $this->buffer[1] | $this->buffer[2] << 8 );
  112. // transparent color index
  113. if ($this->buffer[3]) {
  114. $this->transparentI = $this->buffer[3];
  115. }
  116. }
  117. }
  118. }
  119. }
  120. private function readDescriptor() {
  121. $GIF_screen = array();
  122. $this->getByte ( 9 );
  123. $GIF_screen = $this->buffer;
  124. $imageLeft = $this->getInt(array($this->buffer[0], $this->buffer[1]));
  125. $imageTop = $this->getInt(array($this->buffer[2], $this->buffer[3]));
  126. $this->offset[] = array($imageLeft, $imageTop);
  127. $GIF_colorF = $this->buffer [ 8 ] & 0x80 ? 1 : 0;
  128. if ($GIF_colorF) {
  129. $GIF_code = $this->buffer [ 8 ] & 0x07;
  130. $GIF_sort = $this->buffer [ 8 ] & 0x20 ? 1 : 0;
  131. }
  132. else {
  133. $GIF_code = $this->colorC;
  134. $GIF_sort = $this->sorted;
  135. }
  136. $GIF_size = 2 << $GIF_code;
  137. $this->screen [ 4 ] &= 0x70;
  138. $this->screen [ 4 ] |= 0x80;
  139. $this->screen [ 4 ] |= $GIF_code;
  140. if ( $GIF_sort ) {
  141. $this->screen [ 4 ] |= 0x08;
  142. }
  143. /*
  144. *
  145. * GIF Data Begin
  146. *
  147. */
  148. if ( $this->transparentI ) {
  149. $this->string = "GIF89a";
  150. }
  151. else {
  152. $this->string = "GIF87a";
  153. }
  154. $this->putByte ( $this->screen );
  155. if ( $GIF_colorF == 1 ) {
  156. $this->getByte ( 3 * $GIF_size );
  157. if ( $this->transparentI ) {
  158. $this->transparentR = $this->buffer [ 3 * $this->transparentI + 0 ];
  159. $this->transparentG = $this->buffer [ 3 * $this->transparentI + 1 ];
  160. $this->transparentB = $this->buffer [ 3 * $this->transparentI + 2 ];
  161. }
  162. $this->putByte ( $this->buffer );
  163. }
  164. else {
  165. if ( $this->transparentI ) {
  166. $this->transparentR = $this->global [ 3 * $this->transparentI + 0 ];
  167. $this->transparentG = $this->global [ 3 * $this->transparentI + 1 ];
  168. $this->transparentB = $this->global [ 3 * $this->transparentI + 2 ];
  169. }
  170. $this->putByte ( $this->global );
  171. }
  172. if ( $this->transparentI ) {
  173. $this->string .= "!\xF9\x04\x1\x0\x0". chr ( $this->transparentI ) . "\x0";
  174. }
  175. // \x1 == 000 000 0 1
  176. $this->string .= chr ( 0x2C );
  177. $GIF_screen [ 8 ] &= 0x40;
  178. $this->putByte ( $GIF_screen );
  179. $this->getByte ( 1 );
  180. $this->putByte ( $this->buffer );
  181. for ( ; ; ) {
  182. $this->getByte ( 1 );
  183. $this->putByte ( $this->buffer );
  184. if ( ( $u = $this->buffer [ 0 ] ) == 0x00 ) {
  185. break;
  186. }
  187. $this->getByte ( $u );
  188. $this->putByte ( $this->buffer );
  189. }
  190. $this->string .= chr ( 0x3B );
  191. /*
  192. *
  193. * GIF Data End
  194. *
  195. */
  196. $this->arrays [ ] = $this->string;
  197. }
  198. private function getByte($len) {
  199. $this->buffer = array();
  200. for ( $i = 0; $i < $len; $i++ ) {
  201. if ( $this->bfseek > strlen ( $this->stream ) ) {
  202. return 0;
  203. }
  204. $this->buffer[ ] = ord( $this->stream { $this->bfseek++ } );
  205. }
  206. return 1;
  207. }
  208. private function putByte($bytes) {
  209. foreach ($bytes as $byte) {
  210. $this->string .= chr ( $byte );
  211. }
  212. }
  213. private function getInt(array $bytes) {
  214. if (count($bytes) === 1) return (int) reset($bytes);
  215. $skew = count($bytes)-1;
  216. $bytes = array_reverse($bytes);
  217. foreach ($bytes as $idx => $byte) {
  218. $bytes[$idx] = ($byte << ($skew*8));
  219. $skew--;
  220. }
  221. return array_sum($bytes);
  222. }
  223. public function getFrames() { return $this->arrays; }
  224. public function getScreenWidth() { return $this->screenWidth; }
  225. public function getScreenHeight() { return $this->screenHeight; }
  226. public function getDelays() { return $this->delays; }
  227. public function getLoop() { return $this->anloop; }
  228. public function getDisposal() { return $this->dispos; }
  229. public function getOffset() { return $this->offset; }
  230. public function getTransparentR() { return $this->transparentR; }
  231. public function getTransparentG() { return $this->transparentG; }
  232. public function getTransparentB() { return $this->transparentB; }
  233. }