zoukankan      html  css  js  c++  java
  • php 常见图片处理函数封装

    <?php
    /**
     * 常见图像处理函数的封装
     */
    class Image{
        private $info=[];
        private $width;//原始图片宽度
        private $height;//图片原始高度
        private $mime;//图片mime类型 自 PHP 4.3.0 起,getimagesize() 还会返回额外的参数 mime,符合该图像的 MIME 类型
        private $image;//图像资源
        private $format;//图像格式
        private $ratio;//角度
        // 1、打开图片 读取到内存中
        public function __construct($src){
            $this->info=getimagesize($src);
            $this->width=$this->info['0'];
            $this->height=$this->info['1'];
            $this->mime=$this->info['mime'];
            $func=str_replace('/', 'createfrom', $this->mime);
            $filearray=explode(".",$src);
            //end() 将 array 的内部指针移动到最后一个单元并返回其值。  mixed end ( array &$array )
            $this->format=strtolower(end($filearray));//strtolower(end(explode('.', $src))) Only variables should be passed by reference不能连在一起写
            $this->image=$func($src);//返回一图像标识符,代表了从给定的文件名取得的图像。
            $this->ratio=rad2deg(atan2($this->height,$this->width));
                        
        }
        /**
         * [thumb description]
         * 操作图片 压缩
         * @DateTime 2018-07-27T16:10:38+0800
         * @param    [type]                   $width        [图片宽度或者最大宽度]
         * @param    [type]                   $height       [图片高度或者最大高度]
         * @param    boolean                  $flag         [是否等比例缩放]
         * @param    integer                  $scale        [缩放比例为0时不缩放按宽高比]
         * @return   [type]                                 [description]
         */
        public function thumb($width=null,$height=null,$flag=true,$scale=0){
            $ratio=round($this->width/$this->height,2);//宽高比 比值越大图片越扁
            $dstratio=$width&&$height?round($width/$height,2):1;
            // 根据不同的情况计算缩放图的宽高
            if($scale){
                $dst_width=floor($this->width*$scale);
                $dst_height=floor($this->height*$scale);
            }
            if($width&&$height&&!$flag){
                $dst_width=$width;
                $dst_height=$height;
            }
            if(!$scale&&$flag){
                if($ratio>$dstratio){
                    $dst_width=$width;
                    $dst_height=floor($width/$ratio);
                }elseif($ratio<$dstratio){                
                    $dst_width=floor($height*$ratio);
                    $dst_height=$height;
                }else{
                    $dst_width=$width;
                    $dst_height=$height;
                }
            }
             $dst_image=imagecreatetruecolor($dst_width, $dst_height);
              imagealphablending($dst_image , false);//关闭混合模式,以便透明颜色能覆盖原画板
             imagesavealpha($dst_image, true); //设置标记以在保存 PNG 图像时保存完整的 alpha 通道信息(与单一透明色相反)。 要使用本函数,必须将 alphablending 清位(imagealphablending($im, false)        
            imagecopyresampled($dst_image, $this->image, 0, 0, 0, 0, $dst_width, $dst_height, $this->width, $this->height);
             imagedestroy($this->image);
             $this->image= $dst_image;
    
        }
        /**
         * [addTextwatermark description]
         * 给图片加文字水印
         * @DateTime 2018-07-28T17:27:42+0800
         * @param    [mixed]                   $text         [要加的文字多行的话要存成数组]    
         * @param    integer                  $font         [description]
         * @param    integer                  $angle        [description]
         * @param    integer                  $point        [description]
         */
        
        public function addTextwatermark($text,$font=20,$color=[255,255,255,50],$angle=0,$point=9){
            $textcolor=imagecolorallocatealpha($this->image,$color[0],$color[1],$color[2],$color[3]);
            $angle=$angle==false?$this->ratio:$angle;
            $textlength=is_array($text)&&count($text)>1?count($text):1;//多行文字
            $textSize = imagettfbbox($font, $angle, '../fonts/simkai.ttf',$text);
                $textWidth = $textSize[2] - $textSize[1]; //文字的最大宽度
                $textHeight = $textSize[1] - $textSize[7]; //文字的高度
                $lineHeight = $textlength==1?$textHeight:$textHeight + 3; //文字的行高
            //是否可以添加文字水印 只有图片的可以容纳文字水印时才添加
                if ($textWidth + 40 > $this->width || $lineHeight * $textLength + 40 > $this->height) {
                        return false; //图片太小了,无法添加文字水印
                }
                $pointxy=$this->markLocation(array('width'=>$this->width,'height'=>$this->height),array('width'=>$textWidth,'height'=>$lineHeight),$point,$angle);          
            imagettftext($this->image, $font, $angle, $pointxy['x'],$pointxy['y']+$lineHeight*$textlength, $textcolor,'../fonts/simkai.ttf',$text);    
            
        }
        /**
         * [addPicwatermark description]
         * 添加图片水印
         * @DateTime 2018-07-30T09:40:53+0800
         * @param    [string]                   $markimg [水印图片路径]
         * @param    integer                  $point   [水印图所处位置默认为左上角]
         */
        public function addPicwatermark($markimg,$point=1){
            $info=getimagesize($markimg);
            $markWidth=$info[0];
            $markHight=$info[1];
            $func=str_replace('/', 'createfrom', $info['mime']);
            $filearray=explode(".",$markimg);
            $format=strtolower(end($filearray));
            $mark_image=$func($markimg);//返回一图像标识符,代表了从给定的文件名取得的图像。
             imagealphablending($mark_image , false);//关闭混合模式,以便透明颜色能覆盖原画板
             imagesavealpha($mark_image, true);
            $pointxy=$this->markLocation(array('width'=>$this->width,'height'=>$this->height),array('width'=>$markWidth,'height'=>$markWidth),$point,0);
            imagecopy($this->image, $mark_image, $pointxy['x'],$pointxy['y'], 0, 0, $markWidth, $markHight);
             imagedestroy($mark_image);        
        }
        /**
         * [createCircleimg description]
         * 生成圆角png图像
         * @DateTime 2018-07-30T11:21:33+0800
         * @return   [type]                   [description]
         */
        public function createCircleimg(){
            $diameter=$this->width>$this->height?floor($this->height/2)*2:floor($this->width/2)*2;
            $Circleimg=imagecreatetruecolor($diameter, $diameter);
            // imagesavealpha($Circleimg, true);
             $bg=imagecolorallocatealpha($Circleimg, 255, 255, 255, 127);
             if(is_array($border)&&count($border)==3){
                 $border_color=imagecolorallocate($Circleimg, 0, 0, 0);
             }else{
                 //$border_color= imagecolorallocatealpha($Circleimg, 255, 255, 255, 127);
                 $border_color=imagecolorallocate($Circleimg, 0, 0, 0);
             }
            
             imagealphablending($Circleimg , false);
             imagesavealpha($Circleimg, true);
             $r = floor($diameter / 2);
             if($this->width>$this->height ){
                 $plusx=round(($this->width-$this->height)/2);
                 $plusy=0;
             }else{
                 $plusy=round(($this->height-$this->width)/2);
                 $plusx=0;
             }        
                for ($x = 0; $x < $diameter; $x++) {
                        for ($y = 0; $y <$diameter; $y++) {
                            $rgbColor = imagecolorat($this->image, $x+$plusx, $y+$plusy);           
                            if (((($x-$r) * ($x-$r) + ($y-$r) * ($y-$r)) < ($r*$r))) {
                                imagesetpixel($Circleimg, $x, $y, $rgbColor);
                            }else{
                                imagesetpixel($Circleimg, $x, $y, $bg);
                            }
                    }
                }
                 imagedestroy($this->image);
             $this->image= $Circleimg;
             $this->mime='image/png';
             $this->format='png';
        }
        
        /**
         * [markLocation description]
         * 位置函数
         * @DateTime 2018-07-28T17:22:17+0800
         * @param    [array]                   $outerbox [外层容器宽高] array('width'=>'','height'=>'')
         * @param    [array]                   $innerbox [内层容器宽高]array('width'=>'','height'=>'')
         * @param    [int]                   $point    [位置]$point 1、左上角 2,上居中 3,右上角 4、右居中 5,右下角 6,下居中 7,左下角 8,左居中 9、居中
         * @param    [int]                   $angle    [偏移角度]
         * @param    integer                  $padding  [内距]
         * @return   [mixed]                             [成功返回位移数组]
         */
        public function   markLocation($outerbox,$innerbox,$point,$angle,$padding=20){
            
              if(!is_array($outerbox)||!is_array($innerbox)) return false;
              switch($point){
             case 1://左上角
                 $pointLeft = $padding;
                        $pointTop = $padding;
                        break;
                     case 2:
                         $pointLeft=($outerbox['width']-$innerbox['width'])/2;
                         $pointTop = $padding;
                         break;
                     case 3:
                         $pointLeft=$outerbox['width']-$innerbox['width']-$padding;
                         $pointTop = $padding;
                         break;
                      case 4:
                         $pointLeft=$outerbox['width']-$innerbox['width']-$padding;
                         $pointTop = ($outerbox['height']-$innerbox['height'])/2;
                         break;
                    case 5:
                         $pointLeft=$outerbox['width']-$innerbox['width']-$padding;
                         $pointTop = $outerbox['height']-$innerbox['height']-$padding;
                         break;
                     case 6:
                         $pointLeft=($outerbox['width']-$innerbox['width'])/2;
                         $pointTop = $outerbox['height']-$innerbox['height']-$padding;
                         break;
                     case 7://左上角
                 $pointLeft = $padding;
                        $pointTop = $outerbox['height']-$innerbox['height']-$padding;
                        break;
                    case 8:
                                    $pointLeft=$padding;
                                    $pointTop=($outerbox['height']-$innerbox['height'])/2;
                                    break;
                                case 9:
                                     $pointLeft=($outerbox['width']-$innerbox['width'])/2;
                                    $pointTop=($outerbox['height']-$innerbox['height'])/2;
                                    break;
                                    default;
    
            }
            if ($angle != 0) {
                    if ($angle < 90) {
                        //画一下图 根据三角关系得到偏移量
                        $diffTop = ceil(sin($angle * M_PI / 180) * $innerbox['width']);
                        $diffLeft = ceil(sin($angle * M_PI / 180) * $innerbox['height']);
                        if (in_array($point, array(1, 2, 3))) {// 上部 top 值增加
                        $pointTop += ($diffTop-$diffLeft/2);
                        } elseif (in_array($point, array(4, 8, 9))) {// 中部 top 值根据图片总高判断
                        if ($innerbox['width']+$innerbox['heihgt']/2 > ceil($outerbox['height'] / 2)) {
                            $pointTop += ceil(($innerbox['width'] - $outerbox['height'] / 2) / 2);
                            $diagonal=sqrt(pow($this->width,2)+pow($this->height,2))/2;
                            $pointLeft= ($outerbox['width']-ceil(cos($angle * M_PI / 180) *$innerbox['width']))/2;
                            
                    }
                }
            } elseif ($angle > 270) {
                $diffTop = ceil(sin((360 - $angle) * M_PI / 180) * $innerbox['width']);
    
                if (in_array($point, array(1, 2, 3))) {// 上部 top 值增加
                    $pointTop -= $diffTop;
                } elseif (in_array($point, array(4, 8, 9))) {// 中部 top 值根据图片总高判断
                    if ($innerbox['width'] > ceil($outerbox['height'] / 2)) {
                        $pointTop = ceil(($outerbox['height'] - $diffTop) / 2);
                    }
                }
            }
        }
            return array('x'=>intval($pointLeft),'y'=>intval($pointTop));
         }
        /**
         * [outputInBrower description]
         * 把图片在浏览器输出
         * @DateTime 2018-07-27T16:48:33+0800
         * @return   [type]                   [description]
         */
        public function outputInBrower(){
            header('content-type:'.$this->mime);
            $outfunc=str_replace('/', '', $this->mime);
            $outfunc($this->image);
        }
    
        /**
         * [outputAsFile description]
         * 图片保存为文件
         * @DateTime 2018-07-27T17:00:26+0800
         * @param    [string]                   $destionation [图片保存路径]
         * @return   [type]                                 [description]
         */
        public function outputAsFile($destionation=null){
            $outfunc=str_replace('/', '', $this->mime);
             if($destionation&&!file_exists(dirname($destionation))){
                 mkdir(dirname($destionation),0777,true);
                 }
             $randname=md5(uniqid(microtime(true),true));
             //$dstFilename= $destionation==null ? $destionation : $destionation.'/'.$randname.'.'.$this->format;
             $dstFilename= $destionation.'/'.$randname.'.'.$this->format;
            return $outfunc($this->image,$dstFilename);
        }
        public function __destruct(){
            imagedestroy($this->image);
        }
    }
    
    1、生成缩略图函数
    $test=new Image('../images/new3.jpg');
    $test->thumb();
    $test->outputAsFile('../upload');
    

     

     此函数可以按等比例缩放也可以按指定宽高缩放也可以按比例缩放。

    2、加文字水印 可设置水印位置,颜色,旋转角度默认是对顶角

    $test=new Image('../images/new3.jpg');
    $test->addTextwatermark('hello world');
    $test->outputAsFile('../upload');
    

     3、图片水印 默认位置是左上角 addPicwatermark()

    $test=new Image('../images/new3.jpg');
    $test->addPicwatermark('../images/logo.png');
    $test->outputAsFile('../upload');
    

    4、生成圆角图像 做头像createCircleimg

    $test=new Image('../images/new3.jpg');
    $test->createCircleimg();
    $test->outputAsFile('../upload');
    

    总结,圆角函数跟最初设想的是有差别的,设想中是可以加个边,但是实际做的时候由于坐标是不连续的不能取到圆形精准的坐标值,希望以后能找到代替方法。而同样的原因,边缘很不光滑。

  • 相关阅读:
    Visual Studio日志
    选择jQuery的理由
    第三方开发者可将JIT和编译器引入WinRT吗?
    Visual Studio 2012和.NET 4.5已经就绪!
    500TB——Facebook每天收集的数据量
    Netflix开源他们的另一个架构——Eureka
    PhoneGap 2.0 发布
    快速哈希算法破坏了加密的安全性
    Blend for Visual Studio 2012:为Windows 8应用所用的UX工具
    系统中的故障场景建模
  • 原文地址:https://www.cnblogs.com/zaoa/p/9389742.html
Copyright © 2011-2022 走看看