在日常的開發(fā)過程中,GD 庫最常用的功能就是幫我們對圖片進行一些處理,當然,除了處理已有的圖片之外,它也可以直接來畫圖,就像我們最常見的圖片驗證碼。今天的內(nèi)容主要就是和畫圖有關(guān),所以最后我們也會做一個非常簡單的圖片驗證碼的例子。
創(chuàng)建圖片并指定顏色
首先,我們要先創(chuàng)建一個圖片的畫布。就和 PhotoShop 一樣,任何的繪圖都要在一張畫布下進行。
// 創(chuàng)建一個 200X200 的圖像
$img = imagecreatetruecolor(200, 200);
// 分配顏色
$white = imagecolorallocate($img, 255, 255, 255);
$black = imagecolorallocate($img, 0, 0, 0);
$red = imagecolorallocate($img, 255, 0, 0);
// 帶透明通道的顏色
$alphaRed = imagecolorclosestalpha($img, 255, 0, 0, 50);
imagecreatetruecolor() 函數(shù)就是用于創(chuàng)建一個真彩色圖片,它和 imagecreate() 的區(qū)別就在于 imagecreate() 創(chuàng)建的是一張基于調(diào)色板的圖片。它們?yōu)楫嫴继畛漕伾牧鞒滩灰粯?,imagecreate() 不需要使用 imagefill() 進行填充背景色,直接使用 imagecolorallocate() 就會以第一次調(diào)用的 imagecolorallocate() 的顏色進行填充。它們返回的圖片文件句柄都是后期操作所需要的句柄對象。
imagecolorallocate() 就是為圖片分配顏色,這里我們定義了幾種顏色,另外還使用 imagecolorclosestalpha() 定義了一個帶通道的也就是還透明效果的顏色,它的最后一個參數(shù)就是 0-100 的透明度設(shè)置。
填充背景色
接下來,由于我們使用的是 imagecreatetruecolor() ,所以我們要對畫布進行背景色的填充。
// 填充背景色
imagefill($img, 0, 0, $black);
弧線、直線、矩形
不管是畫線還是畫弧線,都只是一些簡單的函數(shù)調(diào)用。
// 畫一個白色的圓
imagearc($img, 100, 100, 150, 150, 0, 360, $white);
// 畫一條線段
imageline($img, 20, 180, 120, 120, $white);
// 填充一個帶透明的矩形
imagefilledrectangle($img, 30, 30, 70, 70, $alphaRed);
imagearc() 函數(shù)本身是用于畫弧線的,第二和第三個參數(shù)用于指定圓心的位置,第四第五個參數(shù)指定圓的寬度和高度,第六、第七個參數(shù)指定弧線的起始位置(以角度指定),最后一個參數(shù)就是指定的顏色。通過給定的從 0 到 360 度的角度,我們就畫了一個圓形出來。如果不是指定的完整的 360 度,就會是一條弧線。
直線線段的函數(shù) imageline() 的參數(shù)就比較簡單了,第二第三個參數(shù)是起始點的坐標,第四第五個參數(shù)是結(jié)束點的坐標,兩個坐標點一連就繪制出了一條線段。
imagefilledrectangle() 是以填充的方式繪制一個矩形,也就是說我們繪制的矩形是在內(nèi)部填充了顏色的,而不是線條的描邊。它的參數(shù)坐標和線段是一樣的,并且我們填充的是上面定義的帶透明效果的顏色。
當然,我們能夠直接繪制的圖形和線條還有很多。需要注意的是,帶 fill 關(guān)鍵字的基本都是填充圖形,而不帶 fill 的就是形狀線段。比如如果要一個矩形框的話,我們可以使用 imagerectangle() 來進行繪制。同理,如果要畫一個扇形塊的話,我們也可以直接使用 imagefillarc() 。更多的圖形和線段大家可以參考文檔,內(nèi)容比較多,這里就不多羅列了,今天我們主要的功能是生成一張驗證碼,只要有一個線段來做為干擾因素就可以啦。
寫字
直接在圖片中寫字也很簡單。
$string = "I Like PHP!";
// 水平寫一個字符
imagechar($img, 5, 70, 50, $string, $red);
// 垂直寫一個字符
imagecharup($img, 3, 120, 50, $string, $red);
// 水平寫字符串
imagestring($img, 5, 70, 150, $string, $red);
// 垂直寫字符串
imagestringup($img, 3, 120, 150, $string, $red);
imagechar() 是只寫一個字符,imagecharup() 是垂直地寫。imagestring() 則是寫字符串,而 imagestringup() 也就是垂直地寫字符串啦。它們第二個參數(shù)都是字體的大小,第三和第四個參數(shù)是開始寫字的坐標起始位置。不過,使用這些函數(shù)對圖片進行內(nèi)容書寫的話,最主要的一個問題就是不能指定字體,這樣在默認情況下中文是沒辦法輸出的。所以,我們一般會用另一個函數(shù)來為圖片加上文字。
// 用 TrueType 字體向圖像寫入文本
$font = '../font/arial.ttf';
imagettftext($img, 20, 0, 11, 21, $white, $font, $string);
imagettftext() 函數(shù),能夠通過指定的字體來向圖片添加文字內(nèi)容,有了字體文件的支持,寫上去的文字也好看了很多。更主要的是,它還能方便地調(diào)整文字大小和傾斜角度。第二個參數(shù)就是指定文字的大小,第三個參數(shù)就是可以指定文字的傾斜角度,也就是我們可以旋轉(zhuǎn)文字。
生成圖片
最后,當然就是要生成并輸出圖片啦!
// 將圖像輸出到瀏覽器
header("Content-type: image/png");
imagepng($img);
// 釋放內(nèi)存
imagedestroy($img);
我們的測試代碼是直接將圖片輸出到瀏覽器,所以需要指定一個文件輸出的 header 頭。使用 imagepng() 就能生成一張 PNG 格式的圖片,它還有第二個參數(shù),如果給定了第二個參數(shù),那么圖片就會直接以文件形式保存到參數(shù)指定的路徑中。如果不給定這個參數(shù)的話,就會像 phpinfo() 一樣直接輸出到輸出緩沖區(qū)中,也就是直接打印內(nèi)容了。最后,我們再使用 imagedestroy() 釋放掉圖片句柄解除圖片文件的內(nèi)存占用。
除了 imagepng() 之外,還有 imagejpeg() 、 imagegif() 等等一系列的圖片生成函數(shù),大家可以自己查閱文檔學習了解。
說了這么多,我們上面這一堆東西畫出來的是個啥?

小例子:簡單的驗證碼圖片
最后的小例子就是一開頭我們說過的,一個非常簡單的圖片驗證碼的生成?,F(xiàn)在的驗證碼功能其實非常復雜了,各種形式的驗證碼都有,主要還是為了系統(tǒng)的安全著想。同樣在 Composer 中也有很多現(xiàn)成的驗證碼組件供我們使用,其實我們并不需要自己去實現(xiàn)這樣的驗證碼功能的,但學習嘛,總是要接觸一下了解一下的,而且如果是一些很小的小項目的話,完全就可以自己手寫一個來練習了。
$img = imagecreatetruecolor(120, 50);
imagefill($img, 0, 0, imagecolorallocate($img, 255, 255, 255));
$colors = [
imagecolorallocate($img, 0, 0, 0),
imagecolorallocate($img, 255, 0, 0),
imagecolorallocate($img, 0, 255, 0),
imagecolorallocate($img, 0, 0, 255),
];
$chars = array_merge(range(0, 9), range('a', 'z'), range('A', 'Z'));
for ($i = 0; $i < 10; $i++) {
imageline(
$img,
random_int(0, 120),
random_int(0, 50),
random_int(0, 120),
random_int(0, 50),
$colors[array_rand($colors)]
);
}
$font = '../font/arial.ttf';
for ($i = 0; $i < 4; $i++) {
$char = $chars[array_rand($chars)];
$fontSize = random_int(18, 24);
$c = random_int(-20, 20);
$x = $i * 26;
if ($x == 0) {
$x = 5;
}
imagettftext(
$img,
$fontSize,
$c,
$x,
40,
$colors[array_rand($colors)],
$font,
$char
);
}
header("Content-type: image/png");
imagepng($img);
imagedestroy($img);
代碼就不多做解釋了,隨機取一些字符,并且隨機生成一些線段,其它的就是我們上面文章中介紹過的函數(shù)的使用了。最后生成的圖片就是這個樣子的:

總結(jié)
不管之前有沒有自己寫過這種驗證碼的小工具,今天的內(nèi)容相信都是一次系統(tǒng)的學習和回顧,因為我們是按著順序從創(chuàng)建一張圖片畫布,到繪制線條和圖形,再到添加文字,最后生成圖片這一系列的步驟走下來的。以后不管是面試還是自己做小工具的時候,記住這條線,然后參考文檔就可以啦。畢竟這些函數(shù)的參數(shù)都還是挺長挺亂的,除非天天用,要不可真記不住。
測試代碼:
https://github.com/zhangyue0503/dev-blog/blob/master/php/202012/source/2.一起學習PHP中GD庫的使用(二).php
參考文檔: