MOON
Server: Apache
System: Linux vps.erhabenn.com.br 3.10.0-1160.119.1.el7.tuxcare.els2.x86_64 #1 SMP Mon Jul 15 12:09:18 UTC 2024 x86_64
User: machen (1008)
PHP: 8.2.31
Disabled: NONE
Upload Files
File: /disk001/machen/www/support/wp-content/plugins/gif-uploader-wp-grandplugins/includes/GifHelper.php
<?php
namespace Grafika\Gd\Helper;

final class GifHelper {

	/**
	 * @param $imageFile
	 *
	 * @return GifByteStream
	 * @throws \Exception
	 */
	public function open( $imageFile ) {
		$fp = fopen( $imageFile, 'rb' ); // Binary read

		if ( $fp === false ) {
			throw new \Exception( sprintf( 'Error loading file: "%s".', $imageFile ) );
		}

		$size  = filesize( $imageFile );
		$bytes = fread( $fp, $size );
		$bytes = unpack( 'H*', $bytes ); // Unpack as hex
		$bytes = $bytes[1];
		fclose( $fp );

		return new GifByteStream( $bytes );
	}

	/**
	 * @param string $bin Raw binary data from imagegif or file_get_contents
	 *
	 * @return GifByteStream
	 */
	public function load( $bin ) {
		$bytes = unpack( 'H*', $bin ); // Unpack as hex
		$bytes = $bytes[1];

		return new GifByteStream( $bytes );
	}

	/**
	 * @param GifByteStream $bytes
	 *
	 * @return bool
	 */
	public function isAnimated( $bytes ) {

		$bytes->setPosition( 13 );
		$lastPos  = $bytes->getPosition();
		$gceCount = 0;
		while ( ( $lastPos = $bytes->find( '21f904', $lastPos ) ) !== false ) {
			$gceCount++;
			if ( $gceCount > 1 ) {
				return true;
			}
		}
		return false;
	}

	/**
	 * Encode data into GIF hex string.
	 *
	 * @param array $data The array returned by decode.
	 *
	 * @return string Hex string of GIF
	 */
	public function encode( $data ) {
		$hex = '';
		// header block
		$hex .= $this->_fixSize( $this->_asciiToHex( $data['signature'] ), 3 );
		$hex .= $this->_fixSize( $this->_asciiToHex( $data['version'] ), 3 );

		// logical screen descriptor block
		$hex         .= $this->_switchEndian( $this->_fixSize( dechex( $data['canvasWidth'] ), 4 ) );
		$hex         .= $this->_switchEndian( $this->_fixSize( dechex( $data['canvasHeight'] ), 4 ) );
		$packedField  = decbin( $data['globalColorTableFlag'] );
		$packedField .= $this->_fixSize( decbin( $data['colorResolution'] ), 3 );
		$packedField .= decbin( $data['sortFlag'] );
		$packedField .= $this->_fixSize( decbin( $data['sizeOfGlobalColorTable'] ), 3 );
		$hex         .= $this->_fixSize( dechex( bindec( $packedField ) ), 2 );
		$hex         .= $this->_fixSize( dechex( $data['backgroundColorIndex'] ), 2 );
		$hex         .= $this->_fixSize( dechex( $data['pixelAspectRatio'] ), 2 );

		// global color table optional
		if ( $data['globalColorTableFlag'] > 0 ) {
			$hex .= $data['globalColorTable'];
		}
		// app ext optional
		if ( isset( $data['applicationExtension'] ) ) {
			foreach ( $data['applicationExtension'] as $app ) {
				$hex .= '21ff0b';
				$hex .= $this->_fixSize( $this->_asciiToHex( $app['appId'] ), 8 );
				$hex .= $this->_fixSize( $this->_asciiToHex( $app['appCode'] ), 3 );
				foreach ( $app['subBlocks'] as $subBlock ) {
					$len  = $this->_fixSize( dechex( strlen( $subBlock ) / 2 ), 2 );
					$hex .= $len . $subBlock;
				}
				$hex .= '00';
			}
		}

		foreach ( $data['frames'] as $i => $frame ) {

			// graphics control optional
			if ( isset( $frame['delayTime'] ) ) {
				$hex         .= '21f904';
				$packedField  = '000'; // reserved
				$packedField .= $this->_fixSize( decbin( $frame['disposalMethod'] ), 3 );
				$packedField .= decbin( $frame['userInputFlag'] );
				$packedField .= decbin( $frame['transparentColorFlag'] );
				$hex         .= $this->_fixSize( dechex( bindec( $packedField ) ), 2 );
				$hex         .= $this->_switchEndian( $this->_fixSize( dechex( $frame['delayTime'] ), 4 ) );
				$hex         .= $this->_switchEndian( $this->_fixSize( dechex( $frame['transparentColorIndex'] ), 2 ) );
				$hex         .= '00';
			}

			// image desc
			$hex         .= '2c';
			$hex         .= $this->_switchEndian( $this->_fixSize( dechex( $frame['imageLeft'] ), 4 ) );
			$hex         .= $this->_switchEndian( $this->_fixSize( dechex( $frame['imageTop'] ), 4 ) );
			$hex         .= $this->_switchEndian( $this->_fixSize( dechex( $frame['imageWidth'] ), 4 ) );
			$hex         .= $this->_switchEndian( $this->_fixSize( dechex( $frame['imageHeight'] ), 4 ) );
			$packedField  = decbin( $frame['localColorTableFlag'] );
			$packedField .= decbin( $frame['interlaceFlag'] );
			$packedField .= decbin( $frame['sortFlag'] );
			$packedField .= '00'; // reserved
			$packedField .= $this->_fixSize( decbin( $frame['sizeOfLocalColorTable'] ), 3 );
			$hex         .= $this->_fixSize( dechex( bindec( $packedField ) ), 2 );

			// local color table optional
			if ( $frame['localColorTableFlag'] > 0 ) {
				$hex .= $frame['localColorTable'];
			}

			$hex .= $frame['imageData'];
		}
		$hex .= $data['trailer'];
		return $hex;
	}

	/**
	 * Decode GIF into array of data for easy use in PHP userland.
	 *
	 * @param GifByteStream $bytes Decode byte stream into array of GIF blocks.
	 *
	 * @return array Array containing GIF data
	 * @throws \Exception
	 */
	public function decode( $bytes ) {
		$bytes->setPosition( 0 );
		$blocks = $this->decodeToBlocks( $bytes );

		return $this->expandBlocks( $blocks );
	}

	/**
	 * Decompose GIF into its block components. The GIF blocks are in the order that they appear in the byte stream.
	 *
	 * @param GifByteStream $bytes
	 *
	 * @return array
	 * @throws \Exception
	 */
	public function decodeToBlocks( $bytes ) {
		$bytes->setPosition( 0 );
		$blocks = array();

		// Header block
		$blocks['header'] = $bytes->bite( 6 );

		// Logical screen descriptor block
		$part                   = $bytes->bite( 2 ); // canvass w
		$hex                    = $part;
		$part                   = $bytes->bite( 2 ); // canvass h
		$hex                   .= $part;
		$part                   = $bytes->bite( 1 ); // packed field
		$hex                   .= $part;
		$bin                    = $this->_fixSize( $this->_hexToBin( $part ), 8 );
		$globalColorTableFlag   = bindec( substr( $bin, 0, 1 ) );
		$sizeOfGlobalColorTable = bindec( substr( $bin, 5, 3 ) );

		$part                              = $bytes->bite( 1 ); // backgroundColorIndex
		$hex                              .= $part;
		$part                              = $bytes->bite( 1 ); // pixelAspectRatio
		$hex                              .= $part;
		$blocks['logicalScreenDescriptor'] = $hex;

		// Global color table is optional so check its existence
		if ( $globalColorTableFlag > 0 ) {
			// Formula: 3 * (2^(N+1))
			$colorTableLength           = 3 * ( pow( 2, ( $sizeOfGlobalColorTable + 1 ) ) );
			$part                       = $bytes->bite( $colorTableLength );
			$blocks['globalColorTable'] = $part;
		}

		$commentC = $plainTextC = $appCount = $gce = $dc = 0; // index count
		while ( ! $bytes->isEnd() ) {
			$part = $bytes->bite( 1 );

			if ( '21' === $part ) { // block tests
				$hex  = $part;
				$part = $bytes->bite( 1 );
				if ( 'ff' === $part ) { // App extension block
					$hex .= $part;
					$part = $bytes->bite( 1 ); // app name length should be 0x0b or int 11 but we check anyways
					$size = hexdec( $part ); // turn it to int
					$hex .= $part;
					$part = $bytes->bite( $size ); // app name
					$hex .= $part;
					while ( ! $bytes->isEnd() ) { // loop thru all app sub blocks
						$nextSize = $bytes->bite( 1 );
						if ( $nextSize !== '00' ) {
							$hex .= $nextSize;
							$size = hexdec( $nextSize );
							$part = $bytes->bite( $size );
							$hex .= $part;
						} else {
							$hex .= $nextSize;
							$blocks[ 'applicationExtension-' . $appCount ] = $hex;
							break;
						}
					}

					$appCount++;
				} elseif ( 'f9' === $part ) { // graphic
					$hex                                        .= $part;
					$part                                        = $bytes->bite( 1 ); // size
					$hex                                        .= $part;
					$part                                        = $bytes->bite( 1 ); // packed field
					$hex                                        .= $part;
					$part                                        = $bytes->bite( 2 ); // delay time
					$hex                                        .= $part;
					$part                                        = $bytes->bite( 1 ); // trans color index
					$hex                                        .= $part;
					$part                                        = $bytes->bite( 1 ); // terminator
					$hex                                        .= $part;
					$blocks[ 'graphicControlExtension-' . $gce ] = $hex;
					$gce++;
				} elseif ( '01' === $part ) { // plain text ext
					$hex .= $part;

					while ( ! $bytes->isEnd() ) { // loop thru all app sub blocks
						$nextSize = $bytes->bite( 1 );
						if ( $nextSize !== '00' ) {
							$hex .= $nextSize;
							$size = hexdec( $nextSize );
							$part = $bytes->bite( $size );
							$hex .= $part;
						} else {
							$hex .= $nextSize;
							$blocks[ 'plainTextExtension-' . $plainTextC ] = $hex;
							break;
						}
					}
					$plainTextC++;
				} elseif ( 'fe' === $part ) { // comment ext
					$hex .= $part;

					while ( ! $bytes->isEnd() ) { // loop thru all app sub blocks
						$nextSize = $bytes->bite( 1 );
						if ( $nextSize !== '00' ) {
							$hex .= $nextSize;
							$size = hexdec( $nextSize );
							$part = $bytes->bite( $size );
							$hex .= $part;
						} else {
							$hex                                      .= $nextSize;
							$blocks[ 'commentExtension-' . $commentC ] = $hex;
							break;
						}
					}
					$commentC++;
				}
			} elseif ( '2c' === $part ) { // image descriptors
				$hex                                = $part;
				$part                               = $bytes->bite( 2 ); // imageLeft
				$hex                               .= $part;
				$part                               = $bytes->bite( 2 ); // imageTop
				$hex                               .= $part;
				$part                               = $bytes->bite( 2 ); // imageWidth
				$hex                               .= $part;
				$part                               = $bytes->bite( 2 ); // imageHeight
				$hex                               .= $part;
				$part                               = $bytes->bite( 1 ); // packed field
				$hex                               .= $part;
				$blocks[ 'imageDescriptor-' . $dc ] = $hex;
				$bin                                = $this->_fixSize( $this->_hexToBin( $part ), 8 );
				$localColorTableFlag                = bindec( substr( $bin, 0, 1 ) );
				$sizeOfLocalColorTable              = bindec( substr( $bin, 5, 3 ) );

				// LC
				if ( $localColorTableFlag ) {
					// Formula: 3 * (2^(N+1))
					$localColorTableLen                 = 3 * ( pow( 2, ( $sizeOfLocalColorTable + 1 ) ) );
					$part                               = $bytes->bite( $localColorTableLen );
					$blocks[ 'localColorTable-' . $dc ] = $part;
				}

				// Image data
				$part = $bytes->bite( 1 ); // LZW code
				$hex  = $part;
				while ( $bytes->isEnd() === false ) {
					$nextSize = $bytes->bite( 1 );
					$hex     .= $nextSize;
					if ( $nextSize !== '00' ) {
						// In case the Frame imageData is corrupted.
						if ( hexdec( $nextSize ) + $bytes->getPosition() >= $bytes->length() ) {
							break;
						}
						$subBlockLen = hexdec( $nextSize );
						$subBlock    = $bytes->bite( $subBlockLen );
						$hex        .= $subBlock;
					} else {
						$blocks[ 'imageData-' . $dc ] = $hex;
						break;
					}
				}

				// Skip a frame if it has no imageData.
				if ( ! isset( $blocks[ 'imageData-' . $dc ] ) ) {
					unset( $blocks[ 'localColorTable-' . $dc ] );
					unset( $blocks[ 'imageDescriptor-' . $dc ] );
					unset( $blocks[ 'graphicControlExtension-' . $dc ] );
				}
				$dc++;

			} else {
				$blocks['trailer'] = $part;
				break;
			}
		}

		$blocks['trailer'] = '3b';

		return $blocks;
	}

	/**
	 * Expand GIF blocks into useful info.
	 *
	 * @param array $blocks Accepts the array returned by decodeToBlocks
	 *
	 * @return array
	 */
	public function expandBlocks( $blocks ) {

		$decoded = array();
		foreach ( $blocks as $blockName => $block ) {
			$bytes = new GifByteStream( $block );
			if ( false !== strpos( $blockName, 'header' ) ) {
				$part                 = $bytes->bite( 3 );
				$decoded['signature'] = $this->_hexToAscii( $part );
				$part                 = $bytes->bite( 3 );
				$decoded['version']   = $this->_hexToAscii( $part );
			} elseif ( false !== strpos( $blockName, 'logicalScreenDescriptor' ) ) {
				$part                              = $bytes->bite( 2 );
				$decoded['canvasWidth']            = hexdec( $this->_switchEndian( $part ) );
				$part                              = $bytes->bite( 2 );
				$decoded['canvasHeight']           = hexdec( $this->_switchEndian( $part ) );
				$part                              = $bytes->bite( 1 );
				$bin                               = $this->_fixSize( $this->_hexToBin( $part ), 8 ); // Make sure len is correct
				$decoded['globalColorTableFlag']   = bindec( substr( $bin, 0, 1 ) );
				$decoded['colorResolution']        = bindec( substr( $bin, 1, 3 ) );
				$decoded['sortFlag']               = bindec( substr( $bin, 4, 1 ) );
				$decoded['sizeOfGlobalColorTable'] = bindec( substr( $bin, 5, 3 ) );
				$part                              = $bytes->bite( 1 );
				$decoded['backgroundColorIndex']   = hexdec( $part );
				$part                              = $bytes->bite( 1 );
				$decoded['pixelAspectRatio']       = hexdec( $part );

			} elseif ( false !== strpos( $blockName, 'globalColorTable' ) ) {
				$decoded['globalColorTable'] = $block;
			} elseif ( false !== strpos( $blockName, 'applicationExtension' ) ) {
				$index = explode( '-', $blockName, 2 );
				$index = $index[1];

				$bytes->next( 2 ); // Skip ext intro and label: 21 ff
				$appNameSize = $bytes->bite( 1 ); // 0x0b or 11 according to spec but we check anyways
				$appNameSize = hexdec( $appNameSize );
				$appName     = $this->_hexToAscii( $bytes->bite( $appNameSize ) );
				$subBlocks   = array();
				while ( ! $bytes->isEnd() ) { // loop thru all app sub blocks
					$nextSize = $bytes->bite( 1 );
					if ( $nextSize !== '00' ) {
						$size        = hexdec( $nextSize );
						$subBlocks[] = $bytes->bite( $size );

					}
				}
				if ( $appName === 'NETSCAPE2.0' ) {
					$decoded['applicationExtension'][ $index ]['appId']     = 'NETSCAPE';
					$decoded['applicationExtension'][ $index ]['appCode']   = '2.0';
					$decoded['applicationExtension'][ $index ]['subBlocks'] = $subBlocks;
					$decoded['loopCount']                                   = hexdec( $this->_switchEndian( substr( $subBlocks[0], 2, 4 ) ) );
				} else {
					$decoded['applicationExtension'][ $index ]['appId']     = substr( $appName, 0, 8 );
					$decoded['applicationExtension'][ $index ]['appCode']   = substr( $appName, 8, 3 );
					$decoded['applicationExtension'][ $index ]['subBlocks'] = $subBlocks;
				}
			} elseif ( false !== strpos( $blockName, 'graphicControlExtension' ) ) {
				$index = explode( '-', $blockName, 2 );
				$index = $index[1];

				$bytes->next( 3 ); // Skip ext intro, label, and block size which is always 4: 21 f9 04
				$part = $bytes->bite( 1 ); // packed field
				$bin  = $this->_fixSize( $this->_hexToBin( $part ), 8 ); // Make sure len is correct
				$decoded['frames'][ $index ]['disposalMethod']       = bindec( substr( $bin, 3, 3 ) );
				$decoded['frames'][ $index ]['userInputFlag']        = bindec( substr( $bin, 6, 1 ) );
				$decoded['frames'][ $index ]['transparentColorFlag'] = bindec( substr( $bin, 7, 1 ) );
				$part                                     = $bytes->bite( 2 );
				$decoded['frames'][ $index ]['delayTime'] = hexdec( $this->_switchEndian( $part ) );
				$part                                     = $bytes->bite( 1 );
				$decoded['frames'][ $index ]['transparentColorIndex'] = hexdec( $part );
			} elseif ( false !== strpos( $blockName, 'imageDescriptor' ) ) {
				$index = explode( '-', $blockName, 2 );
				$index = $index[1];

				$bytes->next( 1 ); // skip separator: 2c
				$part                                       = $bytes->bite( 2 );
				$decoded['frames'][ $index ]['imageLeft']   = hexdec( $this->_switchEndian( $part ) );
				$part                                       = $bytes->bite( 2 );
				$decoded['frames'][ $index ]['imageTop']    = hexdec( $this->_switchEndian( $part ) );
				$part                                       = $bytes->bite( 2 );
				$decoded['frames'][ $index ]['imageWidth']  = hexdec( $this->_switchEndian( $part ) );
				$part                                       = $bytes->bite( 2 );
				$decoded['frames'][ $index ]['imageHeight'] = hexdec( $this->_switchEndian( $part ) );
				$part                                       = $bytes->bite( 1 ); // packed field
				$bin                                        = $this->_fixSize(
					$this->_hexToBin( $part ),
					8
				);
				$decoded['frames'][ $index ]['localColorTableFlag']   = bindec( substr( $bin, 0, 1 ) );
				$decoded['frames'][ $index ]['interlaceFlag']         = bindec( substr( $bin, 1, 1 ) );
				$decoded['frames'][ $index ]['sortFlag']              = bindec( substr( $bin, 2, 1 ) );
				$decoded['frames'][ $index ]['sizeOfLocalColorTable'] = bindec( substr( $bin, 5, 3 ) );
			} elseif ( false !== strpos( $blockName, 'localColorTable' ) ) {
				$index = explode( '-', $blockName, 2 );
				$index = $index[1];
				$decoded['frames'][ $index ]['localColorTable'] = $block;
			} elseif ( false !== strpos( $blockName, 'imageData' ) ) {
				$index = explode( '-', $blockName, 2 );
				$index = $index[1];

				$decoded['frames'][ $index ]['imageData'] = $block;
			} elseif ( $blockName === 'trailer' ) {
				$decoded['trailer'] = $block;
			}
			unset( $bytes );
		}

		return $decoded;
	}

	/**
	 * @param array $blocks The array returned by decode.
	 *
	 * @return array Array of images each containing 1 of each frames of the original image.
	 */
	public function splitFrames( $blocks ) {
		$images = array();
		if ( isset( $blocks['frames'] ) ) {
			foreach ( $blocks['frames'] as $a => $unused ) {
				$images[ $a ] = $blocks;
				unset( $images[ $a ]['frames'] ); // remove all frames.
				foreach ( $blocks['frames'] as $b => $frame ) {
					if ( $a === $b ) {
						$images[ $a ]['frames'][0] = $frame; // Re-add frames but use only 1 frame and discard others
						break;
					}
				}
			}
		}
		return $images;
	}

	/**
	 * @param $blocks
	 * @param $newW
	 * @param $newH
	 *
	 * @return array $blocks
	 */
	public function resize( $blocks, $newW, $newH ) {
		$images       = $this->splitFrames( $blocks );
		$firstFrameGd = null;

		if ( empty( $images ) ) {
			return $blocks;
		}
		$cX = $newW / $blocks['canvasWidth'];
		$cY = $newH / $blocks['canvasHeight'];

		// Loop on individual images and resize them using Gd
		foreach ( $images as $imageIndex => $image ) {
			$hex       = $this->encode( $image );
			$binaryRaw = pack( 'H*', $hex );

			// Utilize gd for resizing
			$old    = imagecreatefromstring( $binaryRaw );
			$width  = imagesx( $old );
			$height = imagesy( $old );
			$new    = imagecreatetruecolor( $newW, $newH ); // Create a blank image

			// Fill transparent background with white bg for separate frames [ DisposalMethod = 2 ].
			if ( ! empty( $blocks['frames'][ $imageIndex ] ) && ( 2 === $blocks['frames'][ $imageIndex ]['disposalMethod'] ) ) {
				$blank_text_bg_color = imagecolorallocate( $new, 255, 255, 255 );
				imagefill( $new, 0, 0, $blank_text_bg_color );
			}

			// otherwise stack the frames on the first frame [ DisposalMethod = 1|3 ]
			if ( ! is_null( $firstFrameGd ) && ! empty( $blocks['frames'][ $imageIndex ] ) && ( 2 !== $blocks['frames'][ $imageIndex ]['disposalMethod'] ) ) {
				imagedestroy( $new );
                $new = $firstFrameGd;
			}
			// Account for frame imageLeft and imageTop
			$dX           = $image['frames'][0]['imageLeft'];
			$dY           = $image['frames'][0]['imageTop'];
			$frame_width  = $image['frames'][0]['imageWidth'];
			$frame_height = $image['frames'][0]['imageHeight'];
			$dst_x        = (int) round( $dX * $cX );
			$dst_y        = (int) round( $dY * $cY );
			$dst_width    = (int) round( $frame_width * $cX );
			$dst_height   = (int) round( $frame_height * $cY );

			imagecopyresampled(
				$new,
				$old,
				$dst_x,
				$dst_y,
				0,
				0,
				$dst_width,
				$dst_height,
				$width,
				$height
			);

			ob_start();
			imagegif( $new );
			$binaryRaw = ob_get_contents();
			ob_end_clean();


			if ( is_null( $firstFrameGd ) ) {
				$firstFrameGd = $new;
			}
			imagedestroy( $old );

			// Hex of resized
			$bytes  = $this->load( $binaryRaw );
			$hexNew = $this->decode( $bytes );

			// Update original frames with hex from resized frames
			$blocks['frames'][ $imageIndex ]['imageWidth']  = $hexNew['frames'][0]['imageWidth'];
			$blocks['frames'][ $imageIndex ]['imageHeight'] = $hexNew['frames'][0]['imageHeight'];
			$blocks['frames'][ $imageIndex ]['imageLeft']   = $hexNew['frames'][0]['imageLeft'];
			$blocks['frames'][ $imageIndex ]['imageTop']    = $hexNew['frames'][0]['imageTop'];
			// $blocks['frames'][ $imageIndex ]['imageLeft']     = $dst_x;
			// $blocks['frames'][ $imageIndex ]['imageTop']      = $dst_y;
			$blocks['frames'][ $imageIndex ]['imageData']     = $hexNew['frames'][0]['imageData'];
			$blocks['frames'][ $imageIndex ]['interlaceFlag'] = $hexNew['frames'][0]['interlaceFlag'];
			$blocks['frames'][ $imageIndex ]['sortFlag']      = $hexNew['frames'][0]['sortFlag'];
			// We use local color tables on each frame. This will result in faster processing since we dont have to process the global color table at the cost of a larger file size.
			$blocks['frames'][ $imageIndex ]['localColorTableFlag'] = $hexNew['globalColorTableFlag'];
			if ( 1 === $hexNew['globalColorTableFlag'] && ! empty( $hexNew['globalColorTable'] ) ) {
				$blocks['frames'][ $imageIndex ]['localColorTable']       = $hexNew['globalColorTable'];
				$blocks['frames'][ $imageIndex ]['sizeOfLocalColorTable'] = $hexNew['sizeOfGlobalColorTable'];
				$blocks['frames'][ $imageIndex ]['transparentColorFlag']  = 0;
			}
		}
		// Update dimensions or else imagecreatefromgif will choke.
		$blocks['canvasWidth']  = $newW;
		$blocks['canvasHeight'] = $newH;
		// Disable flickering bug. Also we are using localColorTable anyways.
		$blocks['globalColorTableFlag'] = 0;
		$blocks['globalColorTable']     = '';
		if ( ! is_null( $firstFrameGd ) ) {
			@imagedestroy( $firstFrameGd );
		}
		return $blocks;
	}

	/**
	 * @param $asciiString
	 *
	 * @return string
	 */
	private function _asciiToHex( $asciiString ) {
		$chars  = str_split( $asciiString, 1 );
		$string = '';
		foreach ( $chars as $char ) {
			$string .= dechex( ord( $char ) );
		}
		return $string;
	}

	/**
	 * @param $hexString
	 *
	 * @return string
	 */
	private function _hexToAscii( $hexString ) {
		$bytes  = str_split( $hexString, 2 );
		$string = '';
		foreach ( $bytes as $byte ) {
			$string .= chr( hexdec( $byte ) ); // convert hex to dec to ascii character. See http://www.ascii.cl/
		}
		return $string;
	}

	/**
	 * @param $hexString
	 *
	 * @return string
	 */
	private function _hexToBin( $hexString ) {
		return base_convert( $hexString, 16, 2 );
	}

	/**
	 * @param $string
	 * @param $size
	 * @param string $char
	 *
	 * @return string
	 */
	private function _fixSize( $string, $size, $char = '0' ) {
		return str_pad( $string, $size, $char, STR_PAD_LEFT );
	}

	/**
	 * @param $hexString
	 *
	 * @return string
	 */
	private function _switchEndian( $hexString ) {
		return implode( '', array_reverse( str_split( $hexString, 2 ) ) );
	}
}