一起學(xué)習(xí)PHP中GD庫的使用(三)

上篇文章我們已經(jīng)學(xué)習(xí)了一個 GD 庫的應(yīng)用,那就是非常常用的制作驗證碼的功能。不過在現(xiàn)實的業(yè)務(wù)開發(fā)中,這種簡單的驗證碼已經(jīng)使用得不多了,大家會制作出更加復(fù)雜的驗證碼來使用。畢竟現(xiàn)在的各種外掛軟件已經(jīng)能夠輕松地破解這種簡單的圖片驗證碼了。當(dāng)然,我們也可以簡單地對他進(jìn)行變形,比如使用中文然后按順序點擊之類的,這些都比較簡單地就能實現(xiàn)。更復(fù)雜的驗證碼則推薦使用一些開源的庫或者api來實現(xiàn)。

今天,我們將繼續(xù)學(xué)習(xí) GD 庫的一些常用的應(yīng)用。依然是通過一些小例子來進(jìn)行學(xué)習(xí),同樣也是我們在日常開發(fā)中非常常用的一些功能。

生成縮略圖

在日常的開發(fā)過程中,不管是客戶還是我們自己在后臺上傳的圖片,大小可能都不一定是我們需要的尺寸,這個時候縮略圖的功能就比較重要了。一般我們會在保留原圖的基礎(chǔ)上生成對應(yīng)原圖的一張縮略圖用于前臺統(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() 這個函數(shù),它的參數(shù)依次是新圖畫布、原圖、新圖的x和y坐標(biāo)起始點、原圖的x和y坐標(biāo)起始點、新圖的大小、原圖的大小。參數(shù)比較多,但也比較好理解,就是將原圖縮小到指定的大小并放到新的畫布上就可以了。

https://upload-images.jianshu.io/upload_images/10153099-54ca3a5303453d02.png

imagesx() 和 imagesy() 函數(shù)不要從字面理解為什么 x 、 y 坐標(biāo)點之類的,它們其實是獲得圖像句柄文件的寬和高。如果我們輸出的是 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() 函數(shù)的最后一個參數(shù),就和 PS 導(dǎo)出圖片時的壓縮比率一樣,如果數(shù)字越小,壓縮比越高,數(shù)字越大,壓縮比越低,圖片質(zhì)量也就越好。默認(rèn)值為 75 ,可以設(shè)置從 0 到 100 的壓縮比。第二個參數(shù)依然是保存圖片的路徑,我們這里測試的代碼還是直接從瀏覽器輸出的,所以我們這里是給的一個 null 。

https://upload-images.jianshu.io/upload_images/10153099-c61e7221383733cb.png

從圖片的畫質(zhì)來看,確實比上一張直接縮小的圖片模糊了許多。當(dāng)然,圖片的大小也小了很多。對于網(wǎng)站的優(yōu)化來說,jpg 圖片的壓縮比例一般都會在默認(rèn)值的 75 左右。如果太小就會出現(xiàn)這種過于模糊的情況從而影響用戶的體驗。具體業(yè)務(wù)具體分析,需要多大的圖片大小還是要根據(jù)我們實際的情況來定。

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

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

$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ī)范的圖片。這時,我們通過計算 寬/高 的比例,來確定是以寬為基準(zhǔn)進(jìn)行縮小還是以高為基準(zhǔn)進(jìn)行縮小。如果原圖的寬高比大于我們規(guī)定的圖片寬高比,則認(rèn)為是以寬度為基準(zhǔn)進(jìn)行縮小。反之,就是以高度進(jìn)行縮小。同樣地,具體的寬高結(jié)果的算法都都是基于對應(yīng)的比率進(jìn)行等比例縮小的。同時,我們還要計算圖片的位置,要放在居中的位置。最后,再將縮小的大小放入到指定大小的畫布中。

https://upload-images.jianshu.io/upload_images/10153099-5ac882e09ccd069d.png

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

可以看到,我們等比例縮放之后是以原圖的高為基準(zhǔn)進(jìn)行縮放的,所以圖片的兩邊會出現(xiàn)白邊。如果是以寬為基準(zhǔn)的,那么圖片上下會出現(xiàn)白邊。當(dāng)然,如果原圖的比例和我們需要的比例是一樣的,就會完整地?fù)螡M整個畫布。大家可以自己用其它大小的圖片測試一下。

圖片加水印

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

$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, '硬核項目經(jīng)理');

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() 來將水印圖片拷貝到原始圖片上。這兩個函數(shù)的區(qū)別就是 imagecopymerge() 在圖片合并的時候多了一個參數(shù)可以指定通道的透明度,也就是說,如果是一張不帶透明度的圖片可以直接使用這個函數(shù)來讓圖片增加透明的效果。

在添加水印之前的判斷是用于判斷圖片大小是否適合添加水印,如果圖片比水印文件還小的話,那么就不要添加水印了,或者再將水印也縮小后再進(jìn)行添加。

https://upload-images.jianshu.io/upload_images/10153099-cbceccaf68071cbc.png

這樣,簡單地水印添加就完成了。網(wǎng)上其實能找到很多前輩已經(jīng)封裝好的添加水印的類,或者 Composer 中也有很多現(xiàn)成的庫,這里只是手寫一個簡單的效果供大家學(xué)習(xí)復(fù)習(xí)。

總結(jié)

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

測試代碼:

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

參考文檔:

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容