接著上一篇。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