上篇文章我們已經學習了一個 GD 庫的應用,那就是非常常用的制作驗證碼的功能。不過在現(xiàn)實的業(yè)務開發(fā)中,這種簡單的驗證碼已經使用得不多了,大家會制作出更加復雜的驗證碼來使用。畢竟現(xiàn)在的各種外掛軟件已經能夠輕松地破解這種簡單的圖片驗證碼了。當然,我們也可以簡單地對他進行變形,比如使用中文然后按順序點擊之類的,這些都比較簡單地就能實現(xiàn)。更復雜的驗證碼則推薦使用一些開源的庫或者api來實現(xiàn)。
今天,我們將繼續(xù)學習 GD 庫的一些常用的應用。依然是通過一些小例子來進行學習,同樣也是我們在日常開發(fā)中非常常用的一些功能。
生成縮略圖
在日常的開發(fā)過程中,不管是客戶還是我們自己在后臺上傳的圖片,大小可能都不一定是我們需要的尺寸,這個時候縮略圖的功能就比較重要了。一般我們會在保留原圖的基礎上生成對應原圖的一張縮略圖用于前臺統(tǒng)一尺寸頁面的展示。
$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 。
從圖片的畫質來看,確實比上一張直接縮小的圖片模糊了許多。當然,圖片的大小也小了很多。對于網站的優(yōu)化來說,jpg 圖片的壓縮比例一般都會在默認值的 75 左右。如果太小就會出現(xiàn)這種過于模糊的情況從而影響用戶的體驗。具體業(yè)務具體分析,需要多大的圖片大小還是要根據我們實際的情況來定。
生成指定大小的等比例縮略圖
還有一種業(yè)務情況是,我們前臺的圖片展示大小都是一樣的,比如商品圖片在列表中的顯示。這時,很多圖片直接壓縮可能就會丟失比例,比如我們上傳了一張 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);
在測試代碼中,我們規(guī)定的大小是 200*150 的圖片大小,也就是 4:3 的圖片規(guī)格。而需要操作的圖片則是 300*244 的一張不太規(guī)范的圖片。這時,我們通過計算 寬/高 的比例,來確定是以寬為基準進行縮小還是以高為基準進行縮小。如果原圖的寬高比大于我們規(guī)定的圖片寬高比,則認為是以寬度為基準進行縮小。反之,就是以高度進行縮小。同樣地,具體的寬高結果的算法都都是基于對應的比率進行等比例縮小的。同時,我們還要計算圖片的位置,要放在居中的位置。最后,再將縮小的大小放入到指定大小的畫布中。
我們這段測試代碼中的畫布多了兩個像素,是為了畫那個黑色的邊框,目的也是為了演示能夠看清楚。
可以看到,我們等比例縮放之后是以原圖的高為基準進行縮放的,所以圖片的兩邊會出現(xiàn)白邊。如果是以寬為基準的,那么圖片上下會出現(xiàn)白邊。當然,如果原圖的比例和我們需要的比例是一樣的,就會完整地撐滿整個畫布。大家可以自己用其它大小的圖片測試一下。
圖片加水印
除了縮略圖之外,加水印的功能也是很多業(yè)務開發(fā)中必備的功能。直接的文字水印其實就不用多說了,上篇文章中的 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() 來將水印圖片拷貝到原始圖片上。這兩個函數的區(qū)別就是 imagecopymerge() 在圖片合并的時候多了一個參數可以指定通道的透明度,也就是說,如果是一張不帶透明度的圖片可以直接使用這個函數來讓圖片增加透明的效果。
在添加水印之前的判斷是用于判斷圖片大小是否適合添加水印,如果圖片比水印文件還小的話,那么就不要添加水印了,或者再將水印也縮小后再進行添加。
這樣,簡單地水印添加就完成了。網上其實能找到很多前輩已經封裝好的添加水印的類,或者 Composer 中也有很多現(xiàn)成的庫,這里只是手寫一個簡單的效果供大家學習復習。
總結
關于圖片 GD 庫的功能函數還有很多,但說實話,筆者現(xiàn)在都已經用得不多了。為什么呢?在實際的業(yè)務開發(fā)中,大家其實都已經習慣使用 oss 、七牛、upyun 之類的云存儲了。不管是圖片縮放、添加水印,甚至是簡單地進行一些 PS 編輯,都非常方便。而且最主要的是不需要再占用我們的服務器存儲資源以及帶寬資源,何樂而不為呢。像我現(xiàn)在的工作中,程序代碼服務器基本上只需要原始的 20G 左右大小就可以了,只是運行代碼,不存儲上傳的文件、圖片以及靜態(tài)資源。
測試代碼:
https://github.com/zhangyue0503/dev-blog/blob/master/php/202012/source/3.一起學習PHP中GD庫的使用(三).php
參考文檔: