rabin 4 months ago
commit
7eaccdc095
10 changed files with 1126 additions and 0 deletions
  1. 5 0
      index.php
  2. 16 0
      lib/Tool.php
  3. 228 0
      lib/Tool/Core.php
  4. 277 0
      lib/Tool/Gd.php
  5. 346 0
      lib/Tool/Mg.php
  6. 45 0
      table/crop.php
  7. 42 0
      table/manage/core.php
  8. 28 0
      table/thumb.php
  9. 67 0
      table/water_pic.php
  10. 72 0
      table/water_txt.php

+ 5 - 0
index.php

@@ -0,0 +1,5 @@
+<?php
+define('DEVER_APP_NAME', 'image');
+define('DEVER_APP_LANG', '图片处理');
+define('DEVER_APP_PATH', dirname(__FILE__) . DIRECTORY_SEPARATOR);
+include(DEVER_APP_PATH . '../boot.php');

+ 16 - 0
lib/Tool.php

@@ -0,0 +1,16 @@
+<?php namespace Image\Lib;
+use Dever;
+class Tool
+{
+    public function get($source = '')
+    {
+        if (class_exists('\Imagick')) {
+            $type = 'mg';
+        } else {
+            $type = 'gd';
+        }
+        $tool = 'Image\\Lib\\Tool\\' . ucfirst($type);
+        $tool = new $tool($source);
+        return $tool;
+    }
+}

+ 228 - 0
lib/Tool/Core.php

@@ -0,0 +1,228 @@
+<?php namespace Image\Lib\Tool;
+use Dever;
+class Core
+{
+    protected $im;
+    protected $source;
+    protected $cover = false;
+    public function __construct($source)
+    {
+        if ($source) {
+            $this->source($source);
+        }
+    }
+    public function source($source)
+    {
+        if (is_array($source)) {
+            $this->im = $this->create($source[0], $source[1], 1);
+            $this->source = $source[2] ?? false;
+        } else {
+            $this->im = $this->get($source);
+            $this->source = $source;
+        }
+        return $this;
+    }
+    public function cover($cover)
+    {
+        $this->cover = $cover;
+        return $this;
+    }
+    protected function check($file)
+    {
+        if ($this->cover || !file_exists($file)) {
+            return true;
+        }
+        return false;
+    }
+    protected function getDest($name)
+    {
+        if (!$this->source) {
+            $name = md5($name);
+            $path = array_slice(str_split($name, 2), 0, 3);
+            $dest = implode(DIRECTORY_SEPARATOR, $path) . DIRECTORY_SEPARATOR . $name . '.jpg';
+            return Dever::file('image/' . $dest);
+        } else {
+            return $this->source . '_' . $name . '.jpg';
+        }
+    }
+    public function getXy($set, $source_x, $source_y, $source_w, $source_h)
+    {
+        $offset = explode('_', $set);
+        if (isset($offset[2]) && $offset[2] == 1) {
+            //完全等比例
+            if ($source_x > $offset[0]) {
+                $dest_x = $offset[0];
+                $dest_y = $offset[0]*$source_h;
+            } elseif ($offset[1] > 0 && $source_y > $offset[1]) {
+                $dest_x = $offset[1]*$source_w;
+                $dest_y = $offset[1];
+            } else {
+                $dest_x = $source_x;
+                $dest_y = $source_y;
+            }
+        } elseif (isset($offset[2]) && $offset[2] == 2) {
+            //按照一定比例
+            if ($offset[0] == 0 && $offset[1] > 0) {
+                $dest_x = $offset[1]*$source_w;
+                $dest_y = $offset[1];
+            } elseif ($offset[1] > 0 && $source_x > $source_y && $source_y > $offset[1]) {
+                $dest_x = $offset[1]*$source_w;
+                $dest_y = $offset[1];
+            } elseif ($source_y > $source_x && $source_x > $offset[0]) {
+                $dest_x = $offset[0];
+                $dest_y = $offset[0]*$source_h;
+            } elseif ($source_y == $source_x && $offset[0] == $offset[1]) {
+                $dest_x = $offset[0];
+                $dest_y = $offset[1];
+            } elseif ($source_x > $source_y && $source_y < $offset[1]) {
+                $dest_x = $offset[1]*$source_w;
+                $dest_y = $offset[1];
+            } elseif($source_y > $source_x && $source_x < $offset[0]) {
+                $dest_x = $offset[0];
+                $dest_y = $offset[0]*$source_h;
+            } elseif($source_x > $offset[0]) {
+                $dest_x = $offset[0];
+                $dest_y = $offset[0]*$source_h;
+            } else {
+                $dest_x = $source_x;
+                $dest_y = $source_y;
+            }
+        } elseif (isset($offset[2]) && $offset[2] == 3) {
+            //按照比例缩放,如有多余则留白(或黑...如果实在留不了白的话)
+            $b = $offset[0]/$offset[1];
+            $l = $source_x/$source_y;
+            
+            if ($b > $l) {
+                $dest_x = $offset[1]*$source_w;
+                $dest_y = $offset[1];
+            } else {
+                $dest_x = $offset[0];
+                $dest_y = $offset[0]*$source_h;
+            }
+        } elseif (isset($offset[2]) && $offset[2] == 4) {
+            //按照一定比例
+            if ($offset[0] == 0 && $offset[1] > 0) {
+                $dest_x = $offset[1]*$source_w;
+                $dest_y = $offset[1];
+            } elseif($offset[1] > 0 && $source_x > $source_y && $source_y >= $offset[1]) {
+                $dest_x = $offset[1]*$source_w;
+                $dest_y = $offset[1];
+            } elseif ($source_y > $source_x && $source_x >= $offset[0]) {
+                $dest_x = $offset[0];
+                $dest_y = $offset[0]*$source_h;
+            } elseif ($source_y == $source_x && $offset[0] < $offset[1]) {
+                $dest_x = $offset[1]*$source_w;
+                $dest_y = $offset[1];
+            } elseif ($source_y == $source_x && $offset[0] > $offset[1]) {
+                $dest_x = $offset[0];
+                $dest_y = $offset[0]*$source_h;
+            } elseif ($source_y == $source_x && $offset[0] == $offset[1]) {
+                $dest_x = $offset[0];
+                $dest_y = $offset[1];
+            } elseif ($source_x > $source_y && $source_y < $offset[1]) {
+                $dest_x = $offset[1]*$source_w;
+                $dest_y = $offset[1];
+            } elseif ($source_y > $source_x && $source_x < $offset[0]) {
+                $dest_x = $offset[0];
+                $dest_y = $offset[0]*$source_h;
+            } else {
+                $dest_x = $source_x;
+                $dest_y = $source_y;
+            }
+        } else {
+            //直接放大和缩小
+            $dest_x = $offset[0];
+            $dest_y = $offset[1];
+        }
+        return array($dest_x, $dest_y, $offset);
+    }
+    public function position($source_x, $source_y, $dest_x, $dest_y, $position, $offset = 0)
+    {
+        $left = 0;
+        $top = 0;
+        $state = 1;
+        if ($position && is_array($position)) {
+            $left = $position[0];
+            $top = $position[1];
+        } elseif ($position) {
+            switch ($position) {
+                case 1:
+                    //左上
+                    break;
+                case 2:
+                    //左下
+                    $top = $source_y - $dest_y;
+                    break;
+                case 3:
+                    //右上
+                    $left = $source_x - $dest_x;
+                    break;
+                case 4:
+                    //右下
+                    $left = $source_x - $dest_x;
+                    $top = $source_y - $dest_y;
+                    break;
+                case 5:
+                    //中间
+                    $left = $source_x/2 - $dest_x/2;
+                    $top = $source_y/2 - $dest_y/2;
+                    break;
+                case 6:
+                    //上中
+                    $left = $source_x/2 - $dest_x/2;
+                    break;
+                case 7:
+                    //下中
+                    $left = $source_x/2 - $dest_x/2;
+                    $top = $source_y - $dest_y;
+                    break;
+                case 8:
+                    //左中
+                    $top = $source_y/2 - $dest_y/2;
+                    break;
+                case 9:
+                    //右中
+                    $left = $source_x - $dest_x;
+                    $top = $source_y/2 - $dest_y/2;
+                    break;
+                case 10:
+                    //平铺
+                    $left = -1;
+                    $top = -1;
+                    break;
+                default :
+                    $state = false;
+                    break;
+            }
+        }
+        if ($offset && is_array($offset)) {
+            $left = $left + $offset[0];
+            $top = $top + $offset[1];
+        } else {
+            $left = $left + $offset;
+            $top = $top + $offset;
+        }
+        return array($left, $top, $state);
+    }
+
+    public function autowrap(&$autowrap, $fontsize, $angle, $fontface, $string, $width)
+    {
+        // 这几个变量分别是 字体大小, 角度, 字体名称, 字符串, 预设宽度
+        $content = "";
+        // 将字符串拆分成一个个单字 保存到数组 letter 中
+        for ($i=0;$i<mb_strlen($string);$i++) {
+            $letter[] = mb_substr($string, $i, 1);
+        }
+        foreach ($letter as $l) {
+            $teststr = $content." ".$l;
+            $testbox = imagettfbbox($fontsize, $angle, $fontface, $teststr);
+            // 判断拼接后的字符串是否超过预设的宽度
+            if (($testbox[2] > $width) && ($content !== "")) {
+                $content .= "\n";
+                $autowrap += $fontsize;
+            }
+            $content .= $l;
+        }
+        return $content;
+    }
+}

+ 277 - 0
lib/Tool/Gd.php

@@ -0,0 +1,277 @@
+<?php namespace Image\Lib\Tool;
+use Dever;
+class Gd extends Core
+{
+    # 缩放
+    public function thumb($set)
+    {
+        if (!$this->im) {
+            return false;
+        }
+        $result = array();
+        if (!is_array($set)) {
+            $set = explode(',', $set);
+        }
+        $source_x = imagesx($this->im);
+        $source_y = imagesy($this->im);
+        $source_w = $source_x/$source_y;
+        $source_h = $source_y/$source_x;
+        foreach ($set as $k => $v) {
+            $result[$k] = $this->getDest($v . '_thumb');
+            if ($this->check($result[$k])) {
+                list($dest_x, $dest_y, $offset) = $this->getXy($v, $source_x, $source_y, $source_w, $source_h);
+                $im = $this->copy($this->im, $dest_x, $dest_y, $source_x, $source_y, 0, 0, false, 1);
+                imagejpeg($im, $result[$k]);
+                $this->destroy($im);
+            }
+        }
+        return $result;
+    }
+
+    # 裁剪
+    public function crop($set, $position)
+    {
+        if (!$this->im) {
+            return false;
+        }
+        $result = array();
+        if (!is_array($set)) {
+            $set = explode(',', $set);
+        }
+        $source_x = imagesx($this->im);
+        $source_y = imagesy($this->im);
+        foreach ($set as $k => $v) {
+            $result[$k] = $this->getDest($v . '_crop');
+            if ($this->check($result[$k])) {
+                $x = 0;
+                $y = 0;
+                $offset = explode('_', $v);
+                if (isset($offset[2]) && $offset[2]) {
+                    $offset[0] += $offset[2];
+                    $offset[1] += $offset[2];
+                }
+                if ($position) {
+                    if (!is_array($position)) {
+                        list($x, $y) = $this->position($source_x, $source_y, $offset[0], $offset[1], $position);
+                    } else {
+                        # 加入根据百分比计算裁图
+                        if ($position[0] <= 0) {
+                            $position[0] = $source_x/2 - $offset[0]/2;
+                        } elseif (strstr($position[0], '%')) {
+                            $position[0] = $source_x * intval(str_replace('%', '', $position[0]))/100;
+                        }
+                        if ($position[1] <= 0) {
+                            $position[1] = $source_y/2 - $offset[1]/2;
+                        } elseif (strstr($position[1], '%')) {
+                            $position[1] = $source_y * intval(str_replace('%', '', $position[1]))/100;
+                        }
+                        $x = $position[0];
+                        $y = $position[1];
+                    }
+                } else {
+                    $x = $source_x/2 - $offset[0]/2;
+                    $y = $source_y/2 - $offset[1]/2;
+                }
+                if ($x < 0) {
+                    $x = 0;
+                }
+                if ($y < 0) {
+                    $y = 0;
+                }
+                $im = $this->copy($this->im, $offset[0], $offset[1], $offset[0], $offset[1], $x, $y);
+                imagejpeg($im, $result[$k]);
+                $this->destroy($im);
+            }
+        }
+        return $result;
+    }
+
+    # 图片水印
+    public function pic($water, $position = 5, $offset = 0, $width = 0, $height = 0, $radius = 0)
+    {
+        if (!$this->im) {
+            return false;
+        }
+        $result = $this->getDest('mark');
+        if ($this->check($result)) {
+            if ($radius) {
+                $water = $this->get_radius($water, $radius);
+            } else {
+                $water  = $this->get($water);
+            }
+            $source_x = imagesx($this->im);
+            $source_y = imagesy($this->im);
+            $water_x = imagesx($water);
+            $water_y = imagesy($water);
+            if ($width || $height) {
+                $water_w = $water_x/$water_y;
+                $water_h = $water_y/$water_x;
+                if ($water_x > $width) {
+                    $dest_x = $width;
+                    $dest_y = $width*$water_h;
+                } elseif ($height > 0 && $water_y > $height) {
+                    $dest_x = $height*$water_w;
+                    $dest_y = $height;
+                } else {
+                    $dest_x = $water_x;
+                    $dest_y = $water_y;
+                }
+                $water = $this->copy($water, $dest_x, $dest_y, $water_x, $water_y, 0, 0, false, 2);
+                $xy = $this->position($source_x, $source_y, $dest_x, $dest_y, $position, $offset);
+                $water_x = $dest_x;
+                $water_y = $dest_y;
+            } else {
+                $xy = $this->position($source_x, $source_y, $water_x, $water_y, $position, $offset);
+            }
+            if ($xy[0] == -1) {
+                # 水印平铺 gd的先不做了
+                $xy[0] = $xy[1] = 0;
+            }
+            if ($xy[2] == false) {
+                $this->destroy($water);
+                return;
+            }
+            $im = $this->copy($water, $water_x, $water_y, 0, 0, $xy[0], $xy[1], $this->im);
+            imagejpeg($im, $result);
+            $this->destroy($water);
+        }
+        return $result;
+    }
+
+    # 文字水印
+    public function txt($name, $position = 5, $offset = 0, $size = 10, $color = '', $angle = 0, $width = 0, $font = 'SIMSUN.TTC')
+    {
+        if (!$this->im) {
+            return false;
+        }
+        $result = $this->getDest('txt');
+        if ($this->check($result)) {
+            $autowrap = 0;
+            if ($width > 0) {
+                $name = $this->autowrap($autowrap, $size, $angle, $font, $name, $width);
+            }
+            $position = imagettfbbox($size, $angle, $font, $name);
+            if ($position) {
+                $source_x = imagesx($this->im);
+                $source_y = imagesy($this->im);
+                $water_x = $position[2] - $position[0];
+                $water_y = $position[1] - $position[7];
+                $xy = $this->position($source_x, $source_y, $water_x, $water_y, $position, $offset);
+            }
+            if ($color && (strlen($color)==7)) {
+                $left = $xy[0] ?? 0;
+                $top = $xy[1] ?? 0;
+                $R = hexdec(substr($color,1,2)); 
+                $G = hexdec(substr($color,3,2)); 
+                $B = hexdec(substr($color,5)); 
+                putenv('GDFONTPATH=' . realpath('.'));
+                imagettftext($this->im, $size, $angle, $left, $top + $autowrap, imagecolorallocate($this->im, $R, $G, $B), $font, $name);
+            }
+            imagejpeg($this->im, $result);
+        }
+        return $result;
+    }
+
+    protected function copy($im, $w, $h, $x, $y, $l, $t, $dim = false, $ti = 1)
+    {
+        if ($dim == false) {
+            $dim = $this->create($w, $h, $ti);
+            imagecopyresized($dim, $im, 0, 0, $l, $t, $w, $h, $x, $y);
+        } else {
+            imagecopy($dim, $im, $l, $t, 0, 0, $w, $h);
+            //imagecopyresampled($dim, $im, $l,$t, 0, 0, $w, $h, $x, $y);
+        }
+        return $dim;
+    }
+
+    protected function create($w, $h, $t = 1)
+    {
+        $im = imagecreatetruecolor($w,$h);
+        if ($t == 1) {
+            # 空白背景
+            $wite = ImageColorAllocate($im, 255,255,255);
+            imagefilledrectangle($im, 0, 0, $w, $h, $wite);
+            imagefilledrectangle($im, $w, $h, 0,0, $wite);
+            ImageColorTransparent($im, $wite);
+        } elseif ($t == 2) {
+            # 透明背景
+            imagealphablending($im, false);
+            imagesavealpha($im,true);
+            $transparent = imagecolorallocatealpha($im, 255, 255, 255, 127);
+            imagefilledrectangle($im, 0, 0, $w, $h, $transparent);
+        }
+        return $im;
+    }
+    protected function get($im)
+    {
+        $im = file_get_contents($im);
+        $im = imagecreatefromstring($im);
+        return $im;
+    }
+    # 圆角图片
+    private function get_radius($imgpath = '', $radius = 0)
+    {
+        $ext     = pathinfo($imgpath);
+        $src_img = null;
+        switch ($ext['extension']) {
+        case 'jpg':
+            $src_img = imagecreatefromjpeg($imgpath);
+            break;
+        case 'png':
+            $src_img = imagecreatefrompng($imgpath);
+            break;
+        }
+        $wh = getimagesize($imgpath);
+        $w  = $wh[0];
+        $h  = $wh[1];
+        $radius = $radius <= 0 ? (min($w, $h) / 2) : $radius;
+        $img = imagecreatetruecolor($w, $h);
+        //这一句一定要有
+        imagesavealpha($img, true);
+        //拾取一个完全透明的颜色,最后一个参数127为全透明
+        $bg = imagecolorallocatealpha($img, 255, 255, 255, 127);
+        imagefill($img, 0, 0, $bg);
+        $r = $radius; //圆 角半径
+        for ($x = 0; $x < $w; $x++) {
+            for ($y = 0; $y < $h; $y++) {
+                $rgbColor = imagecolorat($src_img, $x, $y);
+                if (($x >= $radius && $x <= ($w - $radius)) || ($y >= $radius && $y <= ($h - $radius))) {
+                    //不在四角的范围内,直接画
+                    imagesetpixel($img, $x, $y, $rgbColor);
+                } else {
+                    //在四角的范围内选择画
+                    //上左
+                    $y_x = $r; //圆心X坐标
+                    $y_y = $r; //圆心Y坐标
+                    if (((($x - $y_x) * ($x - $y_x) + ($y - $y_y) * ($y - $y_y)) <= ($r * $r))) {
+                        imagesetpixel($img, $x, $y, $rgbColor);
+                    }
+                    //上右
+                    $y_x = $w - $r; //圆心X坐标
+                    $y_y = $r; //圆心Y坐标
+                    if (((($x - $y_x) * ($x - $y_x) + ($y - $y_y) * ($y - $y_y)) <= ($r * $r))) {
+                        imagesetpixel($img, $x, $y, $rgbColor);
+                    }
+                    //下左
+                    $y_x = $r; //圆心X坐标
+                    $y_y = $h - $r; //圆心Y坐标
+                    if (((($x - $y_x) * ($x - $y_x) + ($y - $y_y) * ($y - $y_y)) <= ($r * $r))) {
+                        imagesetpixel($img, $x, $y, $rgbColor);
+                    }
+                    //下右
+                    $y_x = $w - $r; //圆心X坐标
+                    $y_y = $h - $r; //圆心Y坐标
+                    if (((($x - $y_x) * ($x - $y_x) + ($y - $y_y) * ($y - $y_y)) <= ($r * $r))) {
+                        imagesetpixel($img, $x, $y, $rgbColor);
+                    }
+                }
+            }
+        }
+        return $img;
+    }
+    protected function _destroy()
+    {
+        imagedestroy($this->im);
+        $this->im = false;
+    }
+}

+ 346 - 0
lib/Tool/Mg.php

@@ -0,0 +1,346 @@
+<?php namespace Image\Lib\Tool;
+use Dever;
+class Mg extends Core
+{
+    private $imageType = false;
+    private function imageType()
+    {
+        if (!$this->imageType) {
+            $this->imageType = strtolower($this->im->getImageFormat());
+        }
+    }
+
+    # 缩放
+    public function thumb($set)
+    {
+        if (!$this->im) {
+            return false;
+        }
+        $this->imageType();
+        if (!is_array($set)) {
+            $set = explode(',', $set);
+        }
+        $source_x   = $this->im->getImageWidth();
+        $source_y   = $this->im->getImageHeight();
+        $source_w = $source_x/$source_y;
+        $source_h = $source_y/$source_x;
+        foreach ($set as $k => $v) {
+            $result[$k] = $this->getDest($v . '_thumb');
+            if ($this->check($result[$k])) {
+                list($dest_x, $dest_y, $offset) = $this->getXy($v, $source_x, $source_y, $source_w, $source_h);
+                //$this->im = $this->get($this->source);
+                $this->im->thumbnailImage($dest_x, $dest_y);
+                
+                if (isset($offset[2]) && $offset[2] == 3) {
+                    /* 按照缩略图大小创建一个有颜色的图片 */  
+                    $canvas = $this->get();
+                    $color = new \ImagickPixel("white");
+                    $canvas->newImage($offset[0], $offset[1], $color, 'png');
+                    //$canvas->paintfloodfillimage('transparent',2000,NULL,0,0);
+                    /* 计算高度 */
+                    $x = ($offset[0] - $dest_x)/2;
+                    $y = ($offset[1] - $dest_y)/2;
+                    /* 合并图片 */
+                    $canvas->compositeImage($this->im, \Imagick::COMPOSITE_OVER, $x, $y);
+                    $canvas->setCompression(\Imagick::COMPRESSION_JPEG);
+                    $canvas->setCompressionQuality(100);
+                    $canvas->writeImage($result[$k]);
+                    if (isset($offset[3]) && $offset[3]) {
+                        $offset[3] = $offset[3] * 1024;
+                        $size = abs(filesize($result[$k]));
+                        if ($size > $offset[3]) {
+                            $this->compress($canvas, $offset[3], 80, $result[$k]);
+                        }
+                    }
+                    $canvas = false;
+                } else {
+                    //$this->im->setCompression(\Imagick::COMPRESSION_JPEG);
+                    $this->im->setCompressionQuality(90);
+                    if ($this->imageType == 'gif') {
+                        $this->im->writeImages($result[$k], true);
+                    } else {
+                        $this->im->writeImage($result[$k]);
+                    }
+                }
+            }
+        }
+        return $result;
+    }
+
+    public function crop($set, $position)
+    {
+        if (!$this->im) {
+            return false;
+        }
+        $this->imageType();
+        $result = array();
+        if (!is_array($set)) {
+            $set = explode(',', $set);
+        }
+        $source_x   = $this->im->getImageWidth();
+        $source_y   = $this->im->getImageHeight();
+        foreach ($set as $k => $v) {
+            $result[$k] = $this->getDest($v . '_crop');
+            if ($this->check($result[$k])) {
+                $offset = explode('_', $v);
+                if (isset($offset[2]) && $offset[2]) {
+                    $offset[0] += $offset[2];
+                    $offset[1] += $offset[2];
+                }
+                if ($position) {
+                    if (!is_array($position)) {
+                        list($x, $y) = $this->position($source_x, $source_y, $offset[0], $offset[1], $position);
+                    } else {
+                        # 加入根据百分比计算裁图
+                        if ($position[0] <= 0) {
+                            $position[0] = $source_x/2 - $offset[0]/2;
+                        } elseif (strstr($position[0], '%')) {
+                            $position[0] = $source_x * intval(str_replace('%', '', $position[0]))/100;
+                        }
+                        if ($position[1] <= 0) {
+                            $position[1] = $source_y/2 - $offset[1]/2;
+                        } elseif (strstr($position[1], '%')) {
+                            $position[1] = $source_y * intval(str_replace('%', '', $position[1]))/100;
+                        }
+                        $x = $position[0];
+                        $y = $position[1];
+                    }
+                } else {
+                    $x = $source_x/2 - $offset[0]/2;
+                    $y = $source_y/2 - $offset[1]/2;
+                }
+                if ($x < 0) {
+                    $x = 0;
+                }
+                if ($y < 0) {
+                    $y = 0;
+                }
+                if ($this->imageType == 'gif') {
+                    $this->gif($offset[0], $offset[1], $x, $y);
+                } else {  
+                    $this->im->cropImage($offset[0], $offset[1], $x, $y);
+                }
+                
+                if (isset($offset[2]) && $offset[2] == 3 && isset($offset[3]) && $offset[3] > 0) {
+                    $this->im->writeImage($result[$k]);
+                    $offset[3] = $offset[3] * 1024;
+                    $size = abs(filesize($result[$k]));
+                    if ($size > $offset[3]) {
+                        $this->_compress($this->im, $offset[3], 80, $result[$k]);
+                    }
+                } else {
+                    //$this->im->setCompression(\Imagick::COMPRESSION_JPEG); 
+                    $this->im->setCompressionQuality(90);
+                    if ($this->imageType == 'gif') {
+                        $this->im->writeImages($result[$k], true);
+                    } else {
+                        $this->im->writeImage($result[$k]);
+                    }
+                }
+            }
+        }
+        return $result;
+    }
+
+    public function pic($water, $position = 5, $offset = 0, $width = 0, $height = 0, $radius = 0)
+    {
+        if (!$this->im) {
+            return false;
+        }
+        $this->imageType();
+        $result = $this->getDest('mark');
+        if ($this->check($result)) {
+            if ($radius) {
+                $water = $this->get_radius($water, $radius);
+            } else {
+                $water  = $this->get($water);
+            }
+            $draw = new \ImagickDraw();
+            $source_x   = $this->im->getImageWidth();
+            $source_y   = $this->im->getImageHeight();
+            $water_x = $water->getImageWidth();
+            $water_y = $water->getImageHeight();
+            if ($width || $height) {
+                $water_w = $water_x/$water_y;
+                $water_h = $water_y/$water_x;
+
+                if ($water_x > $width) {
+                    $dest_x = $width;
+                    $dest_y = $width*$water_h;
+                } elseif ($height > 0 && $water_y > $height) {
+                    $dest_x = $height*$water_w;
+                    $dest_y = $height;
+                } else {
+                    $dest_x = $water_x;
+                    $dest_y = $water_y;
+                }
+                //$water->thumbnailImage($dest_x, $dest_y);
+                list($x, $y) = $this->position($water_x, $water_y, $width, $height, 5, 0);
+                $water->cropImage($width, $height, $x, $y);
+                $xy = $this->position($source_x, $source_y, $dest_x, $dest_y, $position, $offset);
+                $water_x = $dest_x;
+                $water_y = $dest_y;
+            } else {
+                $xy = $this->position($source_x, $source_y, $water_x, $water_y, $position, $offset);
+            }
+            if ($xy[0] == -1) {
+                # 水印平铺
+                $image = new \Imagick();
+                $image->newImage($source_x, $source_y, new \ImagickPixel('none'));
+                $image->setImageFormat('jpg');
+                $water = $image->textureImage($water);
+                $width = $source_x;
+                $height = $source_y;
+                $xy[0] = $xy[1] = 0;
+            }
+            if ($xy[2] == false) {
+                $this->destroy($water);
+                return;
+            }
+            $draw->composite($water->getImageCompose(), $xy[0], $xy[1], $width, $height, $water);
+            if ($this->imageType == 'gif') {
+                $this->gif(0, 0, 0, 0, $draw);
+            } else {
+                $this->im->drawImage($draw);
+            }
+            $this->im->writeImage($result);
+        }
+        return $result;
+    }
+
+    # 文字水印
+    public function txt($name, $position = 5, $offset = 0, $size = 10, $color = '', $angle = 0, $width = 0, $font = 'SIMSUN.TTC')
+    {
+        if (!$this->im) {
+            return false;
+        }
+        $this->imageType();
+        $result = $this->getDest('txt');
+        if ($this->check($result)) {
+            $autowrap = 0;
+            if ($width > 0) {
+                $name = $this->autowrap($autowrap, $size, $angle, $font, $name, $width);
+            }
+            $draw = new \ImagickDraw();
+            $draw->setFont($font);
+            $position = imagettfbbox($size, $angle, $font, $name);
+            if ($position) {
+                $source_x   = $this->im->getImageWidth();
+                $source_y   = $this->im->getImageHeight();
+                $water_x = $position[2] - $position[0];
+                $water_y = $position[1] - $position[7];
+                $xy = $this->position($source_x, $source_y, $water_x, $water_y, $position, $offset);
+            }
+            
+            if ($size) {
+                $draw->setFontSize($size);
+            }
+            if ($color) {
+                $draw->setFillColor($color);
+            }
+            /*
+            if ($bgcolor) {
+                $draw->setTextUnderColor($bgcolor);
+            }*/
+            $left = $xy[0] ?? 0;
+            $top = $xy[1] ?? 0;
+            $draw->setGravity(\Imagick::GRAVITY_NORTHWEST); 
+            if ($this->imageType == 'gif') {  
+                foreach ($this->im as $frame) {
+                    $frame->annotateImage($draw, $left, $top, $angle, $name);
+                }
+            } else {
+                $this->im->annotateImage($draw, $left, $top + $autowrap, $angle, $name);
+            }
+            $this->_image->writeImage($result);
+        }
+        return $result;
+    }
+
+    protected function gif($w, $h, $x, $y, $d = false, $num = false)
+    {
+        $canvas = $this->get();
+        $canvas->setFormat("gif");
+        $this->im->coalesceImages();
+        $num = $num ? $num : $this->im->getNumberImages();
+        for ($i = 0; $i < $num; $i++) {
+            $this->im->setImageIndex($i);
+            $img = $this->get();
+            $img->readImageBlob($this->im);
+            if ($d != false) {
+                $img->drawImage($d);
+            } else {
+                $img->cropImage($w, $h, $x, $y);
+            }
+            $canvas->addImage($img);
+            $canvas->setImageDelay($img->getImageDelay());
+            if($d == false) $canvas->setImagePage($w, $h, 0, 0);
+            $img->destroy();
+            unset($img);
+        }
+        $this->im->destroy();
+        $this->im = $canvas;
+    }
+
+    protected function compress($canvas, $max, $num, $file)
+    {
+        $num = $num - 10;
+        $temp = $file . '_temp_'.$num.'.jpg';
+        $canvas->setCompressionQuality($num);
+        $canvas->stripImage();
+        $canvas->writeImage($temp);
+        $size = abs(filesize($temp));
+        if ($size > $max && $num > 0) {
+            @unlink($temp);
+            return $this->compress($canvas, $max, $num, $file);
+        } else {
+            $canvas->destroy();
+            @copy($temp, $file);
+            @unlink($temp);
+        }
+    }
+
+    protected function create($w, $h, $t = 1)
+    {
+        $im = new \Imagick();
+        if ($t == 1) {
+            $transparent = new \ImagickPixel('#ffffff');
+        } elseif ($t == 2) {
+            $transparent = new \ImagickPixel('#transparent');
+        }
+        $im->newImage($w, $h, $transparent, 'jpg');
+        return $im;
+    }
+    protected function get($im)
+    {
+        if ($im && strstr($im, 'http')) {
+            $content = file_get_contents($im);
+            $im = new \Imagick();
+            $im->readImageBlob($content);
+        } elseif ($im && is_file($im)) {
+            $im = new \Imagick($im);
+        } else {
+            $im = new \Imagick();
+        }
+        return $im;
+    }
+    protected function get_radius($img = '', $radius = -1)
+    {
+        $image = $this->get($img);
+        $image->setImageFormat('png');
+        if ($radius == -1) {
+            $x = $image->getImageWidth() / 2;
+            $y = $image->getImageHeight() / 2;
+        } else {
+            $x = $image->getImageWidth() - $radius;
+            $y = $image->getImageHeight() - $radius;
+        }
+        $image->roundCorners($x, $y);
+        return $image;
+    }
+    protected function _destroy()
+    {
+        $this->im->destroy();
+        $this->im = false;
+    }
+}

+ 45 - 0
table/crop.php

@@ -0,0 +1,45 @@
+<?php
+return array
+(
+    'name' => '裁剪图',
+    # 数据结构
+    'struct' => array
+    (
+        'name'      => array
+        (
+            'name'      => '配置名称',
+            'type'      => 'varchar(32)',
+        ),
+
+        'position'      => array
+        (
+            'name'      => '裁剪位置',
+            'type'      => 'tinyint(1)',
+            'value' => array
+            (
+                1 => '左上',
+                2 => '左下',
+                3 => '右上',
+                4 => '右下',
+                5 => '居中',
+                6 => '上中',
+                7 => '下中',
+            ),
+            'default' => '1',
+        ),
+
+        'width'     => array
+        (
+            'name'      => '宽度',
+            'type'      => 'varchar(11)',
+            'default'   => '0',
+        ),
+
+        'height'     => array
+        (
+            'name'      => '高度',
+            'type'      => 'varchar(11)',
+            'default'   => '0',
+        ),
+    ),
+);

+ 42 - 0
table/manage/core.php

@@ -0,0 +1,42 @@
+<?php
+return array
+(
+    'menu' => array
+    (
+        'image' => array
+        (
+            'parent' => 'set',
+            'name' => '图片处理',
+            'icon' => 'image-line',
+            'sort' => '120',
+        ),
+        'thumb' => array
+        (
+            'parent'    => 'image',
+            'name'      => '缩略图',
+            'icon'      => 'picture-in-picture-line',
+            'sort'      => '1',
+        ),
+        'crop' => array
+        (
+            'parent'    => 'image',
+            'name'      => '裁剪图',
+            'icon'      => 'crop-line',
+            'sort'      => '2',
+        ),
+        'water_pic' => array
+        (
+            'parent'    => 'image',
+            'name'      => '水印图',
+            'icon'      => 'water-flash-line',
+            'sort'      => '3',
+        ),
+        'water_txt' => array
+        (
+            'parent'    => 'image',
+            'name'      => '水印文字',
+            'icon'      => 'text-direction-l',
+            'sort'      => '4',
+        ),
+    ),
+);

+ 28 - 0
table/thumb.php

@@ -0,0 +1,28 @@
+<?php
+return array
+(
+    'name' => '缩略图',
+    # 数据结构
+    'struct' => array
+    (
+        'name'      => array
+        (
+            'name'      => '配置名称',
+            'type'      => 'varchar(32)',
+        ),
+
+        'width'     => array
+        (
+            'name'      => '宽度',
+            'type'      => 'varchar(11)',
+            'default'   => '0',
+        ),
+
+        'height'     => array
+        (
+            'name'      => '高度',
+            'type'      => 'varchar(11)',
+            'default'   => '0',
+        ),
+    ),
+);

+ 67 - 0
table/water_pic.php

@@ -0,0 +1,67 @@
+<?php
+return array
+(
+    'name' => '水印图',
+    # 数据结构
+    'struct' => array
+    (
+        'name'      => array
+        (
+            'name'      => '配置名称',
+            'type'      => 'varchar(32)',
+        ),
+
+        'position'      => array
+        (
+            'name'      => '水印位置',
+            'type'      => 'tinyint(1)',
+            'value' => array
+            (
+                1 => '左上',
+                2 => '左下',
+                3 => '右上',
+                4 => '右下',
+                5 => '居中',
+                6 => '上中',
+                7 => '下中',
+                8 => '左中',
+                9 => '右中',
+                10 => '平铺',
+            ),
+            'default' => '1',
+        ),
+
+        'offset'     => array
+        (
+            'name'      => '偏移量',
+            'type'      => 'varchar(11)',
+        ),
+
+        'pic'       => array
+        (
+            'name'      => '水印图',
+            'type'      => 'varchar(200)',
+        ),
+
+        'width'     => array
+        (
+            'name'      => '水印图宽度',
+            'type'      => 'varchar(11)',
+            'default'   => '0',
+        ),
+
+        'height'     => array
+        (
+            'name'      => '水印图高度',
+            'type'      => 'varchar(11)',
+            'default'   => '0',
+        ),
+
+        'radius'     => array
+        (
+            'name'      => '圆形弧度',
+            'type'      => 'varchar(11)',
+            'default'   => '0',
+        ),
+    ),
+);

+ 72 - 0
table/water_txt.php

@@ -0,0 +1,72 @@
+<?php
+return array
+(
+    'name' => '水印文字',
+    # 数据结构
+    'struct' => array
+    (
+        'name'      => array
+        (
+            'name'      => '配置名称',
+            'type'      => 'varchar(32)',
+        ),
+
+        'position'      => array
+        (
+            'name'      => '水印位置',
+            'type'      => 'tinyint(1)',
+            'value' => array
+            (
+                1 => '左上',
+                2 => '左下',
+                3 => '右上',
+                4 => '右下',
+                5 => '居中',
+                6 => '上中',
+                7 => '下中',
+                8 => '左中',
+                9 => '右中',
+                10 => '平铺',
+            ),
+            'default' => '1',
+        ),
+
+        'offset'     => array
+        (
+            'name'      => '偏移量',
+            'type'      => 'varchar(11)',
+        ),
+
+        'text'       => array
+        (
+            'name'      => '水印文字',
+            'type'      => 'varchar(200)',
+        ),
+
+        'size'     => array
+        (
+            'name'      => '字体大小',
+            'type'      => 'varchar(11)',
+            'default'   => '12',
+        ),
+
+        'color'     => array
+        (
+            'name'      => '字体颜色',
+            'type'      => 'varchar(11)',
+        ),
+
+        'width'     => array
+        (
+            'name'      => '最大宽度',
+            'type'      => 'varchar(11)',
+            'default'   => '0',
+        ),
+
+        'angle'     => array
+        (
+            'name'      => '角度',
+            'type'      => 'varchar(11)',
+        ),
+    ),
+);