PHP 圖像處理與壓縮

PHP圖像處理雖然不比其他語言性能高,但應(yīng)付日常來說業(yè)務(wù)來說是夠用的衣摩。本類大部分是自己編寫其他則參考來自PHP手冊的代碼昂验。另外,要想正確使用記得要啟用GD庫艾扮。

簡單的使用像這樣:

        $src= '/path/IMAGE_NAME.jpg';
        $img = new UImage($src);
        
        $path = $img->negate();  // 顏色翻轉(zhuǎn)
        $path = $img->compress(); // 圖像壓縮
        
        // 第二個參數(shù)如果啟用的話將會覆蓋原圖, 其他操作一樣
        $img = new UImage($src, true);

注意的是處理后的圖像并不會覆蓋源文件既琴,重命名的部分可以自行調(diào)整代碼

<?php

/**
 * YCZ - UImage
 * present by YCZ
 * Author: Nomandia
 * Date: 2019/7/31 10:40
 */
class UImage
{
    /**
     * @var int 圖片寬
     */
    public $width = 0;

    /**
     * @var int 圖片高
     */
    public $height = 0;

    /**
     * @var int 圖片類型
     */
    public $type;

    /**
     * @var string 圖片擴展名
     */
    public $extension;

    /**
     * @var string 圖片MimeType
     */
    public $mimeType;

    /**
     * @var array 圖片屬性
     */
    public $attr;

    /**
     * @var string 原始圖像地址
     */
    public $src;

    /**
     * @var string 創(chuàng)建臨時圖像的方法
     */
    public $createfunc;

    /**
     * @var string 輸出圖像的方法
     */
    public $exportfunc;

    /**
     * @var bool 是否處理后覆蓋原圖
     */
    public $cover = false;

    /**
     * @var string 輸出路徑
     */
    public $exportPath;

    /**
     * UImage constructor.
     * @param string $src
     * @param bool $cover
     * @return $this
     */
    function __construct($src = null, $cover = false)
    {
        $this->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 獲取圖像的基礎(chǔ)信息
        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);

        // 這里根據(jù)擴展名獲取相應(yīng)的處理方法
        $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;
    }

    /**
     * 翻轉(zhuǎn)圖
     * @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;
    }

    /**
     * 圖片旋轉(zhuǎn)
     * @param int $angle 旋轉(zhuǎn)角度(正數(shù)為逆時針旋轉(zhuǎn) 負數(shù)為順時針)
     * @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軸翻轉(zhuǎn) 垂直翻轉(zhuǎn)
     * @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軸翻轉(zhuǎn) 水平翻轉(zhuǎn)
     * @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);
    }

    /**
     * 雙向翻轉(zhuǎn)
     * @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 無留空,即當裁切區(qū)域不足以填充新圖時也會留空白, 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. 顏色翻轉(zhuǎn)
            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. 亮度調(diào)節(jié)
            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. 指定顏色的灰度圖泡嘴, 參數(shù)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 圖片質(zhì)量 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中創(chuàng)建一個圖像
        if (!$this->createfunc) {
            return false;
        }
        $image = call_user_func($this->createfunc, $this->src);
        if (!$image) {
            // 臨時圖創(chuàng)建失敗
            return false;
        }
        // 臨時圖的寬高
        $new_height = $this->height * $ratio;
        $new_width = $this->width * $ratio;

        // 創(chuàng)建臨時圖
        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 圖片旋轉(zhuǎn)問題
        // 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 頭信息, 這里自動處理旋轉(zhuǎn)的照片
            $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;
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市抛虫,隨后出現(xiàn)的幾起案子松靡,更是在濱河造成了極大的恐慌,老刑警劉巖建椰,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件雕欺,死亡現(xiàn)場離奇詭異,居然都是意外死亡棉姐,警方通過查閱死者的電腦和手機屠列,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來伞矩,“玉大人笛洛,你說我怎么就攤上這事∨び酰” “怎么了撞蜂?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵盲镶,是天一觀的道長。 經(jīng)常有香客問我蝌诡,道長溉贿,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任浦旱,我火速辦了婚禮宇色,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘颁湖。我一直安慰自己宣蠕,他們只是感情好,可當我...
    茶點故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布甥捺。 她就那樣靜靜地躺著抢蚀,像睡著了一般。 火紅的嫁衣襯著肌膚如雪镰禾。 梳的紋絲不亂的頭發(fā)上皿曲,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天,我揣著相機與錄音吴侦,去河邊找鬼屋休。 笑死,一個胖子當著我的面吹牛备韧,可吹牛的內(nèi)容都是我干的劫樟。 我是一名探鬼主播,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼织堂,長吁一口氣:“原來是場噩夢啊……” “哼叠艳!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起捧挺,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤虑绵,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后闽烙,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體翅睛,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年黑竞,在試婚紗的時候發(fā)現(xiàn)自己被綠了捕发。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡很魂,死狀恐怖扎酷,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情遏匆,我是刑警寧澤法挨,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布欺税,位于F島的核電站虱饿,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜箩祥,卻給世界環(huán)境...
    茶點故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一吊说、第九天 我趴在偏房一處隱蔽的房頂上張望卧秘。 院中可真熱鬧绪撵,春花似錦、人聲如沸暴氏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽答渔。三九已至关带,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間研儒,已是汗流浹背豫缨。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留端朵,地道東北人。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓燃箭,卻偏偏與公主長得像冲呢,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子招狸,可洞房花燭夜當晚...
    茶點故事閱讀 44,724評論 2 354