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

PHP Imagick 實現 PDF 首頁轉 PNG 縮略圖完整方案

     編輯:PHP 綜合知識

核心需求

服務端自動將上傳的 PDF 文檔第一頁(或指定頁)轉為 PNG 縮略圖,用於列表預覽、文檔管理系統等場景。

前置條件

  • 安裝 ImageMagick 庫:apt-get install imagemagick libmagickwand-dev (Ubuntu/Debian)
  • 安裝 PHP Imagick 擴展:pecl install imagick,啟用 extension=imagick.so
  • ImageMagick 需配置 policy.xml 允許讀取 PDF(默認近期版本限制 PDF 讀取):
    /etc/ImageMagick-6/policy.xml 或 /etc/ImageMagick-7/policy.xml 中修改:
    <policy domain="coder" rights="read|write" pattern="PDF" />

通用轉換函數

<?php
/**
 * PDF 指定頁轉 PNG 縮略圖
 * @param string $pdfPath PDF 文件絕對路徑
 * @param string $saveDir 輸出目錄(自動創建)
 * @param int $page 頁碼(0-based:0=第一頁,-1=所有頁)
 * @param int $thumbWidth 縮略圖寬度
 * @param int $thumbHeight 縮略圖高度
 * @param int $resolution 渲染分辨率 DPI(越高越清晰,越慢)
 * @param int $quality JPEG/PNG 質量 1-100
 * @return string|array|false 成功返回文件路徑(單頁)或路徑數組(多頁),失敗 false
 */
function pdfToPngThumb(
    string $pdfPath,
    string $saveDir,
    int $page = 0,
    int $thumbWidth = 200,
    int $thumbHeight = 150,
    int $resolution = 150,
    int $quality = 85
) {
    if (!extension_loaded('imagick')) {
        error_log('Imagick 擴展未加載');
        return false;
    }
    if (!file_exists($pdfPath)) {
        error_log("PDF 文件不存在: $pdfPath");
        return false;
    }
    if (!is_dir($saveDir) && !mkdir($saveDir, 0755, true)) {
        error_log("無法創建目錄: $saveDir");
        return false;
    }

    try {
        $im = new Imagick();
        $im->setResolution($resolution, $resolution); // 必須在 readImage 前設置
        $im->setCompressionQuality($quality);

        // 讀取指定頁:$pdfPath"[0]" 表示第一頁
        $im->readImage($pdfPath . "[$page]");

        // 縮放:保持比例,使用最佳濾波器
        $im->thumbnailImage($thumbWidth, $thumbHeight, true, true);

        // 設置輸出格式為 PNG
        $im->setImageFormat('png');

        // 生成唯一文件名
        $baseName = pathinfo($pdfPath, PATHINFO_FILENAME);
        $timestamp = time();
        $rand = mt_rand(1000, 9999);

        if ($page === -1) {
            // 所有頁:每頁生成一個文件
            $paths = [];
            foreach ($im as $i => $frame) {
                $frame->setImageFormat('png');
                $fileName = "{$baseName}_page{$i}_{$timestamp}_{$rand}.png";
                $filePath = $saveDir . DIRECTORY_SEPARATOR . $fileName;
                if ($frame->writeImage($filePath)) {
                    $paths[] = $filePath;
                }
            }
            return $paths ?: false;
        } else {
            // 單頁
            $fileName = "{$baseName}_thumb_{$timestamp}_{$rand}.png";
            $filePath = $saveDir . DIRECTORY_SEPARATOR . $fileName;
            if ($im->writeImage($filePath)) {
                return $filePath;
            }
            return false;
        }
    } catch (ImagickException $e) {
        error_log("PDF 轉圖失敗: " . $e->getMessage());
        return false;
    } finally {
        if (isset($im)) {
            $im->clear();
            $im->destroy();
        }
    }
}

// 使用示例
$pdfFile = '/var/www/uploads/doc.pdf';
$thumbDir = '/var/www/public/thumbs';
$result = pdfToPngThumb($pdfFile, $thumbDir, 0, 300, 200);
if ($result) {
    echo "<img src='/thumbs/" . basename($result) . "' alt='PDF縮略圖'>";
} else {
    echo "縮略圖生成失敗";
}

關鍵參數調優

參數推薦值影響
resolution (DPI)150-300越高文字越銳利,但內存/CPU 指數級增長。列表縮略圖 150 足夠。
thumbnailImagetrue, true第三參數 bestfit 保持比例,第四參數 legacy 兼容舊行為。
setCompressionQuality80-90PNG 無損壓縮,質量影響文件大小與壓縮時間。
colorspace$im->setColorspace(Imagick::COLORSPACE_sRGB)確保輸出 sRGB,避免 CMYK 導致顏色偏差。

常見問題排查

  • 權限錯誤: 檢查 policy.xml PDF 讀取策略,重載 PHP-FPM。
  • 內存溢出: 大 PDF 高 DPI 會消耗大量內存。設置 ini_set('memory_limit', '512M') 或降低 DPI。
  • Ghostscript 缺失: ImageMagick 依賴 GS 渲染 PDF。安裝 ghostscript 包。
  • 透明背景變黑: PNG 輸出前調用 $im->setBackgroundColor(new ImagickPixel('white')) 並 $im->flattenImages()。
  • 多頁 PDF 僅轉第一頁: 確認 readImage($pdf."[0]") 語法正確,Imagick 會自動選擇幀。

替代方案對比

方案優點缺點
Imagick + Ghostscript功能全、格式支持廣、PHP 原生擴展依賴重、配置複雜、內存佔用高
pdftoppm (poppler-utils)極快、輕量、專門針對 PDF 渲染需 exec() 調用、輸出格式固定
pdf.js (前端)零後端成本、用戶端渲染首屏慢、移動端性能差、無法服務端預覽
第三方 API (CloudConvert 等)無維護、高可用成本、隱私、延遲、依賴外網

高併發場景建議:隊列異步處理(Redis/RabbitMQ + Worker),或使用 pdftoppm 通過 proc_open() 非阻塞調用。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved