圖形處理
PHP 的圖形處理,主要功能集中在 PHP 的圖形處理函數。
需要先掌握一些要點。什麼叫圖片,怎麼顯示圖片。
所謂的圖片,其實也是一種文件,只是內容不是我們肉眼直接可見的。如果我們用記事本打開一張圖片,只會看到一片亂碼。其實這些亂碼,只是相對我來說是亂碼。對於可以讀寫它的程序來說,一點都不亂。如果我們知道一種圖片的格式,我們就可以自己生成一張圖片。就像我們最早的時候,制作的記事本留言本一樣。
把一些特殊格式的數據,保存到一個文件,就可以生成一張圖片。反之,我們如果用 PHP 直接輸出這些內容,浏覽器也會認為這是一張圖片。
我們先來證實一下這一點,同學們先准備好一張圖片。建議小一點的, JPG 格式就可以了。然後我們使用 PHP 讀取這張圖片,就像普通文件一樣讀取。
<?PHP
$file = "1.jpg";
$fp = fopen($file, "rb");
$data = fread( $fp, filesize($file));
fclose($fp);
echo $data;
?>
相信對於同學們來說,這個代碼沒有什麼問題吧。
打開文件,讀取內容(所有字節),關閉文件,輸出內容。
有沒有同學試一下,這個代碼運行後會輸出什麼,截個圖上來看一下。
也許有同學會奇怪吧,怎麼是亂碼。
因為浏覽器默認,認為我們的 PHP 輸出是文本。即使是亂碼,我們需要告訴浏覽器,這是一張圖片。這個需要用 header 函數,發送頭信息,告訴浏覽器,當前輸出的內容,是格片格式。
Header("Content-type: image/jpeg");
這是 JPG 格式圖片使用的頭信息,內容類型:圖片/jpeg,需要加在 echo 之前。
<?PHP
$file = "1.jpg";
$fp = fopen($file, "rb");
$data = fread( $fp, filesize($file));
fclose($fp);
Header("Content-type: image/jpeg");
echo $data;
?>
同學們再試一下。
這個代碼證明了一點:即使輸出的是亂碼,只要浏覽器知道它是什麼內容;它就能正確顯示。
相對的,如果我們把讀出來的內容,保存到另一個文件,就可以復制這張圖片。
在這裡,可能會有一些同學會有一些誤解。認為,這裡還是一個網頁。各位同學可以試一下,在打開的網頁空白處,點一下鼠標右鍵,查看源文件,會發現,沒有這個選項。即使有,也是灰的。這是因為,這個不是一個頁面,浏覽器已經認為,我們這個 PHP 程序,是一張圖片了。
平時我們使用 PHP 進行任何形式的輸出時,浏覽器認為這是一個 HTML 網頁,才能看到源代碼。
如果我們輸出的是圖片內容,要能正確顯示,就必須告訴浏覽器,本次輸出,別把我當成網頁,而是當成圖片。也就是說,我們的 php 程序,是一張圖片。如果要想在別的網頁使用這張圖片,需要像平時一樣 <img 標記來調用這張圖片。
<img src="img.php" />
把這個 PHP 程序,當成一張圖片來對待,而不能直接在這個程序寫上。
<img src="<?PHP 我們剛才的代碼 ?>" />
這樣是不對的,這樣只會導致一個結果。
<img src="一堆亂碼" />
這是不可能顯示得出來的。
所以,使用 PHP 處理圖片的程序,一定是單項功能的 PHP 程序。除非你不輸出這張圖片,而只是把它保存起來。
<?PHP
$file = "1.jpg";
$fp = fopen($file, "rb");
$data = fread( $fp, filesize($file));
fclose($fp);
$fp = fopen("2.jpg", "wb");
fwrite($fp, $data);
fclose($fp);
?>
<img src="2.jpg" />
如果代碼是這麼寫,就是另一回事,沒有錯。把圖片保存到另一個地方,然後輸出 HTML 調用這張圖片。要直接輸出圖片的 PHP 程序,一定不可能含有別的輸出,沒有用。只能單純的輸出圖片的內容,就是那堆亂碼。
好了,讀取圖片,輸出圖片都沒有問題了。
文件的內容是特殊格式,我們看都看不懂,怎麼處理它呢?
PHP 提供了專門的圖形處理函數。
圖形處理函數庫,有一個專用的名字,叫 GD庫。
這個函數庫並不是 PHP 自帶的。需要在安裝 PHP 的時候,在 php.ini 裡設置加載。
庫文件名叫 php_gd2.dll。PHP 的安裝包裡就有,在 ext 目錄下。如果哪位同學的 php.ini 裡還沒加載 GD庫,請現在打開它。
這樣,PHP 才有圖形處理函數可用。
當前 PHP 自帶的 GD 庫版本是 2.0.28。PHP 4 帶的是 gd 2.0,PHP 3 時代是 gd 1.6。
為什麼要提這個呢?
因為 gd 2.0 的時候,因為 GIF 圖片的版權問題。PHP 做為免費開源的語言,無法向 GIF 的版權商提供版權費,所以只能暫停對 GIF 圖片的支持。PHP 5 以後,GIF 版權到期, 我們的 PHP 才重新支持 gif 圖片。
好了,我們打開 PHP 手冊,看一下 Image 圖像函數。
函數很多,但是,大致上可以分成四類:創建,繪畫,設置,輸出。
如果要創建一張圖片,可以使用 imagecreate 函數。從函數名就可以看得出來了,創建圖像。從手冊上,可以看得到語法格式。
返回圖像資源 imagecreate(寬度 , 高度)
寬度和高度以像素為單位。
還有另一個函數,imagecreatetruecolor 新建一個真彩色圖像,支持更多顏色。
創建類的函數,都會返回一個圖片資源,有點類似於 fopen 函數的返回。資源型的數據,內部含有一個可讀寫指針,,讓我們可以對圖片進行編輯操作。
我們先來試試創建一張圖片,先用 imagecreate 函數好了。
為了能看到這張圖片,我們需要輸出。但是我們的經驗告訴我們,資源型的內容不能直接輸出。
圖片形函數,給我們提供了一些函數,分別是:
imagejpeg 以 JPG 格式輸出
imagegif 以 GIF 格式輸出
imagepng 以 PNG 格式輸出
函數格式是一樣的。
imagejpeg( 圖像資源 , [保存路徑])
如果需要保存這張圖片,就在第二個參數寫上文件名就可以了。如果只是希望直接輸出,第二個參數不寫就行。
我們現在先直接輸出這張圖像。
Header("Content-type: image/JPEG");
$img =imagecreate(100, 100);
imagejpeg($img);
創建一張 100*100 的圖像,然後用 JPG 格式輸出它。要記得告訴浏覽器,這是圖片。
運行的結果是什麼樣的呢?有哪位同學截個圖上來看看。
是的,會輸出一張黑色的圖片。因為我們並沒有在上面畫任何內容,也沒告訴它應該用什麼顏色。
我們先來簡單一點的操作,先在上面塗點顏色。這個需要使用 imagecolorallocate 函數。
函數功能是:為一幅圖像分配顏色
函數格式是
imagecolorallocate(圖像資源, 紅色,綠色,藍色)
三元色,分別用 0 到 255 的數字表示。0是最暗,255是最亮。如果需要白色,三色都是 255 就可以了,黑色就是三色 0,如果只要紅色,就是 255 0 0。
header("Content-type: image/jpeg");
$img =imagecreate(100, 100);
imagecolorallocate($img, 255,0,0);
imagejpeg($img);
我就填上個純紅好了。同學們可以自己試試,分別給紅綠藍設置一些數值,看看結果如何。這個配色,需要一些知識了。同學們也可以直接在各種畫圖工具裡得到這個顏色。
右下角的 紅綠藍 值就可以直接用。很多軟件都有類似的調色板,很容易可以得到各種顏色值。
這裡有一點要注意。
imagecolorallocate 函數,只有第一次使用的時候,會給圖像填上背景色,重新使用,並不會改變背景色。
header("Content-type: image/jpeg");
$img =imagecreate(100, 100);
imagecolorallocate($img, 255,0,0);
imagecolorallocate($img, 0, 0, 255);
imagejpeg($img);
這個代碼,並不會輸出預期的藍色。但是,並不表示函數沒有用。函數依然有效,只是這個顏色沒有被使用而已。我們可以用這個顏色,做其他用途,比如寫字。
我們來試試,在圖像上面寫點字。
PHP 給我們提供的函數裡面,有兩個函數可以用於在圖像上寫字,分別是 imagestring 和 imagestringup。
imagestring 是橫向寫字
imagestringup 是縱向寫字
如果用 imagestringup 寫的話,我就們看字就得扭著脖子看了。好吧,先用 imagestring。
imagestring 函數原型
imagestring(圖像資源, 字體, 開始X坐標,開始Y坐標, 要寫的字, 顏色)
PHP 自帶的字體只有5種,需要用數字1到5表示。
我們來試一下吧。
header("Content-type: image/jpeg");
$img =imagecreate(100, 100);
imagecolorallocate($img, 255,0,0);
$color = imagecolorallocate($img, 0, 0, 255);
imagestring($img, 4, 0,0, 'abcdef', $color);
imagejpeg($img);
你大爺的,好刺眼,我換白底好一點。
有沒有哪個同學試試寫個中文?結果會讓人很失望。
因為 PHP 自帶的字體,弱爆了,跟本無法正常顯示中文。怎麼辦呢?
自定義字體。
image 函數,給我們提供了另一個函數,可以使用自定義字體來寫字。嚴格來說是“畫字”。需要一個帶點陣格式的字體文件,而且要支持中文的,最常見的就是 ttf 類型的字體了。如果做過平面設計的同學,對這個一定不陌生,沒做過的同學,也不要緊。我們可以在我們的系統裡面,挖幾個出來用用。系統自帶的字體文件,在 C:\windows\fonts 目錄,我們可以在裡面找一個支持中文的字體。WIN 系統自帶的字體,大多數都支持中文,我挑一個微軟雅黑。回到我們的 PHP。
要使用這個字體文件來畫字,需要用 imagettftext 函數。
imagettftext 函數原型
imagettftext (圖像資源, 字體大小, 字體方向, 開始X坐標, 開始Y坐, 字體顏色, 字體文件, 要寫的字 )
我的娘哦,好多參數。估計各位同學也是第一次用這麼多參數的函數吧。
//創建圖片,並設置白底
$img =imagecreate(100, 100);
imagecolorallocate($img, 255,255,255);
//准備一個顏色,
$color = imagecolorallocate($img, 0, 0, 255);
//准備一個字體文件
$font = "msyhbd.ttf";
//圖像資源, 字體大小, 字體方向, 開始X坐標, 開始Y坐, 字體顏色, 字體文件, 要寫的字
imagettftext($img, 14, 0, 20, 20, $color, $font, "中文支持");
//JPG格式輸出圖像
imagejpeg($img);
這個圖像文件,如果路徑不在當前目錄下,要告訴 PHP 在哪裡。
比如 $font = "./font/msyhbd.ttf";
或者 $font = "C:\\windows\\fonts\\msyhbd.ttf";
必須讓 PHP 找得到這個字體文件
imagettftext($img, 14, 180, 150, 150, $color, $font, "中文支持");
字體方向 180度,結果就成這樣子。另外,中文在這裡必須是 utf8 編碼。這個很容易做到,把 PHP 文件轉換成 utf8 編碼就可以了。使用 gbk 編碼的同學,可以給字體轉換一下編碼。
$text = iconv("gbk", "utf-8", "中文支持");
只要有足夠的字體,我們可以讓 PHP 輸出任意樣式
$font = "FZKANGFW.TTF";
$text = iconv("gbk", "utf-8", "中文支持");
imagettftext($img, 20, 0, 150, 150, $color, $font, $text);
這個效果,配合預定變量 $_SERVER 可以做到一個效果。
$_SERVER['REMOTE_ADDR']
這個服務器變量,可以得到來訪者的 IP 地址。網上的各種帶 IP 顯示的圖片,就是這麼做出來的。不就是在圖片上寫幾個字麼。
好了。然後我們來學習一下。在上面畫線條。
畫圖函數很多。
imagedashedline - 畫一虛線
imagedestroy - 銷毀一圖像
imageellipse - 畫一個橢圓
imagefill - 區域填充
imagefilledarc - 畫一橢圓弧且填充
imagefilledellipse - 畫一橢圓並填充
imagefilledpolygon - 畫一多邊形並填充
imagefilledrectangle - 畫一矩形並填充
畫線是 imageline,其他畫圖函數,同學們可以自行參考手冊。
看來看去,不外乎原理就是:在圖像資源上,用什麼顏色,從哪個坐標開始,畫什麼。
imageline函數原型
( 圖像資料, 開始X坐標, 開始Y坐標, 結束X坐標, 結束Y坐標, 顏色 )
在數學中,我們知道XY坐標可以確定平面上的一個點,兩個點可以決定一個線段。
//創建圖片,並設置白底
$img =imagecreate(300, 300);
imagecolorallocate($img, 200,200,200);
//准備一個顏色,
$color = imagecolorallocate($img, 0, 0, 255);
//用這個顏色畫一條線
imageline($img, 0,150, 300,150, $color);
//JPG格式輸出圖像
imagejpeg($img);
我的圖像是 300*300 的大小。從0,150 就是最左邊,中間位置,到最右邊,中間位置。
如果要畫一張網格的話,你就慢慢算座標,然後重復畫就可以了。
for($i=0; $i < 6; $i++) {
$y = $i*50;
imageline($img, 0,$y, 300,$y, $color);
}
豎線什麼的,就不多說了。
還有其他各種線條,形狀,各位同學可以跟據手冊的說明,自行練習。
很多時候,我們圖片是現成的。我們要做的只是縮小,裁剪大小。
圖片是現成的,我們需要把圖片加載進來,跟據圖片的不同類型,我們需要不同的函數來加載。
imagecreatefromjpeg 創建一張圖像,來自JPG文件
imagecreatefromgif GIF
imagecreatefrompng PNG
imagecreatefromwbmp WBMP
imagecreatefromxbm XBM
圖片是什麼類型,就用什麼函數來載入。這些函數,都屬於創建類函數。之前,我們使用寫字,畫線,都屬於繪畫類函數。這樣區分,就不覺得函數多了。很多函數其實是重復的,只是針對於不同的類型。所有的操作,都是針對於畫布,在畫布上畫什麼。
其實 PHP 並不能縮小一張圖片,那只是一種思路上的技巧。用的是圖像復制函數imagecopymerge。
可以把圖像的一部份,復制到另一張圖像上面,同類的還有另一個函數imagecopyresampled。都是復制圖像的一部份,復制到另一張圖像上面。這意味著,這樣的操作,需要兩個圖像。一個是原圖,一個是新生成的圖。
原圖,我們可以用 imagefrom 系列函數加載進來。新圖,我們可以自己創建。然後再使用圖像復制函數,從原圖復制到新圖。
如果復制的只是其中的一個區域,那就是 裁剪功能。如果復制是整個圖像大小,新圖的大小和原圖大小不同,就是改變圖片大小,也就是縮略圖,或者放大圖。
$image = "1.jpg";
//讀取圖片大小
list($width, $height) = getimagesize($image);
//加載圖片
$bimg = imagecreatefromjpeg($image);
//新建圖片,大小是原圖的一半
$simg =imagecreatetruecolor($width * 0.5, $height * 0.5);
//在原圖上,把原圖的全部,縮小一半,復制過來
imagecopyresampled($simg, $bimg, 0,0, 0,0, $width*0.5, $height*0.5, $width, $height );
//JPG格式輸出小圖像
imagejpeg($simg);
應該有同學發現了,這裡使用的是 imagecreatetruecolor 創建新圖像。真彩圖像,而不是 imagecreate。同學們可以試一下,用 imagecreate 是什麼結果。
復制圖像,我選擇了 imagecopyresampled 函數,復制並調整大小。同類函數還有 imagecopyresized。
imagecopyresized
imagecopyresampled
這兩個函數都是復制並調整大小圖像。同學們可以自己測試它們的區別。由於參數太多,我這裡幫你們做一個注釋。
新圖, 原圖,
新圖起點X,新圖起點Y,
原圖起點X,原圖起點Y,
新圖寬度,新圖高度,
原圖寬度,原圖高度
兩個一組,一起看就行了。
//加載圖片
$bimg = imagecreatefromjpeg($image);
//新建圖片,大小是原圖的一半
$simg =imagecreatetruecolor($width * 0.5, $height * 0.5);
//在原圖上,把原圖的全部,縮小一半,復制過來
imagecopyresampled($simg, $bimg, 0,0, $width*0.5, $height*0.5, $width, $height, $width, $height );
這個代碼的意思是
$simg, $bimg, //新圖,原圖
0,0, //從新圖的 0*0 開始畫
$width*0.5, $height*0.5, //從原圖的中心點取樣
$width, $height, //新圖和原圖等大小。
$width, $height //到原圖的最右下角坐標結束
由於創建的圖像只有原圖的一半,這個代碼,會使得最終圖片只顯示原圖中心點開始。右下角的內容。也就是 1/4 原圖的內容,就是所謂的裁剪。
這些函數的參數太多,不太容易看,計算各個采樣坐標,需要更細心。
水印圖的原理也是一樣的。加載兩張圖,創建兩個圖像對象。然後把水印圖,復制到原圖上。面。其實都只是一個思路的技巧而已。
圖形函數就講到這裡。
我先來總結一下這一課的要點。
1、一定要先創建圖像,加載創建或自己創建。
2、只能在圖像上面繪畫,線條,形狀
3、文字只能用 UTF8 編碼,要顯示中文需要中文字體
4、圖像本身不能直接調整,只能在復制的過程中調整。
5、如果要直接輸出圖像,這個程序不能輸出其他多余的東西
6、一個直接輸出圖像的程序,要把它看成圖片來調用。
圖像函數。分為幾類:
創建類:imagecreate、imagecreatefromjpeg
設置類:imagecolorallocate、getimagesize
繪制類:imagecopyresampled、imageline、imagettftext
輸出類:imagejpeg、imagepng
其中繪制類的函數最多,函數格式也很相似,都是:
在圖像的XX坐標,繪制XX東西
復制操作的函數,坐標往往有8個之多。
原圖起點坐標,原圖寬高, 這就四個了;
新圖起點坐標,新圖寬高, 這裡又四個;
再加上原圖,新圖。有十來個參數。
所以,一般圖像處理的過程,往往調試好一個程序之後,都不願意再回頭重新改了。封裝成自定義函數吧。
比如縮略圖函數。
function size_img($img, $width, $height) {
中間你就處理吧。
}
這樣提供一個圖片,指定輸出的大小,就可以生成縮略圖了。至少用起來方便多了。