画像処理の分野では、PNG(ポータブルネットワークグラフィックス)は、広く使用されているロスレス圧縮画像形式です。そのファイル構造には、それぞれが特定の画像またはメタデータ情報を含む複数の「チャンク」を含む明確な仕様があります。これらの構造を理解することは、カスタム画像処理ツールの開発に役立つだけでなく、バイナリデータ操作とプロトコル設計の学習にも大きなメリットがあります。
この記事では、PHPのpack()およびunpack()機能を介してPNGファイルのヘッダーを手動で解析し、その構造を分析します。 PHPはWebベースの言語ですが、バイナリデータの処理にも優れた能力があります。
法的PNGファイルは、8バイトの固定署名から開始する必要があります。
89 50 4E 47 0D 0A 1A 0A
次は1つ以上のブロック(チャンク)で、それぞれが次の部分で構成されています。
長さ(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バイト)を読むことを意味します
a4typeとは、型の固定長(4バイト)のASCII文字列を読むことを意味します。
代わりに、 pack()は変数をバイナリ形式にパッケージ化できます。たとえば、PNGファイルヘッダーをパッケージ化する場合、以下を使用できます。
$signature = pack("C8", 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A);
これは、PNGファイルの生成をカスタマイズするときに非常に便利です。
後続のPNGブロック(IDAT、IENDなどなど)を解析し続けるには、次のように各ブロックをループするだけです。
8バイトを読む:4バイトの長さ + 4バイトタイプ
長さに応じて対応するデータフィールドを読み取ります
4バイトCRCチェックをスキップします
Iendが遭遇するまで次のブロックを読み続けます
この分析方法は、透明度(TRNS)、カラーパレット(PLTE)、その他のブロックなど、より複雑なPNG特性にも適用できます。
PHPのunpack()およびpack()関数を使用することにより、PNGファイルを低レベルで簡単に解析し、それらの根底にある構造を理解できます。このスキルは、画像形式の詳細な理解、カスタマイズされた画像処理ツールの作成、または関連するセキュリティツールの開発に非常に役立ちます。これらのスキルを習得することで、毎日のPHP開発により快適になります。