接著上一篇。GD庫可以折騰很多用法出來,當然得跟畫圖相關,除了前面的驗證碼、水印外,還可以進行圖片的縮放,裁剪、旋轉等操作,這在很多應用中可以見到。
1. 加水印
前面已經知道,我們可以使用imagechar或者imagestring等將字符或字符串(甚至中文字符)繪制到圖像上,以達到水印的目的,還有個更好的方式,不僅能加字符水印,還能加圖片水印:imagecopy。
原型:bool imagecopy (resource $dst_im , resource $src_im , int $dst_x , int $dst_y , int $src_x , int $src_y , int $src_w , int $src_h),看名字知道這是復制,第1、2個參數分別是目標圖像句柄、源文件句柄,加水印時,如果水印圖片是一張小圖,加在一張大圖上面,那麼第一個參數就是大圖句柄,第二個參數就是小圖句柄。第3、4個參數是水印在目標圖像上的x、y坐標值,第5、6個參數是水印圖片上開始的x、y坐標值,第7、8個參數是水印圖片即將要作為水印的寬和高,因此這個方法的意思就是,將水印圖像src_im上左上角頂點坐標為(src_x, src_y)處,寬和高分別為src_w、src_h的部分復制到圖像dst_im上,再將這個dst_im圖像畫到畫布上保存或輸出,即為加過水印後的圖片了,代碼:
<?php
date_default_timezone_set('Asia/Shanghai');
define('DS', DIRECTORY_SEPARATOR);
// 加水印,文字、圖片水印,以圖片為例
function watermark($srcFile = '', $markFile = '', $dstFile = '')
{
if(!file_exists($srcFile) || !file_exists($markFile))
{
echo 'file not exists!<br/>';
return false;
}
// 獲取原始圖片與水印圖片的寬高
list($srcWidth, $srcHeight) = getimagesize($srcFile);
list($markWidth, $markHeight) = getimagesize($markFile);
// 水印圖片不能比原始圖片像素還大
if($markWidth > $srcWidth || $markHeight > $srcHeight)
{
return false;
}
// 獲取即將被加水印的原始圖片句柄、水印圖片句柄
$dstImg = imagecreatefromjpeg($srcFile);
$markImg = imagecreatefrompng($markFile);
// 加水印的位置,簡單放在右下角
$dst_x = $srcWidth - $markWidth;
$dst_y = $srcHeight - $markHeight;
// 獲取文件信息
$fileinfo = pathinfo($srcFile);
if(empty($dstFile))
{
$dstFile = rtrim($fileinfo['dirname'], DS).DS.'mark_'.$fileinfo['filename'].date('YmdHis').mt_rand(1, 1000).'.jpeg';
}
// 將水印圖片復制到已有圖片上
imagecopy($dstImg, $markImg, $dst_x, $dst_y, 0, 0, $srcWidth, $srcHeight);
// 將新加完水印的圖片保存起來
imagejpeg($dstImg, $dstFile);
imagedestroy($dstImg);
imagedestroy($markImg);
return true;
}
$srcFile = 'G:\wamp\www\html\image\p125.jpg'; // 原圖片
$markFile = 'G:\wamp\www\html\image\ooopic_5.png'; // 水印圖片
watermark($srcFile, $markFile);
效果:
在這裡,簡單將水印圖片放在圖片右下角,所以放在圖片的右下角要一個簡單的計算,調用imagecopy時,從水印圖片的左上角頂點(坐標0,0)開始全部(寬高傳入水印圖片寬高)復制到待加水印圖片上,然後imagejpeg繪制圖像並保存,注意類似imagejpeg(這裡簡單使用它)等繪圖函數傳入第二個參數時是保存圖片為一個文件,而不是輸出到浏覽器,所以也不需調header函數發送頭信息。
當然還要搞清楚哪是源文件(src),哪是目標文件(dst),把一張小圖加水印到一張大圖上時,源文件是小圖水印,把它復制到大圖上,大圖就是目標。
能用圖片作為水印,在於imagecopy的第二個參數是圖像句柄,所以可以從現有圖片來創建一個(如imagecreatefromjpeg),當然也能從現有的字符創建一個字符圖像句柄變量---使用imagecreatefromstring方法,所以這個更通用。
2. 圖片縮放
很多應用,圖片列表是小圖,當你點擊某一個時,才會展現完整大圖,這涉及到一個圖片收縮的處理。有兩個方法可供使用:imagecopyresized和imagecopyresampled,幾乎一樣,不同的是後者對圖片進行重采樣(貌似是我專業的詞),所以成圖質量更好(重采樣的話也得看采取哪種方法,有的會變得更渣),挑一個說:
bool imagecopyresampled ( resource $dst_image , resource $src_image , int $dst_x , int $dst_y , int $src_x , int $src_y , int $dst_w , int $dst_h , int $src_w , int $src_h )
第一、二個參數與上面相似,如何做到縮放?比如這裡,是將原圖像上左上角頂點處,坐標為(src_x, src_y),寬高為src_w、src_h的部分圖片,畫到目標圖像上坐標為(dst_x, dst_y),寬高為dst_w、dst_h的地方,所以如果目標圖片上的寬高比原圖上選取部分的寬高小的話,就成了縮小版了,當然還需要兩個左上角頂點的坐標值相同,以jpg類型為例:
<?php
date_default_timezone_set('Asia/Shanghai');
define('DS', DIRECTORY_SEPARATOR);
// 縮小圖片
/**
* @param src 原圖像路徑
* @param percent 縮小比例
* @param dstFile 保存圖片的路徑
*/
function zoomPic($srcFile = '', $percent = 0.5, $dstFile = '')
{
if(!file_exists($srcFile))
{
return false;
}
list($width, $height) = getimagesize($srcFile); // 獲取寬高
($percent <= 0 || $percent > 1) && $percent = 0.5;
$newWidth = floor($width * $percent); // 縮小後的寬高
$newHeight = floor($height * $percent);
$dstImg = imagecreatetruecolor($newWidth, $newHeight); // 創建新圖像寬高的畫布
$srcImg = imagecreatefromjpeg($srcFile); // 從原圖像文件創建畫布
$pathinfo = pathinfo($srcFile);
if(!$dstFile) $dstFile = rtrim($pathinfo['dirname'], DS).DS.'zoom_'.$pathinfo['filename'].date('YmdHis').mt_rand(1, 1000).".jpeg";
// 從源文件左上角頂點開始進行縮小
//imagecopyresized($dstImg, $srcImg, 0, 0, 0, 0, $newWidth, $newHeight, $width, $height);
imagecopyresampled($dstImg, $srcImg, 0, 0, 0, 0, $newWidth, $newHeight, $width, $height);
// 繪制且保存圖像
imagejpeg($dstImg, $dstFile);
// 銷毀資源
imagedestroy($dstImg);
imagedestroy($srcImg);
return true;
}
// 測試
$srcFile = 'G:\wamp\www\html\image\p179.jpg';
zoomPic($srcFile);
效果:

在這裡,我們可以將原圖與小圖分兩套存放,列表展示小圖,低級查就展示原圖。
3. 圖片裁剪
考慮上面的imagecopyresampled方法,如果不從原圖像的左上角開始,而是左上角偏右下某一點開始,切圖的寬高也再等於源文件完整的寬高,而是部分寬高,那麼新的重采樣的圖片,就是源圖片的一部分,就達到了裁剪的效果,所以裁剪與縮放使用的方法一樣
<?php
date_default_timezone_set('Asia/Shanghai');
define('DS', DIRECTORY_SEPARATOR);
// cut a picture
function cutPic($srcFile = '', $x = 0, $y = 0, $width = 16, $height = 16, $dstFile = '')
{
if(!file_exists($srcFile))
{
return false;
}
list($srcWidth, $srcHeight, $type) = getimagesize($srcFile);
$x < 0 && $x = 0;
$y < 0 && $y = 0;
// 寬高設置
(($width + $x) > $srcWidth) && $width = $srcWidth;
(($height + $y) > $srcHeight) && $height = $srcHeight;
($width <= 0) && $width = $srcWidth;
($height <= 0) && $height = $srcHeight;
$dstImg = imagecreatetruecolor($width, $height); // 目標文件資源
switch($type)
{
case IMG_GIF:
$srcImg = imagecreatefromgif($srcFile); // 獲取源文件資源句柄及擴展名處理,以使用合適的函數和擴展
$ext = 'gif';
$imagefun = 'imagegif';
break;
case IMG_JPG:
$srcImg = imagecreatefromjpeg($srcFile);
$ext = 'jpeg';
$imagefun = 'imagejpeg';
break;
default:
$srcImg = imagecreatefrompng($srcFile);
$ext = 'png';
$imagefun = 'imagepng';
break;
}
// 設置保存剪切後的文件路徑
$fileinfo = pathinfo($srcFile);
if(empty($dstFile))
{
$dstFile = rtrim($fileinfo['dirname'], DS).DS.'cut_'.$fileinfo['filename'].date('YmdHis').mt_rand(1, 1000).".{$ext}";
}
// 執行剪切操作
imagecopyresampled($dstImg, $srcImg, 0, 0, $x, $y, $width, $height, $width, $height);
// 畫於畫布並保存文件
$imagefun($dstImg, $dstFile);
imagedestroy($dstImg);
imagedestroy($srcImg);
return true;
}
// 測試
$srcFile = 'G:\wamp\www\html\image\p221.jpg';
cutPic($srcFile, 50, 50, 50, 50);
效果:

常見的應用是,我們在給自己的某個應用換頭像時,頭像太大,就會用到裁剪,用這就可以做一個模擬實現。
4. 圖片旋轉
圖片旋轉也十分常見,主要用到函數imagerotate,原型:resource imagerotate ( resource $image , float $angle , int $bgd_color [, int $ignore_transparent = 0 ] ),第一個參數是待旋轉圖像句柄,第二個參數angle 是旋轉的角度數值,第三個參數指定一個顏色,即當旋轉後出現空的地方是使用哪種顏色填充,第四個參數是指定一個透明色,默認0表示保留透明色。該方法返回一個新的圖像句柄,就是經過旋轉後的圖像資源變量,將它繪制保存即可。還要注意的是,旋轉的角度可以指定0到360之間,為逆時針旋轉,以jpg為例:
<?php
date_default_timezone_set('Asia/Shanghai');
define('DS', DIRECTORY_SEPARATOR);
/**
* 圖片旋轉
* @param angular 旋轉角度值 0-360
*/
function rotatePic($srcFile = '', $angular = 0, $dstFile = '')
{
if(!file_exists($srcFile))
{
echo 'file not exists<br/>';
return false;
}
$srcImg = imagecreatefromjpeg($srcFile);
// 處理保存文件地址
$fileinfo = pathinfo($srcFile);
if(empty($dstFile))
{
$dstFile = rtrim($fileinfo['dirname'], DS).DS.'rotate_'.$fileinfo['filename'].date('YmdHis').mt_rand(1, 1000).'.jpeg';
}
$white = imagecolorallocate($srcImg, 0xff, 0xff, 0xf1);
// 執行旋轉,注意是逆時針方向
$dstImg = imagerotate($srcImg, $angular, $white);
// 畫到畫布,保存文件
imagejpeg($dstImg, $dstFile);
imagedestroy($dstImg);
imagedestroy($srcImg);
return true;
}
// 測試
$srcFile = 'G:\wamp\www\html\image\p219.jpg';
rotatePic($srcFile, 220);
效果:原圖
旋轉後
5. 圖片翻轉
這個在應用中不那麼常見。所謂翻轉,就是對圖像進行鏡面翻轉,比如以圖片中間豎直線為軸線,左邊換到右邊,右邊換到左邊,對調一下位置,就是左右翻轉。想象一下,以中間豎直線為對稱軸的情況,Y軸像素點不變,X軸上的像素點左右對調,仍可以使用imagecopy方法,對於源文件,在復制到目標圖像時,進行這個操作,以繞Y軸旋轉,jpg類型圖片為例
<?php
// 圖片翻轉
date_default_timezone_set('Asia/Shanghai');
define('DS', DIRECTORY_SEPARATOR);
// 沿Y軸翻轉,x坐標值對調
function turnY($srcFile = '', $dstFile = '')
{
if(!file_exists($srcFile))
{
return false;
}
// 原圖像句柄和寬高獲取
$srcImg = imagecreatefromjpeg($srcFile);
$srcWidth = imagesx($srcImg);
$srcHeight = imagesy($srcImg);
$dstImg = imagecreatetruecolor($srcWidth, $srcHeight);
// 沿Y軸翻轉,x軸上的像素點左右對調
for($i = 0; $i < $srcWidth; $i++)
{
imagecopy($dstImg, $srcImg, $srcWidth-$i-1, 0, $i, 0, 1, $srcHeight);
}
// 畫像保存路徑處理
$fileinfo = pathinfo($srcFile);
if(empty($dstFile))
{
$dstFile = rtrim($fileinfo['dirname'], DS).DS.'turnx_'.$fileinfo['filename'].date('YmdHis').mt_rand(1, 1000).'.jpeg';
}
// 繪制圖像,保存文件
imagejpeg($dstImg, $dstFile);
imagedestroy($dstImg);
imagedestroy($srcImg);
return false;
}
// 測試
$srcFile = 'G:\wamp\www\html\image\p311.jpg';
turnY($srcFile);
效果: 翻轉前
翻轉後 
主要就是for循環那兒,得到源文件的寬度$srcWidth後,如果源文件上坐標是($i, 0)則對應目標圖像上坐標($srcWidth-$i-1, 0),然後將寬度為1個像素,高為源文件整個高度$srcHeight的資源復制過去,循環完成後就全部復制到一個圖片上了,相當於是一條一條線的畫過去的。
無意浏覽手冊感覺被坑,看到imageflip函數猜到是這個功能,一看果然是的,可是看的書已經落後幾年了,原型:bool imageflip ( resource $image , int $mode ),第一個參數是目標圖像資源,第二個參數是翻轉的方式,使用php自帶的枚舉變量即可,有IMG_FLIP_HORIZONTAL(水平)、IMG_FLIP_HORIZONTAL(豎直)、IMG_FLIP_BOTH(水平豎直)三種方式,一個函數即可實現。
反正都挺簡單,不如練練手玩玩 :-D