一起學習PHP中GD庫的使用(三)

上篇文章我們已經學習了一個 GD 庫的應用,那就是非常常用的製作驗證碼的功能。不過在現實的業務開發中,這種簡單的驗證碼已經使用得不多了,大家會製作出更加複雜的驗證碼來使用。畢竟現在的各種外掛軟件已經能夠輕鬆地破解這種簡單的圖片驗證碼了。當然,我們也可以簡單地對他進行變形,比如使用中文然後按順序點擊之類的,這些都比較簡單地就能實現。更復雜的驗證碼則推薦使用一些開源的庫或者api來實現。

今天,我們將繼續學習 GD 庫的一些常用的應用。依然是通過一些小例子來進行學習,同樣也是我們在日常開發中非常常用的一些功能。

生成縮略圖

在日常的開發過程中,不管是客戶還是我們自己在後臺上傳的圖片,大小可能都不一定是我們需要的尺寸,這個時候縮略圖的功能就比較重要了。一般我們會在保留原圖的基礎上生成對應原圖的一張縮略圖用於前臺統一尺寸頁面的展示。

$w = imagesx($im);
$h = imagesy($im);

$imNew = imagecreatetruecolor($w / 2, $h / 2);

imagecopyresized($imNew, $im, 0, 0, 0, 0, $w / 2, $h / 2, $w, $h);

header("Content-type: image/jpg");
imagejpeg($imNew);
imagedestroy($imNew);

上述代碼中,我們生成的縮略圖是原圖的一半大小,使用的就是 imagecopyresized() 這個函數,它的參數依次是新圖畫布、原圖、新圖的x和y座標起始點、原圖的x和y座標起始點、新圖的大小、原圖的大小。參數比較多,但也比較好理解,就是將原圖縮小到指定的大小並放到新的畫布上就可以了。

imagesx() 和 imagesy() 函數不要從字面理解爲什麼 x 、 y 座標點之類的,它們其實是獲得圖像句柄文件的寬和高。如果我們輸出的是 jpg 格式的圖片,還可以指定它的壓縮比率。

$w = imagesx($im);
$h = imagesy($im);

$imNew = imagecreatetruecolor($w / 2, $h / 2);

imagecopyresized($imNew, $im, 0, 0, 0, 0, $w / 2, $h / 2, $w, $h);

header("Content-type: image/jpg");
imagejpeg($imNew, null, 10);
imagedestroy($imNew);

也就是 imagejpeg() 函數的最後一個參數,就和 PS 導出圖片時的壓縮比率一樣,如果數字越小,壓縮比越高,數字越大,壓縮比越低,圖片質量也就越好。默認值爲 75 ,可以設置從 0 到 100 的壓縮比。第二個參數依然是保存圖片的路徑,我們這裏測試的代碼還是直接從瀏覽器輸出的,所以我們這裏是給的一個 null 。

從圖片的畫質來看,確實比上一張直接縮小的圖片模糊了許多。當然,圖片的大小也小了很多。對於網站的優化來說,jpg 圖片的壓縮比例一般都會在默認值的 75 左右。如果太小就會出現這種過於模糊的情況從而影響用戶的體驗。具體業務具體分析,需要多大的圖片大小還是要根據我們實際的情況來定。

生成指定大小的等比例縮略圖

還有一種業務情況是,我們前臺的圖片展示大小都是一樣的,比如商品圖片在列表中的顯示。這時,很多圖片直接壓縮可能就會丟失比例,比如我們上傳了一張 16:9 的大寬圖,而前臺列表頁的圖片位置是 4:3 的圖,這裏我們就要等比例按照最大寬度或者最大高度進行縮小,同時多出來的部分留白邊或者透明邊,這時,只要計算一下圖片的比例情況就可以了。

$w = imagesx($im);
$h = imagesy($im);

$imNew = imagecreatetruecolor(202, 152);
imagefill($imNew, 0, 0, imagecolorallocate($imNew, 255, 255, 255));
imagerectangle($imNew, 0, 0, 201, 151, imagecolorallocate($imNew, 0, 0, 0));

$sW = 0;
$sH = 0;
if ($w / $h > 200 / 150) {
    $q = 200 / $w;
    $sH = $h * $q;
    $sW = $w * $q;
    $sX = 0;
    $sY = (150 - $sH) / 2;
} else {
    $q = 150 / $h;
    $sH = $h * $q;
    $sW = $w * $q;
    $sX = (200 - $sW) / 2;
    $sY = 0;
}

imagecopyresized($imNew, $im, $sX + 2, $sY + 1, 0, 0, $sW, $sH, $w, $h);

header("Content-type: image/jpg");
imagejpeg($imNew);
imagedestroy($imNew);

在測試代碼中,我們規定的大小是 200*150 的圖片大小,也就是 4:3 的圖片規格。而需要操作的圖片則是 300*244 的一張不太規範的圖片。這時,我們通過計算 寬/高 的比例,來確定是以寬爲基準進行縮小還是以高爲基準進行縮小。如果原圖的寬高比大於我們規定的圖片寬高比,則認爲是以寬度爲基準進行縮小。反之,就是以高度進行縮小。同樣地,具體的寬高結果的算法都都是基於對應的比率進行等比例縮小的。同時,我們還要計算圖片的位置,要放在居中的位置。最後,再將縮小的大小放入到指定大小的畫布中。

我們這段測試代碼中的畫布多了兩個像素,是爲了畫那個黑色的邊框,目的也是爲了演示能夠看清楚。

可以看到,我們等比例縮放之後是以原圖的高爲基準進行縮放的,所以圖片的兩邊會出現白邊。如果是以寬爲基準的,那麼圖片上下會出現白邊。當然,如果原圖的比例和我們需要的比例是一樣的,就會完整地撐滿整個畫布。大家可以自己用其它大小的圖片測試一下。

圖片加水印

除了縮略圖之外,加水印的功能也是很多業務開發中必備的功能。直接的文字水印其實就不用多說了,上篇文章中的 imagettftext() 就可以直接加了,只需要給它用 imagecolorallocatealpha() 函數指定一個帶透明的顏色就可以了。今天我們主要來講的是圖片水印的添加。

$imNew = imagecreatetruecolor(150, 30);

imagecolortransparent($imNew, imagecolorallocatealpha($imNew, 255, 255, 255, 128));
imagesavealpha($imNew, true);

$font = '../font/msyh.ttf';
imagettftext($imNew, 16, 0, 11, 21, imagecolorallocate($imNew, 255, 255, 255), $font, '硬核項目經理');

if (imagesx($im) > 150 + 10 && imagesy($im) > 60 + 10) {
    imagecopy($im, $imNew, imagesx($im) - 150 - 10, imagesy($im) - 30 - 10, 0, 0, 150, 30);

    imagecopymerge($im, $imNew, imagesx($im) - 150 - 10, imagesy($im) - 60 - 10, 0, 0, 150, 30, 50);
}

header("Content-type: image/jpg");
imagejpeg($im);
imagedestroy($im);

首先,我們通過 imagecolortransparent() 和 imagesavealpha() 指定一個透明畫布。然後通過 imagettftext() 生成一張文字圖片。注意,這裏是圖片哦,不是直接添加的文字。

接着,使用 imagecopy() 或 imagecopymerge() 來將水印圖片拷貝到原始圖片上。這兩個函數的區別就是 imagecopymerge() 在圖片合併的時候多了一個參數可以指定通道的透明度,也就是說,如果是一張不帶透明度的圖片可以直接使用這個函數來讓圖片增加透明的效果。

在添加水印之前的判斷是用於判斷圖片大小是否適合添加水印,如果圖片比水印文件還小的話,那麼就不要添加水印了,或者再將水印也縮小後再進行添加。

這樣,簡單地水印添加就完成了。網上其實能找到很多前輩已經封裝好的添加水印的類,或者 Composer 中也有很多現成的庫,這裏只是手寫一個簡單的效果供大家學習複習。

總結

關於圖片 GD 庫的功能函數還有很多,但說實話,筆者現在都已經用得不多了。爲什麼呢?在實際的業務開發中,大家其實都已經習慣使用 oss 、七牛、upyun 之類的雲存儲了。不管是圖片縮放、添加水印,甚至是簡單地進行一些 PS 編輯,都非常方便。而且最主要的是不需要再佔用我們的服務器存儲資源以及帶寬資源,何樂而不爲呢。像我現在的工作中,程序代碼服務器基本上只需要原始的 20G 左右大小就可以了,只是運行代碼,不存儲上傳的文件、圖片以及靜態資源。

測試代碼:

https://github.com/zhangyue0503/dev-blog/blob/master/php/202012/source/3.一起學習PHP中GD庫的使用(三).php

參考文檔:

https://www.php.net/manual/zh/book.image.php

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章