一般開發者習慣使用 GD 或 ImageMagick 生成動態圖片。但若伺服器環境受限(無法安裝擴展),或為了理解圖片格式底層結構,純 PHP 手工組裝 PNG 二進制資料流 是極佳的學習與備選方案。本文解析一個無需任何擴展、僅用核心函數即可輸出「當前時間」PNG 圖片的經典範例。
PNG 採用 塊式結構,主要包含:
89 50 4E 47 0D 0A 1A 0A每個區塊格式:長度(4B) + 類型(4B) + 資料 + CRC32(4B)。
$sx = 80; $sy = 21;
$pixels = '';
for ($y = 0; $y < $sy; $y++) {
for ($x = 0; $x < $sx; $x++) {
$r = 100 / $sx * $x + 155;
$g = 100 / $sy * $y + 155;
$b = 255 - (100 / ($sx + $sy) * ($x + $y));
$pixels .= chr($r) . chr($g) . chr($b); // RGB 三通道
}
}
建立 80×21 像素畫布,填入對角線漸層背景。
$digits = [95, 5, 118, 117, 45, 121, 123, 69, 127, 125]; // 0-9 七段編碼
$lines = [1,1,1,2, 0,1,0,2, 1,0,1,1, 0,0,0,1, 0,2,1,2, 0,1,1,1, 0,0,1,0]; // 線段座標
function draw_digit($x, $y, $digit) {
global $sx, $pixels, $digits, $lines;
$seg = $digits[$digit];
$m = 8; // 放大倍率
for ($b = 1, $i = 0; $i < 7; $i++, $b <<= 1) {
if (($b & $seg) == $b) { // 該段需點亮
$j = $i * 4;
$x0 = $lines[$j] * $m + $x;
$y0 = $lines[$j+1] * $m + $y;
$x1 = $lines[$j+2] * $m + $x;
$y1 = $lines[$j+3] * $m + $y;
// 填充像素(橫向或縱向線段)
if ($x0 == $x1) { /* 縱線 */ }
else { /* 橫線 */ }
}
}
}
利用位元遮罩判斷七段式數字各段亮滅,按座標在像素陣列中寫入黑色(chr(0))。
// CRC32 表建立(標準多項式 0xEDB88320)
$crc_table = [];
for ($n = 0; $n < 256; $n++) {
$c = $n;
for ($k = 0; $k < 8; $k++) {
$c = ($c & 1) ? (0xEDB88320 ^ ($c >> 1)) : ($c >> 1);
}
$crc_table[$n] = $c;
}
// Adler-32(zlib 非壓縮區塊需求)
$s1 = 1; $s2 = 0;
for ($i = $start; $i < strlen($data); $i++) {
$s1 = ($s1 + ord($data[$i])) % 65521;
$s2 = ($s2 + $s1) % 65521;
}
$adler = ($s2 << 16) | $s1;
完全不依賴 hash() 或 zlib 擴展,展示校驗演算法核心邏輯。
$len = ($sx * 3 + 1) * $sy; // 每行 1 byte filter + 3*寬度
$data = chr(0x78) . chr(0x01) . chr(1) . // zlib header: CM=8, CINFO=7, FCHECK=1
pack('v', $len) . pack('v', ~$len & 0xFFFF) . // LEN + NLEN
$raw_pixel_data . // 未壓縮像素資料
pack('N', $adler); // Adler-32
利用 RFC 1950/1951 定義的「無壓縮區塊」格式,繞過需 zlib 擴展的 gzcompress()。
Content-Type: image/png 標頭並 echo $result<img src="timeimg.php" alt="Current Time">
瀏覽器將其視為普通圖片資源,實則由 PHP 動態生成二進制流。
| 優點 | 缺點 |
|---|---|
| 零依賴,極致可移植 | 程式碼冗長、維護困難 |
| 深入理解 PNG/zlib/CRC/Adler 規範 | 無抗鋸齒、字型、透明度等高階功能 |
| 嵌入式/受限環境可用 | 效能遠低於 C 實現的 GD |
建議:生產環境優先使用 GD/ImageMagick;本範例適合教學、離線環境、或作為輕量級驗證碼/狀態圖示的無依賴備選方案。
hash('crc32b', $data, true) 簡化 CRC 計算。header('Cache-Control: no-store, max-age=0'); 避免快取導致時間不更新。