In the field of image processing, PNG (Portable Network Graphics) is a widely used lossless compressed image format. Its file structure has clear specifications, including multiple "chunks", each containing specific image or metadata information. Understanding these structures not only helps to develop custom image processing tools, but also can be of great benefit to learning binary data operations and protocol design.
This article will manually parse the header of the PNG file through PHP's pack() and unpack() functions and analyze its structure. Although PHP is a web-based language, it also has excellent abilities in processing binary data.
A legal PNG file must start with an 8 byte fixed signature:
89 50 4E 47 0D 0A 1A 0A
Next is one or more blocks (Chunk), each of which consists of the following parts:
Length (4 bytes) – length of the data part
Block type (4 bytes) – such as IHDR, IDAT, IEND, etc.
Block data (variable)
CRC Verification (4 bytes)
The following example code will read the first several bytes of a PNG file, extracting the file header and the first block (usually IHDR).
<?php
$filename = 'https://m66.net/sample.png';
// Before reading the file 33 byte:8 bytesign + 4+4+13+4(IHDR Total block length)
$data = file_get_contents($filename, false, null, 0, 33);
if ($data === false || strlen($data) < 33) {
die("Unable to read PNG File or file too small。");
}
// Analysis PNG sign
$signature = substr($data, 0, 8);
$expectedSignature = "\x89PNG\r\n\x1a\n";
if ($signature !== $expectedSignature) {
die("This is not a valid one PNG document。");
}
echo "PNG sign验证成功。\n";
// Analysis第一个 Chunk(Should be IHDR)
$chunkData = substr($data, 8);
// use unpack Extract fields
$unpacked = unpack("Nlength/A4type", substr($chunkData, 0, 8));
$length = $unpacked['length'];
$type = $unpacked['type'];
echo "The first block type: $type\n";
echo "Data length: $length\n";
// extract IHDR data
$ihdrData = substr($chunkData, 8, 13);
$ihdr = unpack("Nwidth/Nheight/CbitDepth/CcolorType/Ccompression/Cfilter/Cinterlace", $ihdrData);
echo "width: {$ihdr['width']} px\n";
echo "high: {$ihdr['height']} px\n";
echo "Deep: {$ihdr['bitDepth']}\n";
echo "Color Type: {$ihdr['colorType']}\n";
echo "Compression method: {$ihdr['compression']}\n";
echo "Filter method: {$ihdr['filter']}\n";
echo "Interlaced scan: {$ihdr['interlace']}\n";
?>
unpack() is used to parse binary data into PHP arrays. It uses a format string to describe the type and order of each field. For example:
unpack("Nlength/A4type", $binary);
Nlength means reading a large-endian unsigned long integer (4 bytes), named length
A4type means reading an ASCII string of fixed length (4 bytes) named type
Instead, pack() can package variables into binary format. For example, when packaging PNG file headers, you can use:
$signature = pack("C8", 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A);
This is very useful when customizing the generation of PNG files.
To continue parsing subsequent PNG blocks (such as IDAT, IEND, etc.), just loop through each block as follows:
Read 8 bytes: 4 byte length + 4 byte type
Read the corresponding data field according to the length
Skip 4 byte CRC check
Continue to read the next block until IEND is encountered
This analysis method can also be applied to more complex PNG characteristics, such as transparency (tRNS), color palette (PLTE), and other blocks.
By using PHP's unpack() and pack() functions, we can easily parse PNG files in a low-level way and understand their underlying structure. This skill is very useful for in-depth understanding of image formats, writing customized image processing tools, or developing related security tools. Mastering these skills can also make you more comfortable in daily PHP development.