當前位置: 首頁> 最新文章列表> 解析PNG 文件頭:pack() + 文件結構分析

解析PNG 文件頭:pack() + 文件結構分析

M66 2025-05-28

在圖像處理領域,PNG(Portable Network Graphics)是一種廣泛使用的無損壓縮圖像格式。其文件結構有著明確的規範,包含多個“塊”(Chunk),每個塊都包含了特定的圖像或元數據信息。理解這些結構不僅有助於開發自定義圖像處理工具,也對於學習二進制數據操作與協議設計大有裨益。

本文將通過PHP 的pack()unpack()函數,手動解析PNG 文件的頭部,並分析其結構。 PHP 儘管是一門以Web 為主的語言,但在處理二進制數據方面也有不俗的能力。

一、PNG 文件結構概覽

一個合法的PNG 文件,開頭必須是8 個字節的固定簽名:

 89 50 4E 47 0D 0A 1A 0A

接下來是一個或多個塊(Chunk),每個塊由以下部分組成:

  • 長度(4字節) – 數據部分的長度

  • 塊類型(4字節) – 比如IHDR、IDAT、IEND 等

  • 塊數據(可變)

  • CRC 校驗(4字節)

二、使用PHP 解析PNG 文件頭

以下示例代碼將讀取一個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()

unpack()用於將二進制數據解析為PHP 數組。它使用格式字符串描述每個字段的類型和順序。例如:

 unpack("Nlength/A4type", $binary);
  • Nlength表示讀取一個大端無符號長整型(4字節),命名為length

  • A4type表示讀取一個固定長度(4字節)的ASCII 字符串,命名為type

pack()

相反, pack()可將變量打包為二進制格式。比如打包PNG 文件頭可以使用:

 $signature = pack("C8", 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A);

這在自定義生成PNG 文件時非常有用。

四、進階解析

若要繼續解析後續的PNG 塊(如IDAT、IEND 等),只需按如下邏輯循環讀取每個塊:

  1. 讀取8 字節:4 字節長度+ 4 字節類型

  2. 根據長度讀取對應的數據字段

  3. 跳過4 字節CRC 校驗

  4. 繼續讀取下一個塊,直到遇到IEND

這種解析方法也可以應用到更複雜的PNG 特性,如透明度(tRNS)、調色板(PLTE)等塊。

五、結語

通過使用PHP 的unpack()pack()函數,我們可以輕鬆地以低層級的方式解析PNG 文件,理解其底層結構。這種技能對深入了解圖像格式、編寫定製圖像處理工具或開發相關安全工具都是非常有用的。掌握這些技巧,也能讓你在日常PHP 開發中更加得心應手。