• GD库使用小结---2


      接着上一篇。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:wampwwwhtmlimagep125.jpg';  // 原图片
        $markFile = 'G:wampwwwhtmlimageooopic_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:wampwwwhtmlimagep179.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:wampwwwhtmlimagep221.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:wampwwwhtmlimagep219.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:wampwwwhtmlimagep311.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

  • 相关阅读:
    《程序员代码面试指南》第八章 数组和矩阵问题 数组排序之后相邻数的最大差值
    《程序员代码面试指南》第八章 数组和矩阵问题 数组中未出现的最小正整数
    《程序员代码面试指南》第八章 数组和矩阵问题 数组的partition 调整
    《程序员代码面试指南》第八章 数组和矩阵问题 不包含本位置值的累乘数组
    《程序员代码面试指南》第八章 数组和矩阵问题 打印N 个数组整体最大的Top K
    《程序员代码面试指南》第八章 数组和矩阵问题 数组中子数组的最大累乘积
    《程序员代码面试指南》第八章 数组和矩阵问题 在数组中找到一个局部最小的位置
    《程序员代码面试指南》第八章 数组和矩阵问题 子矩阵的最大累加和问题
    MySQL 进阶4 SQL常见函数: 字符函数/数学函数/日期函数/流程控制函数(if/case)
    MySQL 进阶3 排序查询
  • 原文地址:https://www.cnblogs.com/lazycat-cz/p/4463753.html
Copyright © 2020-2023  润新知