PHP 图像处理与压缩

PHP图像处理虽然不比其他语言性能高,但应付日常来说业务来说是够用的。本类大部分是自己编写其他则参考来自PHP手册的代码。另外,要想正确使用记得要启用GD库。

简单的使用像这样:

        $src= '/path/IMAGE_NAME.jpg';
        $img = new UImage($src);
        
        $path = $img->negate();  // 颜色翻转
        $path = $img->compress(); // 图像压缩
        
        // 第二个参数如果启用的话将会覆盖原图, 其他操作一样
        $img = new UImage($src, true);

注意的是处理后的图像并不会覆盖源文件,重命名的部分可以自行调整代码

setSrc($src);
        $this->cover = $cover;
        return $this;
    }

    /**
     * @param string $src
     * @return $this|bool
     * Author: Great Nomandia
     * Created At 2019/7/31 12:16
     */
    function setSrc($src)
    {
        if (!$src || !is_file($src) || !getimagesize($src)) {
            return false;
        }
        // getimagesize 获取图像的基础信息
        list($this->width, $this->height, $this->type, $this->attr) = getimagesize($this->src = $src);
        $this->extension = image_type_to_extension($this->type, false);
        $this->mimeType = image_type_to_mime_type($this->type);

        // 这里根据扩展名获取相应的处理方法
        $this->createfunc = 'imagecreatefrom' . $this->extension;
        if (!function_exists($this->createfunc)) {
            Yii::error($this->exportfunc . ' not exists', 'api.uimage.createfunc');
            return false;
        }
        $this->exportfunc = 'image' . $this->extension;
        if (!function_exists($this->exportfunc)) {
            Yii::error($this->exportfunc . ' not exists', 'api.uimage.exportfunc');
            return false;
        }
        return $this;
    }

    /**
     * 输出路径
     * @param string $exportPath
     * @param string $suffix
     * @return string
     * Author: Great Nomandia
     * Created At 2019/7/31 18:07
     */
    protected function getExportPath($exportPath = null, $suffix = null)
    {
        // 指定了输出路径直接返回
        if ($exportPath) {
            return $exportPath;
        }
        if ($this->cover) {
            // 覆盖时返回源文件路径
            return $this->src;
        }
        $pathinfo = pathinfo($this->src);
        return $this->exportPath = $pathinfo['dirname'] . DIRECTORY_SEPARATOR . $pathinfo['filename'] . $suffix . '.' . $this->extension;
    }

    /**
     * 翻转图
     * @param string $exportPath
     * @return bool|UImage
     * Author: Great Nomandia
     * Created At 2019/7/31 15:15
     */
    function negate($exportPath = null)
    {
        return $this->process(IMG_FILTER_NEGATE, $exportPath);
    }

    /**
     * 灰度图
     * @param string $exportPath
     * @return bool|UImage
     * Author: Great Nomandia
     * Created At 2019/7/31 15:24
     */
    function grayscale($exportPath = null)
    {
        return $this->process(IMG_FILTER_GRAYSCALE, $exportPath);
    }

    /**
     * 边界图
     * @param string $exportPath
     * @return bool|UImage
     * Author: Great Nomandia
     * Created At 2019/7/31 15:24
     */
    function edgedetect($exportPath = null)
    {
        return $this->process(IMG_FILTER_EDGEDETECT, $exportPath);
    }

    /**
     * 浮雕图
     * @param string $exportPath
     * @return bool|UImage
     * Author: Great Nomandia
     * Created At 2019/7/31 15:24
     */
    function emboss($exportPath = null)
    {
        return $this->process(IMG_FILTER_EMBOSS, $exportPath);
    }

    /**
     * 高斯模糊
     * @param string $exportPath
     * @return bool|UImage
     * Author: Great Nomandia
     * Created At 2019/7/31 15:43
     */
    function gaussianblur($exportPath = null)
    {
        return $this->process(IMG_FILTER_GAUSSIAN_BLUR, $exportPath);
    }

    /**
     * 严选
     * @param string $exportPath
     * @return bool|UImage
     * Author: Great Nomandia
     * Created At 2019/7/31 15:24
     */
    function selective($exportPath = null)
    {
        return $this->process(IMG_FILTER_SELECTIVE_BLUR, $exportPath);
    }

    /**
     * 轮廓图
     * @param string $exportPath
     * @return bool|UImage
     * Author: Great Nomandia
     * Created At 2019/7/31 15:23
     */
    function meanremoval($exportPath = null)
    {
        return $this->process(IMG_FILTER_MEAN_REMOVAL, $exportPath);
    }

    /**
     * 亮度
     * @param string $exportPath
     * @param int $level 0-100
     * @return bool|UImage
     * Author: Great Nomandia
     * Created At 2019/7/31 15:23
     */
    function brightness($exportPath = null, $level = 50)
    {
        return $this->process(IMG_FILTER_BRIGHTNESS, $exportPath, $level);
    }

    /**
     * 对比度
     * @param string $exportPath
     * @param int $level 0-100 越高颜色越少
     * @return bool|UImage
     * Author: Great Nomandia
     * Created At 2019/7/31 15:23
     */
    function contrast($exportPath = null, $level = 30)
    {
        return $this->process(IMG_FILTER_CONTRAST, $exportPath, $level);
    }

    /**
     * 柔化
     * @param string $exportPath
     * @param int $level
     * @return bool|UImage
     * Author: Great Nomandia
     * Created At 2019/7/31 15:23
     */
    function smooth($exportPath = null, $level = 3)
    {
        return $this->process(IMG_FILTER_SMOOTH, $exportPath, $level);
    }

    /**
     * 彩色灰度图
     * @param string $exportPath
     * @param int $red
     * @param int $blue
     * @param int $green
     * @return bool|UImage
     * Author: Great Nomandia
     * Created At 2019/7/31 15:21
     */
    function colorize($exportPath = null, $red = 255, $blue = 0, $green = 0)
    {
        return $this->process(IMG_FILTER_COLORIZE, $exportPath, $red, $blue, $green);
    }

    /**
     * @param string $mark_src
     * @param int $x
     * @param int $y
     * @return $this
     * Author: Great Nomandia
     * Created At 2019/7/31 18:13
     */
    function watermark($mark_src, $x, $y)
    {
        $image = call_user_func($this->createfunc, $this->src);
        list($w, $h, $type, $attr) = getimagesize($mark_src);
        $extension = image_type_to_extension($type, false);

        // 加载水印图
        $marker = call_user_func('imagecreatefrom' . $extension, $mark_src);

        imagecopy($image, $marker, $x, $y, 0, 0, $this->width, $this->height);

        // 注意这里会覆盖原图
        call_user_func($this->exportfunc, $image, $this->getExportPath($this->src, 'WM'));

        imagedestroy($image);
        imagedestroy($marker);

        return $this;
    }

    /**
     * 图片旋转
     * @param int $angle 旋转角度(正数为逆时针旋转 负数为顺时针)
     * @param int $bgd_color 背景颜色
     * @return $this|UImage
     * Author: Great Nomandia
     * Created At 2019/7/31 17:14
     */
    function rotate($angle, $bgd_color = 0, $exportPath = null)
    {
        $image = call_user_func($this->createfunc, $this->src);
        $image = imagerotate($image, $angle, $bgd_color);

        call_user_func($this->exportfunc, $image, $this->getExportPath($exportPath, '.R'));

        imagedestroy($image);

        return $this;
    }

    /**
     * X轴翻转 垂直翻转
     * @param string $exportPath
     * @return UImage
     * Author: Great Nomandia
     * Created At 2019/7/31 18:35
     */
    function flipX($exportPath = null)
    {
        return $this->flip(IMG_FLIP_VERTICAL, $exportPath);
    }

    /**
     * Y轴翻转 水平翻转
     * @param string $exportPath
     * @return mixed
     * Author: Great Nomandia
     * Created At 2019/7/31 18:34
     */
    function flipY($exportPath = null)
    {
        return $this->flip(IMG_FLIP_HORIZONTAL, $exportPath);
    }

    /**
     * 双向翻转
     * @param string $exportPath
     * @return UImage
     * Author: Great Nomandia
     * Created At 2019/7/31 18:34
     */
    function flipBoth($exportPath = null)
    {
        return $this->flip(IMG_FLIP_BOTH, $exportPath);
    }

    /**
     * @param int $mode
     * @param string $exportPath
     * @return $this|UImage
     * Author: Great Nomandia
     * Created At 2019/7/31 17:23
     */
    function flip($mode = IMG_FLIP_HORIZONTAL, $exportPath = null)
    {
        $image = call_user_func($this->createfunc, $this->src);
        imageflip($image, $mode);

        call_user_func($this->exportfunc, $image, $this->getExportPath($exportPath, '.F'));
        imagedestroy($image);
        return $this;
    }

    /**
     * 裁剪图像
     * @param int $dst_x
     * @param int $dst_y
     * @param int $width
     * @param int $height
     * @param int $quality
     * @param bool $no_blank 无留空,即当裁切区域不足以填充新图时也会留空白, true则不会但宽高会被裁剪
     * @param null $exportPath
     * @return string|null
     * Author: Great Nomandia
     * Created At 2019/7/31 16:51
     */
    function cut($dst_x, $dst_y, $width, $height, $quality = 80, $no_blank = false, $exportPath = null)
    {
        if ($no_blank) {
            $width = $this->width - $dst_x > $width ? $width : $this->width - $dst_x;
            $height = $this->height - $dst_y > $height ? $height : $this->height - $dst_y;
        }
        return $this->copy($exportPath, 0, 0, $dst_x, $dst_y, $width, $height, $width, $height, $quality);
    }

    /**
     * 等比缩放
     * @param int $scale
     * @param int $quality
     * @param string $exportPath
     * @return string|null
     * Author: Great Nomandia
     * Created At 2019/7/31 16:42
     */
    function scale($scale = 1.0, $quality = 80, $exportPath = null)
    {
        return $this->copy($exportPath, 0, 0, 0, 0, $this->width * $scale, $this->height * $scale, null, null, $quality);
    }

    /**
     * 重置大小
     * @param int $width
     * @param int $height
     * @param int $quality
     * @param string $exportPath
     * @return string|null
     * Author: Great Nomandia
     * Created At 2019/7/31 16:33
     */
    function resize($width, $height, $quality = 80, $exportPath = null)
    {
        return $this->copy($exportPath, 0, 0, 0, 0, $width, $height, null, null, $quality);
    }

    /**
     * 复制图像
     * @param string $exportPath
     * @param int $dst_x
     * @param int $dst_y
     * @param int $src_x
     * @param int $src_y
     * @param int $dst_width
     * @param int $dst_height
     * @param int $quality
     * @return string|null
     * Author: Great Nomandia
     * Created At 2019/7/31 16:32
     */
    function copy($exportPath = null, $dst_x = 0, $dst_y = 0, $src_x = 0, $src_y = 0, $dst_width = null, $dst_height = null, $src_width = null, $src_height = null, $quality = 70)
    {
        $image = call_user_func($this->createfunc, $this->src);

        $dst_width = $dst_width ?: $this->width;
        $dst_height = $dst_height ?: $this->height;

        $src_width = $src_width ?: $this->width;
        $src_height = $src_height ?: $this->height;

        $thump = function_exists('imagecreatetruecolor') ?
            imagecreatetruecolor($dst_width, $dst_height) :
            imagecreate($dst_width, $dst_height);

        // 注意如果纵横比改变了那图像将被拉伸
        imagecopyresampled($thump, $image, $dst_x, $dst_y, $src_x, $src_y, $dst_width, $dst_height, $src_width, $src_height);

        call_user_func($this->exportfunc, $thump, $this->getExportPath($exportPath, $dst_width . 'x' . $dst_height), $quality);

        imagedestroy($image);
        imagedestroy($thump);
        return $exportPath;
    }

    /**
     * 处理图片
     * @param int $filter
     * @param string $exportPath
     * @return $this|bool
     * Author: Great Nomandia
     * Created At 2019/7/31 14:59
     */
    function process($filter, $exportPath = null)
    {
        if (null === $filter) {
            return false;
        }
        $image = call_user_func($this->createfunc, $this->src);

        switch ($filter) {
            case IMG_FILTER_NEGATE: // 0. 颜色翻转
            case IMG_FILTER_GRAYSCALE: // 1. 灰度图
            case IMG_FILTER_EDGEDETECT: // 5. 边缘图
            case IMG_FILTER_EMBOSS: // 6. 浮雕图
            case IMG_FILTER_GAUSSIAN_BLUR: // 7. 高斯模糊
            case IMG_FILTER_SELECTIVE_BLUR: // 8. 别样模糊
            case IMG_FILTER_MEAN_REMOVAL : // 9. 轮廓图
                imagefilter($image, $filter);
                break;
            case IMG_FILTER_BRIGHTNESS: // 2. 亮度调节
            case IMG_FILTER_CONTRAST: // 3. 对比度
                imagefilter($image, $filter, func_get_arg(2));
                break;
            case IMG_FILTER_SMOOTH: // 10. 柔化
                imagefilter($image, $filter, func_get_arg(2));
                break;
            case IMG_FILTER_COLORIZE: // 4. 指定颜色的灰度图, 参数1=R 2=B 3=G, 值范围0-255
                imagefilter($image, $filter, func_get_arg(2), func_get_arg(3), func_get_arg(4));
                break;
            default:
                // 非有效图像不做处理
                imagedestroy($image);
                return $this;
        }

        call_user_func($this->exportfunc, $image, $this->getExportPath($exportPath, '.' . $filter));

        imagedestroy($image);

        return $this;
    }

    /**
     * 模糊处理
     * @param string $exportPath 输出路径(含文件名)
     * @param int $factor
     * @return $this|bool
     * Author: Great Nomandia
     * Created At 2019/7/31 14:37
     */
    function blur($exportPath = null, $factor = 3)
    {
        if (!$this->createfunc) {
            return false;
        }
        $image = call_user_func($this->createfunc, $this->src);
        $factor = round($factor);

        $originalWidth = imagesx($image);
        $originalHeight = imagesy($image);

        $smallestWidth = ceil($originalWidth * pow(0.5, $factor));
        $smallestHeight = ceil($originalHeight * pow(0.5, $factor));

        // for the first run, the previous image is the original input
        $prevImage = $image;
        $prevWidth = $originalWidth;
        $prevHeight = $originalHeight;

        // scale way down and gradually scale back up, blurring all the way
        for ($i = 0; $i < $factor; $i++) {
            // determine dimensions of next image
            $nextWidth = $smallestWidth * pow(2, $i);
            $nextHeight = $smallestHeight * pow(2, $i);

            // resize previous image to next size
            $nextImage = imagecreatetruecolor($nextWidth, $nextHeight);
            imagecopyresized($nextImage, $prevImage, 0, 0, 0, 0, $nextWidth, $nextHeight, $prevWidth, $prevHeight);

            // apply blur filter
            imagefilter($nextImage, IMG_FILTER_GAUSSIAN_BLUR);

            // now the new image becomes the previous image for the next step
            $prevImage = $nextImage;
            $prevWidth = $nextWidth;
            $prevHeight = $nextHeight;
        }

        // scale back to original size and blur one more time
        imagecopyresized($image, $nextImage, 0, 0, 0, 0, $originalWidth, $originalHeight, $nextWidth, $nextHeight);
        imagefilter($image, IMG_FILTER_GAUSSIAN_BLUR);

        // clean up
        imagedestroy($prevImage);

        call_user_func($this->exportfunc, $image, $this->getExportPath($exportPath, '.B' . $factor));

        imagedestroy($image);

        return $this;
    }

    /**
     * 压缩图像
     * @param float $ratio 保持原图比例(等比缩放)
     * @param int $quality 图片质量 0-100,越大越好
     * @param string $exportPath 保存路径 null 时将覆盖源文件
     * @return string
     * Author: Great Nomandia
     * Created At 2019/7/31 10:38
     */
    function compress($ratio = 1.0, $quality = 60, $exportPath = null)
    {
        // 从SRC中创建一个图像
        if (!$this->createfunc) {
            return false;
        }
        $image = call_user_func($this->createfunc, $this->src);
        if (!$image) {
            // 临时图创建失败
            return false;
        }
        // 临时图的宽高
        $new_height = $this->height * $ratio;
        $new_width = $this->width * $ratio;

        // 创建临时图
        if (function_exists('imagecreatetruecolor')) {
            // 需要GD2支持,老版用imagecreate
            $thump = imagecreatetruecolor($new_width, $new_height);
        } else { // 此方法试过会失真
            $thump = imagecreate($new_width, $new_height);
        }

        // 复制源图像到临时文件
        imagecopyresampled($thump, $image, 0, 0, 0, 0, $new_width, $new_height, $this->width, $this->height);

        // 压缩后的图片的命名,以及回存路径

        // IOS 图片旋转问题
        // 1:0°,6:顺时针90°, 8:逆时针90°,3:180°
        if ((IMAGETYPE_JPEG == $this->type || IMAGETYPE_TIFF_II == $this->type)
            && function_exists('exif_read_data')) {
            // JPEG 或 TIFF 文件中读取 EXIF 头信息, 这里自动处理旋转的照片
            $exif = exif_read_data($this->src);
            if (isset($exif['Orientation'])) {
                switch ($exif['Orientation']) {
                    case 3:
                        $thump = imagerotate($thump, 180, 0);
                        break;
                    case 6:
                        $thump = imagerotate($thump, -90, 0);
                        break;
                    case 8:
                        $thump = imagerotate($thump, 90, 0);
                        break;
                }
            }
        }

        // 生成图片, 注意quality并非所有方法都试用
        // 另外 quality实测高于80时无效果,文件反而更大
        call_user_func($this->exportfunc, $thump, $this->getExportPath($exportPath, '.C'), $quality);

        // 销毁
        imagedestroy($thump);
        imagedestroy($image);

        return $this;
    }
}

你可能感兴趣的:(PHP 图像处理与压缩)