Chris@76: MAX_LZW_BITS = 12; Chris@76: unset($this->Next, $this->Vals, $this->Stack, $this->Buf); Chris@76: Chris@76: $this->Next = range(0, (1 << $this->MAX_LZW_BITS) - 1); Chris@76: $this->Vals = range(0, (1 << $this->MAX_LZW_BITS) - 1); Chris@76: $this->Stack = range(0, (1 << ($this->MAX_LZW_BITS + 1)) - 1); Chris@76: $this->Buf = range(0, 279); Chris@76: } Chris@76: Chris@76: public function decompress($data, &$datLen) Chris@76: { Chris@76: $stLen = strlen($data); Chris@76: $datLen = 0; Chris@76: $ret = ''; Chris@76: Chris@76: $this->LZWCommand($data, true); Chris@76: Chris@76: while (($iIndex = $this->LZWCommand($data, false)) >= 0) Chris@76: $ret .= chr($iIndex); Chris@76: Chris@76: $datLen = $stLen - strlen($data); Chris@76: Chris@76: if ($iIndex != -2) Chris@76: return false; Chris@76: Chris@76: return $ret; Chris@76: } Chris@76: Chris@76: public function LZWCommand(&$data, $bInit) Chris@76: { Chris@76: if ($bInit) Chris@76: { Chris@76: $this->SetCodeSize = ord($data[0]); Chris@76: $data = substr($data, 1); Chris@76: Chris@76: $this->CodeSize = $this->SetCodeSize + 1; Chris@76: $this->ClearCode = 1 << $this->SetCodeSize; Chris@76: $this->EndCode = $this->ClearCode + 1; Chris@76: $this->MaxCode = $this->ClearCode + 2; Chris@76: $this->MaxCodeSize = $this->ClearCode << 1; Chris@76: Chris@76: $this->GetCode($data, $bInit); Chris@76: Chris@76: $this->Fresh = 1; Chris@76: for ($i = 0; $i < $this->ClearCode; $i++) Chris@76: { Chris@76: $this->Next[$i] = 0; Chris@76: $this->Vals[$i] = $i; Chris@76: } Chris@76: Chris@76: for (; $i < (1 << $this->MAX_LZW_BITS); $i++) Chris@76: { Chris@76: $this->Next[$i] = 0; Chris@76: $this->Vals[$i] = 0; Chris@76: } Chris@76: Chris@76: $this->sp = 0; Chris@76: return 1; Chris@76: } Chris@76: Chris@76: if ($this->Fresh) Chris@76: { Chris@76: $this->Fresh = 0; Chris@76: do Chris@76: { Chris@76: $this->FirstCode = $this->GetCode($data, $bInit); Chris@76: $this->OldCode = $this->FirstCode; Chris@76: } Chris@76: while ($this->FirstCode == $this->ClearCode); Chris@76: Chris@76: return $this->FirstCode; Chris@76: } Chris@76: Chris@76: if ($this->sp > 0) Chris@76: { Chris@76: $this->sp--; Chris@76: return $this->Stack[$this->sp]; Chris@76: } Chris@76: Chris@76: while (($Code = $this->GetCode($data, $bInit)) >= 0) Chris@76: { Chris@76: if ($Code == $this->ClearCode) Chris@76: { Chris@76: for ($i = 0; $i < $this->ClearCode; $i++) Chris@76: { Chris@76: $this->Next[$i] = 0; Chris@76: $this->Vals[$i] = $i; Chris@76: } Chris@76: Chris@76: for (; $i < (1 << $this->MAX_LZW_BITS); $i++) Chris@76: { Chris@76: $this->Next[$i] = 0; Chris@76: $this->Vals[$i] = 0; Chris@76: } Chris@76: Chris@76: $this->CodeSize = $this->SetCodeSize + 1; Chris@76: $this->MaxCodeSize = $this->ClearCode << 1; Chris@76: $this->MaxCode = $this->ClearCode + 2; Chris@76: $this->sp = 0; Chris@76: $this->FirstCode = $this->GetCode($data, $bInit); Chris@76: $this->OldCode = $this->FirstCode; Chris@76: Chris@76: return $this->FirstCode; Chris@76: } Chris@76: Chris@76: if ($Code == $this->EndCode) Chris@76: return -2; Chris@76: Chris@76: $InCode = $Code; Chris@76: if ($Code >= $this->MaxCode) Chris@76: { Chris@76: $this->Stack[$this->sp] = $this->FirstCode; Chris@76: $this->sp++; Chris@76: $Code = $this->OldCode; Chris@76: } Chris@76: Chris@76: while ($Code >= $this->ClearCode) Chris@76: { Chris@76: $this->Stack[$this->sp] = $this->Vals[$Code]; Chris@76: $this->sp++; Chris@76: Chris@76: if ($Code == $this->Next[$Code]) // Circular table entry, big GIF Error! Chris@76: return -1; Chris@76: Chris@76: $Code = $this->Next[$Code]; Chris@76: } Chris@76: Chris@76: $this->FirstCode = $this->Vals[$Code]; Chris@76: $this->Stack[$this->sp] = $this->FirstCode; Chris@76: $this->sp++; Chris@76: Chris@76: if (($Code = $this->MaxCode) < (1 << $this->MAX_LZW_BITS)) Chris@76: { Chris@76: $this->Next[$Code] = $this->OldCode; Chris@76: $this->Vals[$Code] = $this->FirstCode; Chris@76: $this->MaxCode++; Chris@76: Chris@76: if (($this->MaxCode >= $this->MaxCodeSize) && ($this->MaxCodeSize < (1 << $this->MAX_LZW_BITS))) Chris@76: { Chris@76: $this->MaxCodeSize *= 2; Chris@76: $this->CodeSize++; Chris@76: } Chris@76: } Chris@76: Chris@76: $this->OldCode = $InCode; Chris@76: if ($this->sp > 0) Chris@76: { Chris@76: $this->sp--; Chris@76: return $this->Stack[$this->sp]; Chris@76: } Chris@76: } Chris@76: Chris@76: return $Code; Chris@76: } Chris@76: Chris@76: public function GetCode(&$data, $bInit) Chris@76: { Chris@76: if ($bInit) Chris@76: { Chris@76: $this->CurBit = 0; Chris@76: $this->LastBit = 0; Chris@76: $this->Done = 0; Chris@76: $this->LastByte = 2; Chris@76: Chris@76: return 1; Chris@76: } Chris@76: Chris@76: if (($this->CurBit + $this->CodeSize) >= $this->LastBit) Chris@76: { Chris@76: if ($this->Done) Chris@76: { Chris@76: // Ran off the end of my bits... Chris@76: if ($this->CurBit >= $this->LastBit) Chris@76: return 0; Chris@76: Chris@76: return -1; Chris@76: } Chris@76: Chris@76: $this->Buf[0] = $this->Buf[$this->LastByte - 2]; Chris@76: $this->Buf[1] = $this->Buf[$this->LastByte - 1]; Chris@76: Chris@76: $count = ord($data[0]); Chris@76: $data = substr($data, 1); Chris@76: Chris@76: if ($count) Chris@76: { Chris@76: for ($i = 0; $i < $count; $i++) Chris@76: $this->Buf[2 + $i] = ord($data{$i}); Chris@76: Chris@76: $data = substr($data, $count); Chris@76: } Chris@76: else Chris@76: $this->Done = 1; Chris@76: Chris@76: $this->LastByte = 2 + $count; Chris@76: $this->CurBit = ($this->CurBit - $this->LastBit) + 16; Chris@76: $this->LastBit = (2 + $count) << 3; Chris@76: } Chris@76: Chris@76: $iRet = 0; Chris@76: for ($i = $this->CurBit, $j = 0; $j < $this->CodeSize; $i++, $j++) Chris@76: $iRet |= (($this->Buf[intval($i / 8)] & (1 << ($i % 8))) != 0) << $j; Chris@76: Chris@76: $this->CurBit += $this->CodeSize; Chris@76: return $iRet; Chris@76: } Chris@76: } Chris@76: Chris@76: class gif_color_table Chris@76: { Chris@76: public $m_nColors; Chris@76: public $m_arColors; Chris@76: Chris@76: public function __construct() Chris@76: { Chris@76: unset($this->m_nColors, $this->m_arColors); Chris@76: } Chris@76: Chris@76: public function load($lpData, $num) Chris@76: { Chris@76: $this->m_nColors = 0; Chris@76: $this->m_arColors = array(); Chris@76: Chris@76: for ($i = 0; $i < $num; $i++) Chris@76: { Chris@76: $rgb = substr($lpData, $i * 3, 3); Chris@76: if (strlen($rgb) < 3) Chris@76: return false; Chris@76: Chris@76: $this->m_arColors[] = (ord($rgb[2]) << 16) + (ord($rgb[1]) << 8) + ord($rgb[0]); Chris@76: $this->m_nColors++; Chris@76: } Chris@76: Chris@76: return true; Chris@76: } Chris@76: Chris@76: public function toString() Chris@76: { Chris@76: $ret = ''; Chris@76: Chris@76: for ($i = 0; $i < $this->m_nColors; $i++) Chris@76: { Chris@76: $ret .= Chris@76: chr(($this->m_arColors[$i] & 0x000000FF)) . // R Chris@76: chr(($this->m_arColors[$i] & 0x0000FF00) >> 8) . // G Chris@76: chr(($this->m_arColors[$i] & 0x00FF0000) >> 16); // B Chris@76: } Chris@76: Chris@76: return $ret; Chris@76: } Chris@76: Chris@76: public function colorIndex($rgb) Chris@76: { Chris@76: $rgb = intval($rgb) & 0xFFFFFF; Chris@76: $r1 = ($rgb & 0x0000FF); Chris@76: $g1 = ($rgb & 0x00FF00) >> 8; Chris@76: $b1 = ($rgb & 0xFF0000) >> 16; Chris@76: $idx = -1; Chris@76: Chris@76: for ($i = 0; $i < $this->m_nColors; $i++) Chris@76: { Chris@76: $r2 = ($this->m_arColors[$i] & 0x000000FF); Chris@76: $g2 = ($this->m_arColors[$i] & 0x0000FF00) >> 8; Chris@76: $b2 = ($this->m_arColors[$i] & 0x00FF0000) >> 16; Chris@76: $d = abs($r2 - $r1) + abs($g2 - $g1) + abs($b2 - $b1); Chris@76: Chris@76: if (($idx == -1) || ($d < $dif)) Chris@76: { Chris@76: $idx = $i; Chris@76: $dif = $d; Chris@76: } Chris@76: } Chris@76: Chris@76: return $idx; Chris@76: } Chris@76: } Chris@76: Chris@76: class gif_file_header Chris@76: { Chris@76: public $m_lpVer, $m_nWidth, $m_nHeight, $m_bGlobalClr, $m_nColorRes; Chris@76: public $m_bSorted, $m_nTableSize, $m_nBgColor, $m_nPixelRatio; Chris@76: public $m_colorTable; Chris@76: Chris@76: public function __construct() Chris@76: { Chris@76: unset($this->m_lpVer, $this->m_nWidth, $this->m_nHeight, $this->m_bGlobalClr, $this->m_nColorRes); Chris@76: unset($this->m_bSorted, $this->m_nTableSize, $this->m_nBgColor, $this->m_nPixelRatio, $this->m_colorTable); Chris@76: } Chris@76: Chris@76: public function load($lpData, &$hdrLen) Chris@76: { Chris@76: $hdrLen = 0; Chris@76: Chris@76: $this->m_lpVer = substr($lpData, 0, 6); Chris@76: if (($this->m_lpVer != 'GIF87a') && ($this->m_lpVer != 'GIF89a')) Chris@76: return false; Chris@76: Chris@76: list ($this->m_nWidth, $this->m_nHeight) = array_values(unpack('v2', substr($lpData, 6, 4))); Chris@76: Chris@76: if (!$this->m_nWidth || !$this->m_nHeight) Chris@76: return false; Chris@76: Chris@76: $b = ord(substr($lpData, 10, 1)); Chris@76: $this->m_bGlobalClr = ($b & 0x80) ? true : false; Chris@76: $this->m_nColorRes = ($b & 0x70) >> 4; Chris@76: $this->m_bSorted = ($b & 0x08) ? true : false; Chris@76: $this->m_nTableSize = 2 << ($b & 0x07); Chris@76: $this->m_nBgColor = ord(substr($lpData, 11, 1)); Chris@76: $this->m_nPixelRatio = ord(substr($lpData, 12, 1)); Chris@76: $hdrLen = 13; Chris@76: Chris@76: if ($this->m_bGlobalClr) Chris@76: { Chris@76: $this->m_colorTable = new gif_color_table(); Chris@76: if (!$this->m_colorTable->load(substr($lpData, $hdrLen), $this->m_nTableSize)) Chris@76: return false; Chris@76: Chris@76: $hdrLen += 3 * $this->m_nTableSize; Chris@76: } Chris@76: Chris@76: return true; Chris@76: } Chris@76: } Chris@76: Chris@76: class gif_image_header Chris@76: { Chris@76: public $m_nLeft, $m_nTop, $m_nWidth, $m_nHeight, $m_bLocalClr; Chris@76: public $m_bInterlace, $m_bSorted, $m_nTableSize, $m_colorTable; Chris@76: Chris@76: public function __construct() Chris@76: { Chris@76: unset($this->m_nLeft, $this->m_nTop, $this->m_nWidth, $this->m_nHeight, $this->m_bLocalClr); Chris@76: unset($this->m_bInterlace, $this->m_bSorted, $this->m_nTableSize, $this->m_colorTable); Chris@76: } Chris@76: Chris@76: public function load($lpData, &$hdrLen) Chris@76: { Chris@76: $hdrLen = 0; Chris@76: Chris@76: // Get the width/height/etc. from the header. Chris@76: list ($this->m_nLeft, $this->m_nTop, $this->m_nWidth, $this->m_nHeight) = array_values(unpack('v4', substr($lpData, 0, 8))); Chris@76: Chris@76: if (!$this->m_nWidth || !$this->m_nHeight) Chris@76: return false; Chris@76: Chris@76: $b = ord($lpData[8]); Chris@76: $this->m_bLocalClr = ($b & 0x80) ? true : false; Chris@76: $this->m_bInterlace = ($b & 0x40) ? true : false; Chris@76: $this->m_bSorted = ($b & 0x20) ? true : false; Chris@76: $this->m_nTableSize = 2 << ($b & 0x07); Chris@76: $hdrLen = 9; Chris@76: Chris@76: if ($this->m_bLocalClr) Chris@76: { Chris@76: $this->m_colorTable = new gif_color_table(); Chris@76: if (!$this->m_colorTable->load(substr($lpData, $hdrLen), $this->m_nTableSize)) Chris@76: return false; Chris@76: Chris@76: $hdrLen += 3 * $this->m_nTableSize; Chris@76: } Chris@76: Chris@76: return true; Chris@76: } Chris@76: } Chris@76: Chris@76: class gif_image Chris@76: { Chris@76: public $m_disp, $m_bUser, $m_bTrans, $m_nDelay, $m_nTrans, $m_lpComm; Chris@76: public $m_gih, $m_data, $m_lzw; Chris@76: Chris@76: public function __construct() Chris@76: { Chris@76: unset($this->m_disp, $this->m_bUser, $this->m_nDelay, $this->m_nTrans, $this->m_lpComm, $this->m_data); Chris@76: $this->m_gih = new gif_image_header(); Chris@76: $this->m_lzw = new gif_lzw_compression(); Chris@76: } Chris@76: Chris@76: public function load($data, &$datLen) Chris@76: { Chris@76: $datLen = 0; Chris@76: Chris@76: while (true) Chris@76: { Chris@76: $b = ord($data[0]); Chris@76: $data = substr($data, 1); Chris@76: $datLen++; Chris@76: Chris@76: switch ($b) Chris@76: { Chris@76: // Extension... Chris@76: case 0x21: Chris@76: $len = 0; Chris@76: if (!$this->skipExt($data, $len)) Chris@76: return false; Chris@76: Chris@76: $datLen += $len; Chris@76: break; Chris@76: Chris@76: // Image... Chris@76: case 0x2C: Chris@76: // Load the header and color table. Chris@76: $len = 0; Chris@76: if (!$this->m_gih->load($data, $len)) Chris@76: return false; Chris@76: Chris@76: $data = substr($data, $len); Chris@76: $datLen += $len; Chris@76: Chris@76: // Decompress the data, and ride on home ;). Chris@76: $len = 0; Chris@76: if (!($this->m_data = $this->m_lzw->decompress($data, $len))) Chris@76: return false; Chris@76: Chris@76: $data = substr($data, $len); Chris@76: $datLen += $len; Chris@76: Chris@76: if ($this->m_gih->m_bInterlace) Chris@76: $this->deInterlace(); Chris@76: Chris@76: return true; Chris@76: Chris@76: case 0x3B: // EOF Chris@76: default: Chris@76: return false; Chris@76: } Chris@76: } Chris@76: return false; Chris@76: } Chris@76: Chris@76: public function skipExt(&$data, &$extLen) Chris@76: { Chris@76: $extLen = 0; Chris@76: Chris@76: $b = ord($data[0]); Chris@76: $data = substr($data, 1); Chris@76: $extLen++; Chris@76: Chris@76: switch ($b) Chris@76: { Chris@76: // Graphic Control... Chris@76: case 0xF9: Chris@76: $b = ord($data[1]); Chris@76: $this->m_disp = ($b & 0x1C) >> 2; Chris@76: $this->m_bUser = ($b & 0x02) ? true : false; Chris@76: $this->m_bTrans = ($b & 0x01) ? true : false; Chris@76: list ($this->m_nDelay) = array_values(unpack('v', substr($data, 2, 2))); Chris@76: $this->m_nTrans = ord($data[4]); Chris@76: break; Chris@76: Chris@76: // Comment... Chris@76: case 0xFE: Chris@76: $this->m_lpComm = substr($data, 1, ord($data[0])); Chris@76: break; Chris@76: Chris@76: // Plain text... Chris@76: case 0x01: Chris@76: break; Chris@76: Chris@76: // Application... Chris@76: case 0xFF: Chris@76: break; Chris@76: } Chris@76: Chris@76: // Skip default as defs may change. Chris@76: $b = ord($data[0]); Chris@76: $data = substr($data, 1); Chris@76: $extLen++; Chris@76: while ($b > 0) Chris@76: { Chris@76: $data = substr($data, $b); Chris@76: $extLen += $b; Chris@76: $b = ord($data[0]); Chris@76: $data = substr($data, 1); Chris@76: $extLen++; Chris@76: } Chris@76: return true; Chris@76: } Chris@76: Chris@76: public function deInterlace() Chris@76: { Chris@76: $data = $this->m_data; Chris@76: Chris@76: for ($i = 0; $i < 4; $i++) Chris@76: { Chris@76: switch ($i) Chris@76: { Chris@76: case 0: Chris@76: $s = 8; Chris@76: $y = 0; Chris@76: break; Chris@76: Chris@76: case 1: Chris@76: $s = 8; Chris@76: $y = 4; Chris@76: break; Chris@76: Chris@76: case 2: Chris@76: $s = 4; Chris@76: $y = 2; Chris@76: break; Chris@76: Chris@76: case 3: Chris@76: $s = 2; Chris@76: $y = 1; Chris@76: break; Chris@76: } Chris@76: Chris@76: for (; $y < $this->m_gih->m_nHeight; $y += $s) Chris@76: { Chris@76: $lne = substr($this->m_data, 0, $this->m_gih->m_nWidth); Chris@76: $this->m_data = substr($this->m_data, $this->m_gih->m_nWidth); Chris@76: Chris@76: $data = Chris@76: substr($data, 0, $y * $this->m_gih->m_nWidth) . Chris@76: $lne . Chris@76: substr($data, ($y + 1) * $this->m_gih->m_nWidth); Chris@76: } Chris@76: } Chris@76: Chris@76: $this->m_data = $data; Chris@76: } Chris@76: } Chris@76: Chris@76: class gif_file Chris@76: { Chris@76: public $header, $image, $data, $loaded; Chris@76: Chris@76: public function __construct() Chris@76: { Chris@76: $this->data = ''; Chris@76: $this->loaded = false; Chris@76: $this->header = new gif_file_header(); Chris@76: $this->image = new gif_image(); Chris@76: } Chris@76: Chris@76: public function loadFile($filename, $iIndex) Chris@76: { Chris@76: if ($iIndex < 0) Chris@76: return false; Chris@76: Chris@76: $this->data = @file_get_contents($filename); Chris@76: if ($this->data === false) Chris@76: return false; Chris@76: Chris@76: // Tell the header to load up.... Chris@76: $len = 0; Chris@76: if (!$this->header->load($this->data, $len)) Chris@76: return false; Chris@76: Chris@76: $this->data = substr($this->data, $len); Chris@76: Chris@76: // Keep reading (at least once) so we get to the actual image we're looking for. Chris@76: for ($j = 0; $j <= $iIndex; $j++) Chris@76: { Chris@76: $imgLen = 0; Chris@76: if (!$this->image->load($this->data, $imgLen)) Chris@76: return false; Chris@76: Chris@76: $this->data = substr($this->data, $imgLen); Chris@76: } Chris@76: Chris@76: $this->loaded = true; Chris@76: return true; Chris@76: } Chris@76: Chris@76: public function get_png_data($background_color) Chris@76: { Chris@76: if (!$this->loaded) Chris@76: return false; Chris@76: Chris@76: // Prepare the color table. Chris@76: if ($this->image->m_gih->m_bLocalClr) Chris@76: { Chris@76: $colors = $this->image->m_gih->m_nTableSize; Chris@76: $pal = $this->image->m_gih->m_colorTable->toString(); Chris@76: Chris@76: if ($background_color != -1) Chris@76: $background_color = $this->image->m_gih->m_colorTable->colorIndex($background_color); Chris@76: } Chris@76: elseif ($this->header->m_bGlobalClr) Chris@76: { Chris@76: $colors = $this->header->m_nTableSize; Chris@76: $pal = $this->header->m_colorTable->toString(); Chris@76: Chris@76: if ($background_color != -1) Chris@76: $background_color = $this->header->m_colorTable->colorIndex($background_color); Chris@76: } Chris@76: else Chris@76: { Chris@76: $colors = 0; Chris@76: $background_color = -1; Chris@76: } Chris@76: Chris@76: if ($background_color == -1) Chris@76: $background_color = $this->header->m_nBgColor; Chris@76: Chris@76: $data = &$this->image->m_data; Chris@76: $header = &$this->image->m_gih; Chris@76: Chris@76: $i = 0; Chris@76: $bmp = ''; Chris@76: Chris@76: // Prepare the bitmap itself. Chris@76: for ($y = 0; $y < $this->header->m_nHeight; $y++) Chris@76: { Chris@76: $bmp .= "\x00"; Chris@76: Chris@76: for ($x = 0; $x < $this->header->m_nWidth; $x++, $i++) Chris@76: { Chris@76: // Is this in the proper range? If so, get the specific pixel data... Chris@76: if ($x >= $header->m_nLeft && $y >= $header->m_nTop && $x < ($header->m_nLeft + $header->m_nWidth) && $y < ($header->m_nTop + $header->m_nHeight)) Chris@76: $bmp .= $data{$i}; Chris@76: // Otherwise, this is background... Chris@76: else Chris@76: $bmp .= chr($background_color); Chris@76: } Chris@76: } Chris@76: Chris@76: $bmp = gzcompress($bmp, 9); Chris@76: Chris@76: // Output the basic signature first of all. Chris@76: $out = "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A"; Chris@76: Chris@76: // Now, we want the header... Chris@76: $out .= "\x00\x00\x00\x0D"; Chris@76: $tmp = 'IHDR' . pack('N', (int) $this->header->m_nWidth) . pack('N', (int) $this->header->m_nHeight) . "\x08\x03\x00\x00\x00"; Chris@76: $out .= $tmp . pack('N', smf_crc32($tmp)); Chris@76: Chris@76: // The palette, assuming we have one to speak of... Chris@76: if ($colors > 0) Chris@76: { Chris@76: $out .= pack('N', (int) $colors * 3); Chris@76: $tmp = 'PLTE' . $pal; Chris@76: $out .= $tmp . pack('N', smf_crc32($tmp)); Chris@76: } Chris@76: Chris@76: // Do we have any transparency we want to make available? Chris@76: if ($this->image->m_bTrans && $colors > 0) Chris@76: { Chris@76: $out .= pack('N', (int) $colors); Chris@76: $tmp = 'tRNS'; Chris@76: Chris@76: // Stick each color on - full transparency or none. Chris@76: for ($i = 0; $i < $colors; $i++) Chris@76: $tmp .= $i == $this->image->m_nTrans ? "\x00" : "\xFF"; Chris@76: Chris@76: $out .= $tmp . pack('N', smf_crc32($tmp)); Chris@76: } Chris@76: Chris@76: // Here's the data itself! Chris@76: $out .= pack('N', strlen($bmp)); Chris@76: $tmp = 'IDAT' . $bmp; Chris@76: $out .= $tmp . pack('N', smf_crc32($tmp)); Chris@76: Chris@76: // EOF marker... Chris@76: $out .= "\x00\x00\x00\x00" . 'IEND' . "\xAE\x42\x60\x82"; Chris@76: Chris@76: return $out; Chris@76: } Chris@76: } Chris@76: Chris@76: // crc32 doesn't work as expected on 64-bit functions - make our own. Chris@76: // http://www.php.net/crc32#79567 Chris@76: if (!function_exists('smf_crc32')) Chris@76: { Chris@76: function smf_crc32($number) Chris@76: { Chris@76: $crc = crc32($number); Chris@76: Chris@76: if ($crc & 0x80000000) Chris@76: { Chris@76: $crc ^= 0xffffffff; Chris@76: $crc += 1; Chris@76: $crc = -$crc; Chris@76: } Chris@76: Chris@76: return $crc; Chris@76: } Chris@76: } Chris@76: Chris@76: ?>