首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

純 PHP 實現 PNG 圖片生成:無需 GD 库的當前時間圖像輸出

     編輯:PHP 綜合知識

核心概念:手工構造 PNG 二進制流

一般開發者習慣使用 GD 或 ImageMagick 生成動態圖片。但若伺服器環境受限(無法安裝擴展),或為了理解圖片格式底層結構,純 PHP 手工組裝 PNG 二進制資料流 是極佳的學習與備選方案。本文解析一個無需任何擴展、僅用核心函數即可輸出「當前時間」PNG 圖片的經典範例。

PNG 檔案格式快速回顧

PNG 採用 塊式結構,主要包含:

  1. 檔案簽名(8 bytes):89 50 4E 47 0D 0A 1A 0A
  2. IHDR 區塊:圖片寬、高、位深、色彩類型、壓縮/濾鏡/隔行掃描方法
  3. IDAT 區塊:經 zlib 壓縮的像素資料(每行前綴濾鏡型別 byte)
  4. IEND 區塊:結束標記

每個區塊格式:長度(4B) + 類型(4B) + 資料 + CRC32(4B)。

程式碼架構解析

1. 像素畫布初始化與漸層填充

$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 像素畫布,填入對角線漸層背景。

2. 七段式數字繪製邏輯

$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))。

3. CRC32 與 Adler-32 校驗碼純 PHP 實現

// 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 擴展,展示校驗演算法核心邏輯。

4. 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()。

完整輸出流程

  1. 建立畫布、填充背景
  2. 取得當前時間(時/分/秒),繪製六位數字與分隔點
  3. 建立 CRC32 查表
  4. 組裝 PNG 簽名 + IHDR + IDAT(含 zlib 封裝)+ IEND
  5. 輸出 Content-Type: image/png 標頭並 echo $result

前端調用方式

<img src="timeimg.php" alt="Current Time">

瀏覽器將其視為普通圖片資源,實則由 PHP 動態生成二進制流。

優缺點評估與適用場景

優點缺點
零依賴,極致可移植程式碼冗長、維護困難
深入理解 PNG/zlib/CRC/Adler 規範無抗鋸齒、字型、透明度等高階功能
嵌入式/受限環境可用效能遠低於 C 實現的 GD

建議:生產環境優先使用 GD/ImageMagick;本範例適合教學、離線環境、或作為輕量級驗證碼/狀態圖示的無依賴備選方案。

現代改良方向

  • 若 PHP 7.2+ 可用 hash('crc32b', $data, true) 簡化 CRC 計算。
  • 若需簡易文字繪製,可預先將字型光柵化為陣列內嵌程式碼。
  • 輸出前加入 header('Cache-Control: no-store, max-age=0'); 避免快取導致時間不更新。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved