在圖像處理領域,PNG(Portable Network Graphics)是一種廣泛使用的無損壓縮圖像格式。其文件結構有著明確的規範,包含多個“塊”(Chunk),每個塊都包含了特定的圖像或元數據信息。理解這些結構不僅有助於開發自定義圖像處理工具,也對於學習二進制數據操作與協議設計大有裨益。
本文將通過PHP 的pack()和unpack()函數,手動解析PNG 文件的頭部,並分析其結構。 PHP 儘管是一門以Web 為主的語言,但在處理二進制數據方面也有不俗的能力。
一個合法的PNG 文件,開頭必須是8 個字節的固定簽名:
89 50 4E 47 0D 0A 1A 0A
接下來是一個或多個塊(Chunk),每個塊由以下部分組成:
長度(4字節) – 數據部分的長度
塊類型(4字節) – 比如IHDR、IDAT、IEND 等
塊數據(可變)
CRC 校驗(4字節)
以下示例代碼將讀取一個PNG 文件的前若干字節,提取文件頭和第一個塊(通常是IHDR)。
<?php
$filename = 'https://m66.net/sample.png';
// 讀取文件的前 33 位元組:8 位元組簽名 + 4+4+13+4(IHDR 塊總長度)
$data = file_get_contents($filename, false, null, 0, 33);
if ($data === false || strlen($data) < 33) {
die("無法讀取 PNG 文件或文件過小。");
}
// 解析 PNG 簽名
$signature = substr($data, 0, 8);
$expectedSignature = "\x89PNG\r\n\x1a\n";
if ($signature !== $expectedSignature) {
die("這不是一個有效的 PNG 文件。");
}
echo "PNG 簽名验证成功。\n";
// 解析第一個 Chunk(應為 IHDR)
$chunkData = substr($data, 8);
// 使用 unpack 提取字段
$unpacked = unpack("Nlength/A4type", substr($chunkData, 0, 8));
$length = $unpacked['length'];
$type = $unpacked['type'];
echo "第一個塊類型: $type\n";
echo "數據長度: $length\n";
// 提取 IHDR 數據
$ihdrData = substr($chunkData, 8, 13);
$ihdr = unpack("Nwidth/Nheight/CbitDepth/CcolorType/Ccompression/Cfilter/Cinterlace", $ihdrData);
echo "寬度: {$ihdr['width']} px\n";
echo "高度: {$ihdr['height']} px\n";
echo "位深: {$ihdr['bitDepth']}\n";
echo "顏色類型: {$ihdr['colorType']}\n";
echo "壓縮方法: {$ihdr['compression']}\n";
echo "濾鏡方法: {$ihdr['filter']}\n";
echo "隔行掃描: {$ihdr['interlace']}\n";
?>
unpack()用於將二進制數據解析為PHP 數組。它使用格式字符串描述每個字段的類型和順序。例如:
unpack("Nlength/A4type", $binary);
Nlength表示讀取一個大端無符號長整型(4字節),命名為length
A4type表示讀取一個固定長度(4字節)的ASCII 字符串,命名為type
相反, pack()可將變量打包為二進制格式。比如打包PNG 文件頭可以使用:
$signature = pack("C8", 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A);
這在自定義生成PNG 文件時非常有用。
若要繼續解析後續的PNG 塊(如IDAT、IEND 等),只需按如下邏輯循環讀取每個塊:
讀取8 字節:4 字節長度+ 4 字節類型
根據長度讀取對應的數據字段
跳過4 字節CRC 校驗
繼續讀取下一個塊,直到遇到IEND
這種解析方法也可以應用到更複雜的PNG 特性,如透明度(tRNS)、調色板(PLTE)等塊。
通過使用PHP 的unpack()和pack()函數,我們可以輕鬆地以低層級的方式解析PNG 文件,理解其底層結構。這種技能對深入了解圖像格式、編寫定製圖像處理工具或開發相關安全工具都是非常有用的。掌握這些技巧,也能讓你在日常PHP 開發中更加得心應手。