PHP学习之GD库图像处理

配置


header("content-type:text/html;charset=utf-8");
/**
 * GD库提供图像处理功能
 * GD库的配置
 * 1.配置php.ini,开启extension=gd2/php_gd2.dll,两种书写风格都可识别
 * 2.开启extension_dir="ext",这一步是指定扩展目录
 * 3.重启服务器
 * 
 * 检测GD扩展是否已开启
 * 1.phpinfo();
 * 2.extension_loaded('gd')
 * 3.function_exists('gd_info')
 * 4.gd_info()
 * 5.get_defined_functions()
 */
//检测扩展是否已开启
var_dump(extension_loaded('gd'));//bool(true)

//检测函数是否可以使用
var_dump(function_exists('gd_info'));//bool(true)

//得到gd库信息
var_dump(gd_info());

//得到所有已定义的函数,在其中找gd相关函数
print_r(get_defined_functions());

绘图基本步骤


//1.创建画布:imagecreatetruecolor($width, $height)
$image = imagecreatetruecolor(500, 300);

//2.创建颜色:imagecolorallocate($image, $red, $green, $blue)
$red = imagecolorallocate($image, 255, 0, 0);
$blue = imagecolorallocate($image, 0, 0, 255);

//3.绘画:imagechar()水平绘制一个字符;imagecharup()垂直绘制一个字符;imagestring()水平绘制字符串
//imagechar($image, $font, $x, $y, $char, $color),其他函数同理
imagechar($image, 5, 30, 50, 'H', $red);
imagestring($image, 18, 100, 120, 'still', $blue);//18不生效,字号最大到5

//4.输出
//4.1告诉浏览器以图片的形式显示:加一个header(),image/jpeg、image/gif、image/png
header("content-type:image/png");
//4.2输出图像:imagejpeg($image);或imagepng()、imagegif()
imagepng($image);//输出到浏览器
imagepng($image, 'images/demo.png');//保存文件

//5.销毁图像
imagedestroy($image);

美化图像

/**
 * 1.画布默认黑色,修改为白色
 * 2.字体自定义
 */
//创建随机颜色
$randColor = imagecolorallocate($image, mt_rand(0,255), mt_rand(0,255), mt_rand(0,255));

//imagefilledrectangle()绘制填充矩形
imagefilledrectangle($image, 0, 0, 500, 500, $white);

//imagettftext($image,$size,$angle,$x,$y,$color, $fontfile, $text)用TrueType字体向图像写入文本
//$x和$y定义字符的左下角,$y是基线位置
//在测试中发现fontfile写绝对路径才会生效
imagettftext($image, 28, 30, 50, 280, $randColor, 'C:\study\gd\fonts\consola.ttf', 'This is a show');
imagettftext($image, 22, 0, 300, 120, $randColor, 'C:\website-study\gd\PALSCRI.TTF', 'HanyStill');

验证码绘制案例

生成验证码【字符串函数】

/**
 * range(0,9)生成包含0-9的数组
 * array_rand(array, num)从数组中取出多个随机单元的key值
 * implode([glue],array) [用glue]将一维数组的值连接为字符串,别名join
 * array_merge(array...)合并一个或多个数组
 * array_flip(array) 交换数组中的key和value
 * explode(delimiter,string) 用delimiter分割string,返回数组
 */
switch ($type) { //type取值 1.数字 2.字母 3.数字+字母 4.汉字
    case 1:
        $code = implode(array_rand(range(0, 9), $length));
        break;
    case 2:
    	$arr = array_flip(array_merge(range('a', 'z'), range('A', 'Z'));//键值为a-Z的数组
        $code = implode(array_rand($arr, $length));
        break;
    case 3:
    	$arr = array_flip(array_merge(range(0, 9), range('a', 'z'), range('A', 'Z'));
        $code = implode(array_rand($arr, $length));
        break;
    case 4:
        $str = "在,中,国,共,产,党,的,领,导,下,人,民,生,活,会,更,加,美,好,因,为,力,量,拧,成,一,股,绳,
        困,难,和,险,阻,也,击,垮,不,了,我,们,最,后,衷,心,祝,愿,祖,国,繁,荣,昌,盛";
        $code = implode(array_rand(array_flip(explode(',', $str)), $length));
        break;
    default:
    	//exit()输出一个消息并退出当前脚本
        exit('非法参数');
        break;
}

绘制验证码

//imagefontwidth(size)|imagefontheight(size) 得到字体的宽高(字体最大为28),用于计算$x,$y
$textwidth = imagefontwidth(28);//9
$textheight = imagefontheight(28);//15
for($i=0; $i<$length; $i++){//$length 验证码长度
    $size = mt_rand(20,28);
    $angle = mt_rand(-15, 15);
    $x = 15+45*$i+mt_rand(0,36);//计算得到宽度范围
    $y = $textheight/1.5;
	//mb_substr($string, $start, $length, $encoding) 获取多字节字符串的部分
    $text = mb_substr($string, $i, 1, 'utf-8');
    imagettftext($image, $size, $angle, $x, $y, getRandColor($image), $fontFile, $text);
}

给验证码添加干扰元素

//添加像素当作干扰元素:imagesetpixel($image, $x, $y, $color)
for($i=0; $i<50; $i++){
    imagesetpixel($image, mt_rand(0,$width), mt_rand(0,$height), getRandColor($image));
}
//绘制线段当作干扰元素:imageline($image, $x1, $y1, $x2, $y2, $color)
for($i=0; $i<3; $i++){
    imageline($image, mt_rand(0,$width), mt_rand(0,$height), 
    mt_rand(0,$width), mt_rand(0,$height), getRandColor($image));
}
//绘制椭圆弧:imagearc($image, $cx, $cy, $width, $height, $start, $end, $color) 
//$cx/$cy是原点,$width/$height是椭圆的宽高,$start/$end是起始角度和结束角度
for($i=0; $i<3; $i++){
    imagearc($image, mt_rand(0,$width), mt_rand(0,$height), 
    mt_rand(0, $width/2), mt_rand(0, $height/2), 
    mt_rand(0,360), mt_rand(0, 360), getRandColor($image));
}

综合以上,封装验证码类


Class Captcha{
    private $_fontfile = '';
    private $_size = 20;
    private $_width = 300;
    private $_height = 50;
    private $_length = 6;
    private $_image = null;
    private $_snow = 0;//雪花数量
    private $_pixel = 0;//像素数量
    private $_line = 0;//线段数量
    /**
     * 初始化数据
     */
    public function __construct($config=array()){
        if(is_array($config) && count($config)>0){
            //检测文件是否存在并且可读
            if(isset($config['fontfile']) && is_file($config['fontfile']) && is_readable($config['fontfile'])){
                $this->_fontfile = $config['fontfile'];
            }else{
                return false;
            }
            //检测是否设置字体大小
            if(isset($config['size']) && $config['size']>0){
                $this->_size = $config['size'];
            }
            //检测是否设置画布的宽和高
            if(isset($config['width']) && $config['width']>0){
                $this->_width = $config['width'];
            }
            if(isset($config['height']) && $config['height']>0){
                $this->_height = $config['height'];
            }
            //检测是否设置验证码的长度
            if(isset($config['length']) && $config['length']>0){
                $this->_length = $config['length'];
            }
            //检测是否设置干扰元素
            if(isset($config['snow']) && $config['snow']>0){
                $this->_snow = (int)$config['snow'];
            }
            if(isset($config['pixel']) && $config['pixel']>0){
                $this->_pixel = (int)$config['pixel'];
            }
            if(isset($config['line']) && $config['line']>0){
                $this->_line = (int)$config['line'];
            }

            //创建画布资源
            $this->_image = imagecreatetruecolor($this->_width, $this->_height);
            return $this->_image;
        }else{
            return false;
        }
    }
    /**
     * 得到验证码
     */
    public function getCaptcha(){
        //填充矩形
        $white = imagecolorallocate($this->_image, 255, 255, 255);
        imagefilledrectangle($this->_image, 0, 0, $this->_width, $this->_height, $white);
        //生成验证码
        $code = $this->_generateStr($this->_length);
        if(false===$code){
            return false;
        }
        //绘制验证码
        for($i=0; $i<$this->_length; $i++){
            $angle = rand(-15, 15);
            $x = ceil($this->_width/$this->_length * $i);
            $y = ceil($this->_height/1.5);//ceil(num)向上取整
            //$text = mb_substr($code, $i, 1, 'utf-8');//针对中文截取
            $text = $code[$i];
            imagettftext($this->_image, $this->_size, $angle, $x, $y, $this->_getRandColor(), $this->_fontfile, $text);
        }
        //绘制干扰元素
        if($this->_snow){
            $this->_getSnow();
        }else{
            if($this->_pixel){
                $this->_getPixel();
            }
            if($this->_line){
                $this->_getLine();
            }
        }

        //输出
        header('content-type:image/png');
        imagepng($this->_image);
        imagedestroy($this->_image);
        return strtolower($code);
    }
    /**
     * 产生验证码字符
     * @param int $length 验证码字符长度
     */
    private function _generateStr($length = 4){
        if($length<1 || $length>10){
            return false;
        }
        $chars = array(
            'a','b','c','d','e','f','g','h','j','k','m','n','p','q','r','s','t','y',
            'A','B','C','D','E','F','G','H','J','K','M','N','P','Q','R','S','T','Y',
            1,2,3,4,5,6,7,8,9
        );
        $str = implode(array_rand(array_flip($chars), $length));
        return $str;
    }
    /**
     * 产生随机颜色
     */
    private function _getRandColor(){
        return imagecolorallocate($this->_image, mt_rand(0,255), mt_rand(0,255), mt_rand(0,255));
    }

    /**
     * 产生雪花
     */
    private function _getSnow(){
        for($i=0; $i<$this->_snow; $i++){
            imagestring($this->_image, mt_rand(1,5), mt_rand(0,$this->_width), mt_rand(0, $this->_height),
            '*', $this->_getRandColor());
        }
    }

    /**
     * 产生像素
     */
    private function _getPixel(){
        for($i=0; $i<$this->_pixel; $i++){
            imagesetpixel($this->_image, mt_rand(0,$this->_width), mt_rand(0,$this->_height), $this->_getRandColor());
        }
    }

    /**
     * 产生线段
     */
    private function _getLine(){
        for($i=0; $i<$this->_line; $i++){
            imageline($this->_image, mt_rand(0,$this->_width), mt_rand(0,$this->_height), 
            mt_rand(0,$this->_width), mt_rand(0,$this->_height), $this->_getRandColor());
        }
    }
}

缩略图案例

缩略图的简单实现


$filename = 'images\code.png';
//getimagesize(filename)得到图片大小,会识别是否是真正的图片,如果是则返回数组,不是返回false
//返回值是一个数组 {[0]=>width [1]=>height [2]=>mark [3]=>string [mime]=>mime}
//[2]mark为图像类型标记 1=GIF 2=JPG 3=PNG
//[3]string为文本字符串,内容为 height="yyy" width="xxx"
//[mime]为字符串,内容为 image/png | image/jpeg | image/gif 等
$imageInfo = getimagesize($filename);
//list(var)把数组中的值赋给一些变量
list($src_width, $src_height) = $imageInfo;
//创建一个100x100的缩略图
$dst_width = 100;
$dst_height = 100;
//创建目标画布资源
$dst_image = imagecreatetruecolor($dst_width, $dst_height);
//通过图片文件创建原画布资源
//imagecreatefrompng()|imagecreatefromjpeg()|imagecreatefromgif()
$src_image = imagecreatefrompng($filename);
$dst_x = 0;
$dst_y = 0;//目标起始坐标点
$src_x = 0;
$src_y = 0;//源起始坐标点
//imagecopyresampled()拷贝图像并调整大小
imagecopyresampled($dst_image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $dst_width, $dst_height, $src_width, $src_height);
//以png格式将图像输出到文件
imagepng($dst_image, 'images/thumb_100x100.jpg');
imagedestroy($src_image);
imagedestroy($dst_image);

优化缩略图操作

1.获取文件操作优化

/**
 * 获取图像文件信息,包括宽高/创建函数/输出函数/扩展名
 */
function getImageInfo($filename){
    if(!$info = getimagesize($filename)){
        exit('文件不是真实图片');
    }
    $fileInfo['width'] = $info[0];
    $fileInfo['height'] = $info[1];
    //image_type_to_mime_type() 根据图像类型返回mime类型
    $mime = image_type_to_mime_type($info[2]);//比如$mime='image/jpeg'
    $createFun = str_replace('/','createfrom', $mime);
    $outFun = str_replace('/', '', $mime);
    $fileInfo['createFun'] = $createFun;
    $fileInfo['outFun'] = $outFun;
    //image_type_to_extension(type,dot)取得图像类型的文件后缀,dot指是否在后缀前加点,默认为true
    $ext = image_type_to_extension($info[2]);//比如$ext='.jpg'
    $fileInfo['ext'] = strtolower($ext);
    return $fileInfo;
}

2.形成缩略图操作优化

/**
 * @description: 形成缩略图的函数
 * @param $file 图像文件
 * @param $dest 缩略图的保存路径
 * @param $pre 缩略图文件名前缀
 * @param $delSource 是否删除源文件
 * @param $scale 缩放比例
 * @param $dst_width 最大宽度
 * @param $dst_height 最大高度
 * @return 最终保存路径和文件名
 */
function thumb($file, $dest='thumb', $pre='thumb_', $delSource=false, $scale=0.5, $dst_width=null, $dst_height=null){
    $fileInfo = getImageInfo($file);
    $src_width = $fileInfo['width'];
    $src_height = $fileInfo['height'];
    //如果指定最大宽高,则等比例缩放
    //is_numeric(var)检测变量是否为数字或数字字符串
    if (is_numeric($dst_width) && is_numeric($dst_height)) {
        //宽高等比缩放算法
        $ratio = $src_width / $src_height;
        if ($dst_width / $dst_height > $ratio) {
            $dst_width = $dst_width * $ratio;
        } else {
            $dst_height = $dst_width / $ratio;
        }
    } else { //不指定最大宽高按照默认比例缩放
        $dst_width = ceil($src_width * $scale);
        $dst_height = ceil($src_height * $scale);
    }

    $src_image = $fileInfo['createFun']($file);
    $dst_image = imagecreatetruecolor($dst_width, $dst_height);
    imagecopyresampled($dst_image, $src_image, 0, 0, 0, 0, $dst_width, $dst_height, $src_width, $src_height);

    //检测目标目录是否存在,不存在则创建
    if ($dest && !file_exists($dest)) {
        //mkdir(pathname[,mode,recursive])新建一个由pathname指定的目录
        //mode指定访问权限,默认0777,意为最大可能的访问权限,在windows下不生效
        //recursive adj.递归的 是否允许创建嵌套目录,默认false
        mkdir($dest);
    }

    $randNum = mt_rand(100000, 999999);
    $dstName = "{$pre}{$randNum}" . $fileInfo['ext']; //图片名称 例如thumb_121212.jpg
    $destination = $dest ? $dest . '/' . $dstName : $dstName; //保存路径 destination n.目标,目的地
    $fileInfo['outFun']($dst_image, $destination);

    if($delSource){
        //unlink(file)删除文件
        unlink($file);
    }
    imagedestroy($dst_image);
    imagedestroy($src_image);
    return $destination;
}

给图片添加水印案例

文字水印

/**
 * @description: 给指定图片添加文字水印
 * @param $filename 图像文件
 * @param $fontfile 水印字体文件
 * @param $text 水印内容
 * @param $dest 水印图片保存位置
 * @param $pre 水印图文件名前缀
 * @param $delSource 是否删除源文件
 * @param $red 水印颜色红色分量
 * @param $green 水印颜色绿色分量
 * @param $blue 水印颜色蓝色分量
 * @param $alpha 水印透明度
 * @param $size 字体大小
 * @param $angle 字体倾斜角度
 * @param $x 水印位置x坐标,x和y定义了字符的左下角
 * @param $y 水印位置y坐标
 * @return 水印图保存路径和名称
 */
function getWaterText($filename, $fontfile, $text='watermark', $dest='watermark', $pre='waterText_', $delSource=false,
    $red=255, $green=0, $blue=0, $alpha=100, $size=30, $angle=0, $x=0, $y=30){
    $fileInfo = getImageInfo($filename);
    $image = $fileInfo['createFun']($filename);
    //imagecolorallocatealpha($image, red, green, blue, $alpha) 为一幅图像分配颜色和透明度
    //alpha取值范围(0,127),0表示完全不透明,127表示完全透明
    $color = imagecolorallocatealpha($image, $red, $green, $blue, $alpha);
    imagettftext($image, $size, $angle, $x, $y, $color, $fontfile, $text);

    if($dest && !file_exists($dest)){
        mkdir($dest);
    }
    $randNum = mt_rand(100000, 999999);
    $dstName = "{$pre}{$randNum}".$fileInfo['ext'];
    $destination = $dest ? $dest.'/'.$dstName : $dstName;
    $fileInfo['outFun']($image, $destination);

    if($delSource){
        unlink($filename);
    }

    imagedestroy($image);
    return $destination;
}

图片水印

/**
 * @description: 给指定图像添加图片水印
 * @param $dstFile 要添加水印的图片文件
 * @param $srcFile 水印文件
 * @param $position 水印位置
 * @param $pct 水印和图片的融合程度
 * @param $pre 水印图的文件名前缀
 * @param $dest 水印图的保存路径
 * @param $delSource 是否删除源文件
 * @return 水印图的保存路径和文件名
 */
function getWaterPic($dstFile, $srcFile, $position=0, $pct=50, $pre='waterPic_', $dest='watermark', $delSource=false){
    $dstInfo = getImageInfo($dstFile);
    $srcInfo = getImageInfo($srcFile);
    $dst_image = $dstInfo['createFun']($dstFile);
    $src_image = $srcInfo['createFun']($srcFile);
    $dst_width = $dstInfo['width'];
    $dst_height = $dstInfo['height'];
    $src_width = $srcInfo['width'];
    $src_height = $srcInfo['height'];
    switch ($position) {
        case 0://左上
            $x = 0;
            $y = 0;
            break;
        case 1://中上
            $x = ($dst_width - $src_width)/2;
            $y = 0;
            break;
        case 2://右上
            $x = $dst_width - $src_width;
            $y = 0;
            break;
        case 3://左中
            $x = 0;
            $y = ($dst_height - $src_height)/2;
            break;
        case 4://居中
            $x = ($dst_width - $src_width)/2;
            $y = ($dst_height - $src_height)/2;
            break;
        case 5://右中
            $x = $dst_width - $src_width;
            $y = ($dst_height - $src_height)/2;
            break;
        case 6://左下
            $x = 0;
            $y = $dst_height - $src_height;
            break;
        case 7://中下
            $x = ($dst_width - $src_width)/2;
            $y = $dst_height - $src_height;
            break;
        case 8://右下
            $x = $dst_width - $src_width;
            $y = $dst_height - $src_height;
            break;
        default:
            $x = 0;
            $y = 0;
            break;
    }
    //imagecopymerge($dst_image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $src_width, $src_height, $pct);
    //拷贝并合并图像的一部分 pct决定合并程度,范围(0,100),100表示完全不融合,0表示完全融合,源图透明
    imagecopymerge($dst_image, $src_image, $x, $y, 0, 0, $src_width, $src_height, $pct);

    if($dest && !file_exists($dest)){}
    $randNum = mt_rand(100000, 999999);
    $dstName = "{$pre}{$randNum}".$dstInfo['ext'];
    $destination = $dest ? $dest.'/'.$dstName : $dstName;
    $dstInfo['outFun']($dst_image, $destination);

    if($delSource){
        unlink($dstFile);
    }

    imagedestroy($dst_image);
    imagedestroy($src_image);
    return $destination;
}

你可能感兴趣的:(php,学习,图像处理)