What's Here?
Members: 132,704
Replies: 471,812
Topics: 73,159
Snippets: 2,541
Tutorials: 667
Total Online: 1,376
Members: 76
Guests: 1,300
Who's Online?
Loading. Please Wait...
PHP PNG Library
PHP PNG Library, An attempt at creating a non-extension PNG library for PHP.
grimpirate
16 Sep, 2008 - 11:37 AM
D.I.C Head
Joined: 3 Aug, 2006
Posts: 187
Thanked 5 times
Dream Kudos: 375
My Contributions
Alright here's my idea. Some servers don't provide the gd or zlib extensions for PHP. PNG is a widely accepted internet picture format. If you don't have gd for php it's impossible to make things such as captcha images and the like. Therefore, I'm working on creating a PNG library that works using only the already available PHP functions (those that don't need a special install or directive enable). Right now the code I have is very limited. The limitations are as follows:
Images must be truecolor with alpha No error handling zlib is implemented using the gzcompress function of php (must remake zlib to be completely independent) PNG output images have only been viewable thus far on Opera If anyone can offer some help/guidance as to why these images aren't viewable on other browsers or in media editors/picture viewers please let me know what I'm doing wrong. To me the PNG stream seems compliant, but I'm no guru. I can also save the image from the browser and view it using Windows Picture and Fax Viewer and Paint surprisingly. However, Internet Explorer and Firefox won't show the image. Two PHP files work the code as of now. Here they are:
png.php
php
<?php require_once('crcpng.php'); header("Content-type: image/png"); $png = new PNG(69, 5); $png->line(0, 0, 3, 0); $png->line(6, 0, 9, 0); $png->line(12, 0, 16, 0); $png->line(19, 0, 21, 0); $png->line(24, 0, 28, 0); $png->line(32, 0, 36, 0); $png->pixel(38, 0); $png->pixel(42, 0); $png->line(46, 0, 50, 0); $png->line(52, 0, 56, 0); $png->line(58, 0, 61, 0); $png->line(64, 0, 68, 0); $png->pixel(0, 1); $png->pixel(4, 1); $png->pixel(6, 1); $png->pixel(10, 1); $png->pixel(12, 1); $png->pixel(18, 1); $png->pixel(22, 1); $png->pixel(24, 1); $png->pixel(26, 1); $png->pixel(28, 1); $png->pixel(34, 1); $png->pixel(38, 1); $png->pixel(39, 1); $png->pixel(42, 1); $png->pixel(46, 1); $png->pixel(52, 1); $png->pixel(56, 1); $png->pixel(58, 1); $png->pixel(62, 1); $png->pixel(64, 1); $png->pixel(0, 2); $png->pixel(4, 2); $png->line(6, 2, 10, 2); $png->line(12, 2, 15, 2); $png->pixel(18, 2); $png->pixel(22, 2); $png->pixel(24, 2); $png->pixel(26, 2); $png->pixel(28, 2); $png->pixel(34, 2); $png->pixel(38, 2); $png->pixel(40, 2); $png->pixel(42, 2); $png->pixel(46, 2); $png->pixel(52, 2); $png->pixel(56, 2); $png->pixel(58, 2); $png->pixel(62, 2); $png->line(64, 2, 67, 2); $png->pixel(0, 3); $png->pixel(4, 3); $png->pixel(6, 3); $png->pixel(8, 3); $png->pixel(12, 3); $png->line(18, 3, 22, 3); $png->pixel(24, 3); $png->pixel(26, 3); $png->pixel(28, 3); $png->pixel(34, 3); $png->pixel(38, 3); $png->pixel(41, 3); $png->pixel(42, 3); $png->pixel(46, 3); $png->pixel(52, 3); $png->pixel(56, 3); $png->pixel(58, 3); $png->pixel(62, 3); $png->pixel(64, 3); $png->line(0, 4, 3, 4); $png->pixel(6, 4); $png->pixel(9, 4); $png->pixel(10, 4); $png->line(12, 4, 16, 4); $png->pixel(18, 4); $png->pixel(22, 4); $png->pixel(24, 4); $png->pixel(28, 4); $png->pixel(30, 4); $png->line(32, 4, 36, 4); $png->pixel(38, 4); $png->pixel(42, 4); $png->pixel(44, 4); $png->line(46, 4, 50, 4); $png->line(52, 4, 56, 4); $png->line(58, 4, 61, 4); $png->line(64, 4, 68, 4); echo $png->resultantImage(); class PNG { var $signature; // 8 bytes var $width; // 4 bytes var $height; // 4 bytes var $bit_depth; // 1 byte var $colour_type; // 1 byte var $compression_method; // 1 byte var $filter_method; // 1 byte var $interlace_method; // 1 byte var $pixelData; // n bytes function PNG($width, $height, $bit_depth = 8, $colour_type = 6, $compression_method = 0, $filter_method = 0, $interlace_method = 0){ $this->signature = chr(137) . 'PNG' . chr(13) . chr(10) . chr(26) . chr(10); $this->width = $width; $this->height = $height; $this->bit_depth = $bit_depth; $this->colour_type = $colour_type; $this->compression_method = $compression_method; $this->filter_method = $filter_method; $this->interlace_method = $interlace_method; for($i = 0; $i < $height; $i++){ $this->pixelData[] = array(); for($j = 0; $j < $width; $j++){ $this->pixelData[$i][] = chr(255) . chr(255) . chr(255) . chr(0); } } } function chunk($type){ $chunk = array( 'length' => null, // 4 bytes 'type' => null, // 4 bytes 'data' => null, // n bytes 'crc' => null // 4 bytes ); if(!strcmp('IHDR', $type)){ $chunk['type'] = 'IHDR'; $chunk['data'] = writableInt($this->width) . writableInt($this->height) . chr($this->bit_depth) . chr($this->colour_type) . chr($this->compression_method) . chr($this->filter_method) . chr($this->interlace_method); }elseif(!strcmp('IDAT', $type)){ $chunk['type'] = 'IDAT'; $scanlines = array_values($this->pixelData); $scanlines = array_map('scanser', $scanlines); $scanlines = gzcompress(implode('', $scanlines)); $chunk['data'] = $scanlines; }elseif(!strcmp('IEND', $type)){ $chunk['type'] = 'IEND'; } $chunk['length'] = writableInt(strlen($chunk['data'])); $chunk['crc'] = writableInt(crc($chunk['type'] . $chunk['data'])); return implode('', $chunk); } function resultantImage(){ return $this->signature . $this->chunk('IHDR') . $this->chunk('IDAT') . $this->chunk('IEND'); } function pixel($x, $y, $r = 0, $g = 0, $b = 0, $a = 255){ $this->pixelData[$y][$x] = chr($r) . chr($g) . chr($b) . chr($a); } /* Makes use of the Bresenham line algorithm http://en.wikipedia.org/wiki/Bresenham's_line_algorithm */ function line($x0, $y0, $x1, $y1, $r = 0, $g = 0, $b = 0, $a = 255){ $steep = abs($y1 - $y0) > abs($x1 - $x0); if($steep){ $temp = $x0; $x0 = $y0; $y0 = $temp; $temp = $x1; $x1 = $y1; $y1 = $temp; } if($x0 > $x1){ $temp = $x0; $x0 = $x1; $x1 = $temp; $temp = $y0; $y0 = $y1; $y1 = $temp; } $deltax = $x1 - $x0; $deltay = abs($y1 - $y0); $error = $deltax / 2; $y = $y0; if($y0 < $y1) $ystep = 1; else $ystep = -1; for($x = $x0; $x <= $x1; $x++){ if($steep) $this->pixelData[$x][$y] = chr($r) . chr($g) . chr($b) . chr($a); else $this->pixelData[$y][$x] = chr($r) . chr($g) . chr($b) . chr($a); $error = $error - $deltay; if($error < 0){ $y += $ystep; $error += $deltax; } } } } function scanser($value){ return chr(0) . implode('', $value); } function writableInt($number){ $output = ''; for($i = 0; $i > -32; $i -= 8){ $output .= chr(bitRotate32($number, $i) & 0x000000ff); } return strrev($output); } // Negatives rotate right, positives rotate left // Made by Nina Cording from the php.net site function bitRotate32($value, $amount){ if ($amount > 0){ $amount %= 32; $value = ($value << $amount) | ($value >> (32 - $amount)); } elseif($amount < 0){ $amount = (-1 * $amount) % 32; $value = ($value >> $amount) | ($value << (32 - $amount)); } return $value; } ?> crcpng.php
php
<?php $crc_table = array(); $crc_table_computed = false; function make_crc_table(){ global $crc_table, $crc_table_computed; for($n = 0; $n < 256; $n++){ $c = $n; for($k = 0; $k < 8; $k++){ if($c & 1 === 1) $c = 0xedb88320 ^ (($c >> 1) & 0xefffffff); else $c = ($c >> 1) & 0xefffffff; } $crc_table[] = $c; } $crc_table_computed = true; } function update_crc($crc, $buf){ global $crc_table, $crc_table_computed; $c = $crc; if(!$crc_table_computed) make_crc_table(); $len = strlen($buf); for($n = 0; $n < $len; $n++){ $c = $crc_table[($c ^ ord(substr($buf, $n, 1))) & 0x000000ff] ^ (($c >> 8) & 0x00ffffff); } return $c; } function crc($buf){ return update_crc(0xffffffff, $buf) ^ 0xffffffff; } ?> The output it produces on Opera is basically a small image that says DREAM.IN.CODE on it. I'm including a screencap. Thank you for any input you can provide.
Attached image(s)
grimpirate
16 Sep, 2008 - 10:03 PM
D.I.C Head
Joined: 3 Aug, 2006
Posts: 187
Thanked 5 times
Dream Kudos: 375
My Contributions
I figured out the problem. It was line 143 of the
png.php file. The checksum that they perform can in fact be determined with the php function
crc32 . I though the implementation I had coded did the exact same thing as that listed in the specifications, but apparently it is erroneous. So basically the line SHOULD become the following:
CODE
$chunk['crc'] = writableInt(crc32($chunk['type'] . $chunk['data']));
This change eliminates the need for the
crcpng.php file. Now your png images should open up anywhere Mocker. Only thing left now is to figure out how to code zlib. T_T
grimpirate
17 Sep, 2008 - 12:16 AM
D.I.C Head
Joined: 3 Aug, 2006
Posts: 187
Thanked 5 times
Dream Kudos: 375
My Contributions
To all those that would defy me, BEHOLD MY GLORY!
php
<?php define('DEF_BLK_SIZE', 65531); define('ADLER_BASE', 65521); header("Content-type: image/png"); $png = new PNG(69, 5); $png->line(0, 0, 3, 0); $png->line(6, 0, 9, 0); $png->line(12, 0, 16, 0); $png->line(19, 0, 21, 0); $png->line(24, 0, 28, 0); $png->line(32, 0, 36, 0); $png->pixel(38, 0); $png->pixel(42, 0); $png->line(46, 0, 50, 0); $png->line(52, 0, 56, 0); $png->line(58, 0, 61, 0); $png->line(64, 0, 68, 0); $png->pixel(0, 1); $png->pixel(4, 1); $png->pixel(6, 1); $png->pixel(10, 1); $png->pixel(12, 1); $png->pixel(18, 1); $png->pixel(22, 1); $png->pixel(24, 1); $png->pixel(26, 1); $png->pixel(28, 1); $png->pixel(34, 1); $png->pixel(38, 1); $png->pixel(39, 1); $png->pixel(42, 1); $png->pixel(46, 1); $png->pixel(52, 1); $png->pixel(56, 1); $png->pixel(58, 1); $png->pixel(62, 1); $png->pixel(64, 1); $png->pixel(0, 2); $png->pixel(4, 2); $png->line(6, 2, 10, 2); $png->line(12, 2, 15, 2); $png->pixel(18, 2); $png->pixel(22, 2); $png->pixel(24, 2); $png->pixel(26, 2); $png->pixel(28, 2); $png->pixel(34, 2); $png->pixel(38, 2); $png->pixel(40, 2); $png->pixel(42, 2); $png->pixel(46, 2); $png->pixel(52, 2); $png->pixel(56, 2); $png->pixel(58, 2); $png->pixel(62, 2); $png->line(64, 2, 67, 2); $png->pixel(0, 3); $png->pixel(4, 3); $png->pixel(6, 3); $png->pixel(8, 3); $png->pixel(12, 3); $png->line(18, 3, 22, 3); $png->pixel(24, 3); $png->pixel(26, 3); $png->pixel(28, 3); $png->pixel(34, 3); $png->pixel(38, 3); $png->pixel(41, 3); $png->pixel(42, 3); $png->pixel(46, 3); $png->pixel(52, 3); $png->pixel(56, 3); $png->pixel(58, 3); $png->pixel(62, 3); $png->pixel(64, 3); $png->line(0, 4, 3, 4); $png->pixel(6, 4); $png->pixel(9, 4); $png->pixel(10, 4); $png->line(12, 4, 16, 4); $png->pixel(18, 4); $png->pixel(22, 4); $png->pixel(24, 4); $png->pixel(28, 4); $png->pixel(30, 4); $png->line(32, 4, 36, 4); $png->pixel(38, 4); $png->pixel(42, 4); $png->pixel(44, 4); $png->line(46, 4, 50, 4); $png->line(52, 4, 56, 4); $png->line(58, 4, 61, 4); $png->line(64, 4, 68, 4); echo $png->resultantImage(); class PNG { var $signature; // 8 bytes var $width; // 4 bytes var $height; // 4 bytes var $bit_depth; // 1 byte var $colour_type; // 1 byte var $compression_method; // 1 byte var $filter_method; // 1 byte var $interlace_method; // 1 byte var $pixelData; // n bytes function PNG($width, $height, $bit_depth = 8, $colour_type = 6, $compression_method = 0, $filter_method = 0, $interlace_method = 0){ $this->signature = chr(137) . 'PNG' . chr(13) . chr(10) . chr(26) . chr(10); $this->width = $width; $this->height = $height; $this->bit_depth = $bit_depth; $this->colour_type = $colour_type; $this->compression_method = $compression_method; $this->filter_method = $filter_method; $this->interlace_method = $interlace_method; for($i = 0; $i < $height; $i++){ $this->pixelData[] = array(); for($j = 0; $j < $width; $j++){ $this->pixelData[$i][] = chr(255) . chr(255) . chr(255) . chr(0); } } } function chunk($type){ $chunk = array( 'length' => null, // 4 bytes 'type' => null, // 4 bytes 'data' => null, // n bytes 'crc' => null // 4 bytes ); if(!strcmp('IHDR', $type)){ $chunk['type'] = 'IHDR'; $chunk['data'] = writableInt($this->width) . writableInt($this->height) . chr($this->bit_depth) . chr($this->colour_type) . chr($this->compression_method) . chr($this->filter_method) . chr($this->interlace_method); }elseif(!strcmp('IDAT', $type)){ $chunk['type'] = 'IDAT'; $scanlines = array_values($this->pixelData); $scanlines = array_map('scanser', $scanlines); //$scanlines = gzcompress(implode('', $scanlines)); $scanlines = defstr(implode('', $scanlines)); $chunk['data'] = $scanlines; }elseif(!strcmp('IEND', $type)){ $chunk['type'] = 'IEND'; } $chunk['length'] = writableInt(strlen($chunk['data'])); $chunk['crc'] = writableInt(crc32($chunk['type'] . $chunk['data'])); return implode('', $chunk); } function resultantImage(){ return $this->signature . $this->chunk('IHDR') . $this->chunk('IDAT') . $this->chunk('IEND'); } function pixel($x, $y, $r = 0, $g = 0, $b = 0, $a = 255){ $this->pixelData[$y][$x] = chr($r) . chr($g) . chr($b) . chr($a); } /* Makes use of the Bresenham line algorithm http://en.wikipedia.org/wiki/Bresenham's_line_algorithm */ function line($x0, $y0, $x1, $y1, $r = 0, $g = 0, $b = 0, $a = 255){ $steep = abs($y1 - $y0) > abs($x1 - $x0); if($steep){ $temp = $x0; $x0 = $y0; $y0 = $temp; $temp = $x1; $x1 = $y1; $y1 = $temp; } if($x0 > $x1){ $temp = $x0; $x0 = $x1; $x1 = $temp; $temp = $y0; $y0 = $y1; $y1 = $temp; } $deltax = $x1 - $x0; $deltay = abs($y1 - $y0); $error = $deltax / 2; $y = $y0; if($y0 < $y1) $ystep = 1; else $ystep = -1; for($x = $x0; $x <= $x1; $x++){ if($steep) $this->pixelData[$x][$y] = chr($r) . chr($g) . chr($b) . chr($a); else $this->pixelData[$y][$x] = chr($r) . chr($g) . chr($b) . chr($a); $error = $error - $deltay; if($error < 0){ $y += $ystep; $error += $deltax; } } } } function defstr($string){ $adler = writableInt(adler32($string)); $output = chr(120) . chr(1); $len = strlen($string); $div = floor($len / DEF_BLK_SIZE); if($div != 0){ for($i = 0; $i < $div; $i++){ $output .= chr(0); $output .= strrev(substr(writableInt(DEF_BLK_SIZE), 2)); $output .= strrev(substr(writableInt(DEF_BLK_SIZE ^ 0xffffffff), 2)); $output .= substr($string, 0, DEF_BLK_SIZE); $string = substr($string, DEF_BLK_SIZE); } } $len = strlen($string); $output .= chr(1); $output .= strrev(substr(writableInt($len), 2)); $output .= strrev(substr(writableInt($len ^ 0xffffffff), 2)); $output .= $string; $output .= $adler; return $output; } function adler32($buf){ return update_adler32(1, $buf); } function update_adler32($adler, $buf){ $s1 = $adler & 0x0000ffff; $s2 = ($adler >> 16) & 0x0000ffff; $len = strlen($buf); for($n = 0; $n < $len; $n++){ $s1 = ($s1 + ord(substr($buf, $n, 1))) % ADLER_BASE; $s2 = ($s2 + $s1) % ADLER_BASE; } return ($s2 << 16) + $s1; } function scanser($value){ return chr(0) . implode('', $value); } function writableInt($number){ $output = ''; for($i = 0; $i > -32; $i -= 8){ $output .= chr(bitRotate32($number, $i) & 0x000000ff); } return strrev($output); } // Negatives rotate right, positives rotate left // Made by Nina Cording from the php.net site function bitRotate32($value, $amount){ if ($amount > 0){ $amount %= 32; $value = ($value << $amount) | ($value >> (32 - $amount)); } elseif($amount < 0){ $amount = (-1 * $amount) % 32; $value = ($value >> $amount) | ($value << (32 - $amount)); } return $value; } ?> DREAM.IN.CODE generated from the ground up without any outside libraries! BWAHAHAHA! NEXT THE WORLD!
Programming
Web Development
Reference Sheets
Bye Bye Ads
Free DIC T-Shirt
Related Sites
Monthly Drawing
Partners
Top Contributors
Top 10 Kudos This Month