Retour

Building PNG Images

2008-09-18 10:26:31 (ID: 226, Parent: 0, Type: post)

Did you ever try to build a png image (with a programming language, not an image editor)?  A lot of code sample are available on the internet.  But most if not all are using libpng or some high level libraries like gd.

But what happend if you can’t install libraries on the system where you’re working?  Ever thing about building an image from scratch?  Here is what I do in PHP.

This isn’t the most performant code, but at least it generate a valid PNG image without any non standard libraries.   (Some one could say that zlib or crc are php external libs.. but I haven’t see any php distribution whitout them in a while!)

<?php
/*
* Title: PNG Image Generation
* Author: Jean-Luc Cyr
* Date: 2008-09-17
* License: GNU GPL2
* Description: Generate a simple PNG image
* directly in PHP without using external libs
* like GD.
*/
 
header("content-type: image/png");
 
function long2string($long)
{
$string = chr(($long&0xFF000000)>>24).
chr(($long&0xFF0000)>>16).
chr(($long&0xFF00)>>8).
chr(($long&0xFF)>>0);
return $string;
} // long2string()
function build_png($matrix, $w, $h)
{
////////////////////////////////////////////////////////////////
//PNG Header
$image = chr(0x89).chr(0x50).chr(0x4E).chr(0x47);
$image .= chr(0x0D).chr(0x0A).chr(0x1A).chr(0x0A);
 
////////////////////////////////////////////////////////////////
//Header Chunk
 
//Chunk type
$chunk = "IHDR";
//Chunk data
//Width
$data = long2string($w);
//Height
$data .= long2string($h);
//Depth
$data .= chr(8); //Bits per sample
//Color Type
$data .= chr(2); //RGB
//Compression method
$data .= chr(0);
//Filter method
$data .= chr(0);
//Interlaced method
$data .= chr(0);
 
$crc = crc32($chunk.$data);
//Add length at start
$chunk = long2string(strlen($data)).$chunk.$data;
//Add CRC at the end
//Dump chunk
$chunk = $chunk.long2string($crc);
$image .= $chunk;
 
////////////////////////////////////////////////////////////////
//Data Chunk
 
//Chunk type
$chunk = "IDAT";
//Data (2x2 rgb 8bits)
$s = 3; //samples per pixels
#$matrix  ="\0\0\0\0\0\0\0\0\0";
#$matrix .="\0\0\0\0\0\0\0\0\0";
#$matrix .="\0\0\0\0\0\0\0\0\0";
// No filter so add 0 to beginning of each scan line
$datas = '';
for($c=0; $c<$h; $c++)
$datas .= "\0". substr($matrix,$c*($w*$s),($w*$s));
// Compress Data
#$zdata = gzencode($data,9,FORCE_DEFLATE);
#$zdata = gzdeflate($data,0);
$zdata = gzcompress($datas,0);
// Calculate CRC
$crc = crc32($chunk.$zdata);
// Add length at start
$l = strlen($zdata);
$chunk = long2string($l).$chunk.$zdata;
// Add CRC at the end
$chunk = $chunk.long2string($crc);
$image .= $chunk;
 
////////////////////////////////////////////////////////////////
//End Chunk
 
// Chunk type
$chunk = "IEND";
// Data
$data = "";
// Calculate CRC
$crc = crc32($chunk);
// Add length at start
$chunk = long2string(strlen($data)).$chunk.$data;
// Add CRC at the end
$chunk = $chunk.long2string($crc);
$image .= $chunk;
 
// Send out the image
echo $image;die();
} // build_png()
////////////////////////////////////////////////////////////////
// Demo code
 
// Build a simple image matrix
// 256 x 256 x 8rgb
 
$w=256; // width
$h=256; // height
$s=3;   // 3 x 8 bits samples per pixel (8bits rgb)
for($x=0; $x<$h; $x++)
for($y=0; $y<$w; $y++)
//    for($z=0; $z<$s; $z++) //Ordered R G B
$matrix .=
chr( ( (($y/64)<1) && (($y/64)>0) )?$x:0 ). // R
chr( ( (($y/64)<2) && (($y/64)>1) )?$x:0 ). // G
chr( ( (($y/64)<3) && (($y/64)>2) )?$x:0 ); // B
 
build_png($matrix,$w,$h);
die();
 
////////////////////////////////////////////////////////////////
// Hex dump image for debugging
 
for ($x=0; $x<strlen($image); $x++) {
printf("%02X ",ord($image[$x]));
if ((($x+1)%16)==0)
printf("<br/>");
}