ImageMagick vs GD

PHP 應用程式中要轉換圖像格式、製作縮圖、或者施加濾鏡效果,大抵不出兩個選擇:GD 或者 ImageMagick,到底哪一個支援更多圖像格式?哪一個執行得較快?還有什麼需要考慮?Jacek Barecki 寫了一篇文章比較兩者的表現。

可用度

只要把相關的模組安裝好,並且配置妥當,GD 和 ImageMagick 都可以在 PHP 應用程式中被調用,PHP 4.3 開始的版本自動包含 GD,所以在大部份伺服器上你都可以使用 GD,但不是所有伺服器都安裝 ImageMagick。你可以使用下面的程式檢查 GD 和 ImageMagick 是否可用,其中 GD 的 gd_info() 和 ImageMagick 的 queryFormats() 函式列出兩者支援的圖像格式。

if(extension_loaded('gd')) {
print_r(gd_info());
}
else {
echo 'GD is not available.';
}

if(extension_loaded('imagick')) {
$imagick = new Imagick();
print_r($imagick->queryFormats());
}
else {
echo 'ImageMagick is not available.';
}

支援的圖像格式

執行上面的程式後,你會立即發現 ImageMagick 支援的圖像格式比 GD 多得多,GD 只支援 JPG、PNG、GIF、WBMP、WebP, XBM 和 XPM,跟 ImageMagick 支遠超過一百種格式相比,顯得相形見絀。

你可能會認為大部份 ImageMagick 支援的格式都不是常見的格式,你永遠都不會使用這些格式,不過世事難料, Jecek 便曾經因為 GD 不支援 TIFF 而被逼切換到 ImageMagick。

功能

GD 和 ImageMagick 都提供基本的圖像處理功能:

  • 調整大小和裁剪圖像
  • 建立由自定義形狀、文字和圖像檔案產生的圖像
  • 施加濾鏡(改變亮度,對比度,著色等)

如果你需要更先進的圖像處理功能,不妨察看一下 ImageMagick 函式庫的所有功能,在 ImageMagick 的官方範例頁面範例程式可以看到,它可以把圖像轉換、修飾、扭曲,真正變化萬千。

PHP 的 ImageMagick 類別本身共提供了 331 個成員函式,數量十分可觀,一方面這顯示了 ImageMagick 函式庫的巨大能力,另一方面也很難找到和實現針對特定用例的適當方法。

效能

老實說,如果你只是想製作一組縮圖或為圖像施加簡單的轉換,你無需為兩個圖像函式庫的效能孰高孰低而擔心。

很多人曾經為 GD 和 ImageMagick 進行過效能比拼,但是發現有時 GD 跑得輕微快些,有時 ImageMagick 稍稍領先,很在乎使用情況,所以效能不能作為一個選擇的標準。

程式風格

比較一下使用 GD 和 ImageMagick 編寫用來轉換圖像的程式,便會發現兩者有很大的區別。GD 函式庫是一組像 getimagesize() 或 imagecreatetruecolor() 函式,所以使用 GD 的應用程式就是一連串對 GD 函式的呼叫,以下是一個製作 JPG 縮略圖的範例:

$src_img = imagecreatefromjpeg('source.jpg');
if(!$src_img) {
die('Error when reading the source image.');
}
$thumbnail = imagecreatetruecolor(800, 800);
if(!$thumbnail) {
die('Error when creating the destination image.');
}
$result = imagecopyresampled($thumbnail, $src_img, 0, 0, 0, 0, 800, 800, 1600, 1600);
if(!$result) {
die('Error when generating the thumbnail.');
}
$result = imagejpeg($thumbnail, 'destination.jpg');
if(!$result) {
die('Error when saving the thumbnail.');
}
$result = imagedestroy($thumbnail);
if(!$result) {
die('Error when destroying the image.');
}

可以看到有錯誤的時候 GD 函式不會拋出 Exception,所以每次呼叫 GD 函式後都要檢查返回值來確定沒有錯誤。另外,部份「怪獸」 GD 函式有多達十個參數,例如 imagecopyresampled() 和 imagecopyresized(),這些都不能算是良好程式風格。

GD 還有一件令人感到十分不便的事,就是讀取和儲存不同格式的圖像檔案要呼叫不同的函式,若果你要編寫一個製作縮略圖的程式,並希望它可以處理多種圖像格式,你便需要以下的程式碼:

switch($image_type) {
case 'gif' :
$src_img = imagecreatefromgif($path);
break;
case 'png' :
$src_img = imagecreatefrompng($path);
break;
case 'jpg' :
case 'jpeg' :
$src_img = imagecreatefromjpeg($path);
break;
default:
return false;
break;
}

可見 GD 的程式很快會變得又長又難明。現在我們看一看用 ImageMagick 做同樣的事,你便明白分別有多大:

try {
$imagick = new Imagick();
$imagick->readImage('source.jpg');
$imagick->thumbnailImage(800, 800);
$imagick->writeImage('destination.jpg');
}
catch(Exception $e) {
die('Error when creating a thumbnail: ' . $e->getMessage());
}

我們透過 Imagick 類別來呼叫 ImageMagick 函式庫,所以可享受物件導向編程的好處,最簡單的例子是處理錯誤的方法,使用 ImageMagick 時程式可以被一個 try-catch 區塊包裹著安全地執行。從上面的例子可以看到使用 ImageMagick 的製作縮略圖程式不包含任何與圖像格式相關的程式碼,同一段程式可用來處理 JPG、PNG、甚至 TIFF 檔案。如果要轉換圖像的格式,只要在呼叫 writeImage() 之前假如下面的語句:

$image->setImageFormat('PNG');

足夠簡單了吧?可見 ImageMagick 遠遠比 GD 容易使用,雖然在網上可以找到一些程式把 GD 包裝成一個物件導向式的函式庫,但感覺上只是在破布上加上補丁,底子仍然是破布。

普及程度

由於從 PHP 5.3 開始系統預設包含了 GD,很多開發專案都採用 GD,不過有時也會發現一些兼容 GD 和 ImageMagick 的專案,例如 Kohana 圖像函式庫框架

總結

GD 和 ImageMagick 各有千秋。GD 函式庫比較普及,幾乎在所有伺服器上都可以使用,由於它的普及,很容易可以找到它的範例程式和使用它的程式模組,熟悉 GD 的人也比較多,尋找幫助也比較容易。

ImageMagick 則支援更多圖像格式,圖像轉換的功能也比較強大,它也容許你編寫比較清晰和高質量的程式碼。

如你有任何意見,歡迎在下面發表意見。