不懂先生

那些年我们踩的ThinkPHP添加水印坑
序言最近为我写的电脑120信息系统设计了上传图片自动添加水印的功能,最后的效果比较满意,过程也收获满满。需要解决的...
扫描右侧二维码阅读全文
21
2022/04

那些年我们踩的ThinkPHP添加水印坑

序言

最近为我写的电脑120信息系统设计了上传图片自动添加水印的功能,最后的效果比较满意,过程也收获满满。

需要解决的问题

  1. 解决添加图片水印的水印图片大小自适应
  2. 解决添加文字水印的字体大小自适应
  3. 解决图片水印和文字水印自定义位置
  4. 解决IOS图片上传添加水印时图片自动旋转

问题一

图片水印默认的水印图片是固定的,当上传的图片大小与水印图片大小接近或者小于水印图片大小时,添加水印后的水印图片会篡位甚至全覆盖原始图片,解决问题的思路就是想办法获取上传图片的大小,并按照一定的比例对水印图片进行缩放,这里用到ThinkPHP图片处理的thumb()函数,通过

$imgSize    =   getimagesize($_FILES['file']['tmp_name']);
$imgWidth   =   $imgSize[0];
$imgHeight  =   $imgSize[1];

获取上传图片的宽和高,然后打开并修改水印图片尺寸,其中$imgWidth/5代表水印图片尺寸为上传图片的1/5,代码如下:

$water = Image::open('./xxxx/xxxx/logo.png');
                    $water->thumb($imgWidth/5,$imgHeight,\think\Image::THUMB_SCALING)->save('./xxxx/xxxx/newLogo.png');

问题二

该问题原理与问题一相同,只需要将获取到的上传图片的尺寸的宽按照一定比例赋值给文字水印添加的参数即可,代码如下:

text('图片版权归电脑120所有  ','STXINGKA.TTF',$imgWidth/30,'#ffffff',\think\Image::WATER_SOUTHEAST)

问题三

ThinkPHP默认的水印位置为图片的四个顶部,四条边的中间,在我的项目中文字水印需要在右下角,使用默认的\think\Image::WATER_SOUTHEAST,比较难的是图片水印的位置处理,需要的满足的样式为下图:
11076-ysu94twmlpo.png
默认的水印图片的位置只是在右下角,不能满足需求,这里我修改了ThinkPHP处理图片的函数,添加了两个参数,$offsetWidth,$offsetHeight分别为X偏移量,和Y偏移量,水印图片的位置应该与底部间隔两个水印字体大小,而与右边间隔应该刚好到文字水印的中间位置,$imgWidth*0.15,$imgWidth/15两参数通过数学几何计算而来,但是该参数不针对IOS系统,IOS系统与平常系统图片格式不同所以对应参数不同,IOS系统对应的参数为$imgWidth*0.15,$imgWidth/15,代码如下:

//处理图片
$image->water('./xxxx/xxxx/newLogo.png',\think\Image::WATER_SOUTHWEST ,30,$imgWidth*0.18,$imgWidth/15)

ThinkPHPwater函数处理如下:

public function water($source, $locate = self::WATER_SOUTHEAST, $alpha = 100,$offsetWidth,$offsetHeight)
    {
        if (!is_file($source)) {
            throw new ImageException('水印图像不存在');
        }
        //获取水印图像信息
        $info = getimagesize($source);
        if (false === $info || (IMAGETYPE_GIF === $info[2] && empty($info['bits']))) {
            throw new ImageException('非法水印文件');
        }
        //创建水印图像资源
        $fun   = 'imagecreatefrom' . image_type_to_extension($info[2], false);
        $water = $fun($source);
        //设定水印图像的混色模式
        imagealphablending($water, true);
        /* 设定水印位置 */
        switch ($locate) {
            /* 右下角水印 */
            case self::WATER_SOUTHEAST:
                $x = $this->info['width'] - $info[0]-$offsetWidth;
                $y = $this->info['height'] - $info[1]-$offsetHeight;
                break;
            /* 左下角水印 */

问题四

这个问题是比较难的坑了,刚开始只是发现有的添加过水印的图片发生了旋转,但是问题并不知道出在哪里,而且有的翻转了有的没有翻转,翻转也只针对上传图片为竖屏的图片,其他格式图片不发生翻转,最后才发现只有IOS系统上传的竖屏图片添加水印时会发生翻转,针对该问题做了以下处理:

  1. 开启PHP扩展函数exif
  2. 先将图片上传到指定文件夹,再读取图片,利用exif对获取图片的参数,其中利用的参数为"Orientation" ,一般的安卓或是window系统,在上传图片时该参数会默认设为0或1,但是IOS系统不会默认设置,导致上传的竖屏图片宽和长的参数是相反的,而IOS上传竖屏图片对应的"Orientation" 值为6,对应上传的竖屏图片参数如下:
  ["FileName"] => string(36) "xxxx.jpg"
  ["FileDateTime"] => int(1650515493)
  ["FileSize"] => int(2287525)
  ["FileType"] => int(2)
  ["MimeType"] => string(10) "image/jpeg"
  ["SectionsFound"] => string(19) "ANY_TAG, IFD0, EXIF"
  ["COMPUTED"] => array(5) {
    ["html"] => string(26) "width="4032" height="3024""
    ["Height"] => int(3024)
    ["Width"] => int(4032)
    ["IsColor"] => int(1)
    ["ByteOrderMotorola"] => int(1)
  }
  ["Orientation"] => int(6)
  ["Exif_IFD_Pointer"] => int(38)
  ["ColorSpace"] => int(65535)
  ["ExifImageWidth"] => int(4032)
  ["ExifImageLength"] => int(3024)

可以想到,竖屏图片的宽一定是小于高的,但是在获取到的参数中可以看到,宽大于高,虽然展示图片时不会翻转,但是添加水印是会获取该参数,导致图片发生翻转。

  1. 对于"Orientation" 值为3,6,8的图片进行旋转,代码如下:
if(isset($exif) && !empty($exif) && !empty($exif['Orientation'])) {
                        
                        switch ($exif['Orientation']) {
                            case 8:
                                $savename = $savename."-".$imgHeight."-".$imgWidth;
                                Session::set('savename',$savename.".".$savetype);
                                $image->thumb(config('imgfile.width'), config('imgfile.height'))->rotate(90)->save('./xxxx/xxxx/'.Session::get('savename'));
                                break;
                            case 3:
                                $savename = $savename."-".$imgHeight."-".$imgWidth;
                                Session::set('savename',$savename.".".$savetype);
                                $image->thumb(config('imgfile.width'), config('imgfile.height'))->rotate(180)->save('./xxxx/xxxx/'.Session::get('savename'));
                                break;
                            case 6:
                                $savename = $savename."-".$imgHeight."-".$imgWidth;
                                Session::set('savename',$savename.".".$savetype);
                                $image->thumb(config('imgfile.width'), config('imgfile.height'))->rotate(90)->save('./xxxx/xxxx/'.Session::get('savename'));
                                break;
                            default:
                                $savename = $savename."-".$imgWidth."-".$imgHeight;
                                Session::set('savename',$savename.".".$savetype);
                                $image->thumb(config('imgfile.width'), config('imgfile.height'))->save($imgpath);
                        }

最后再运行添加水印的函数:

$image->water('./xxxx/xxxx/newLogo.png',\think\Image::WATER_SOUTHWEST ,30,$imgWidth*0.15,$imgWidth/15)->text('图片版权归电脑120所有  ','STXINGKA.TTF',$imgWidth/30,'#ffffff',\think\Image::WATER_SOUTHEAST)->save('./xxxx/xxxx/'.Session::get('savename'));

大功告成

Last modification:April 21st, 2022 at 05:50 pm

Leave a Comment