目的

  • 將圖片依比例縮放並降低品質

紀錄

<?php

/**
 * Class PhotoCompressor 圖片壓縮
 *
 * @date 2018/4/30
 * @author York <jason945119@gmail.com>
 */
class PhotoCompressor
{
    // 裁切
    const IS_CROP_MODE = 1;
    const NO_CROP_MODE = 2;
    // 預設寬高
    const DEFAULT_W = 800;
    const DEFAULT_H = 600;
    // 預設品質
    const DEFAULT_QUALITY = 80;

    // 編輯核心
    protected $imagick;
    // 壓縮模式 1: 不裁切全圖 2:裁切至符合最大寬高
    protected $mode;
    // 品質預設 80
    protected $quality;
    // 以什麼為主  true: 寬 false:高
    protected $main;

    // 原始圖檔參數
    protected $source_file;
    protected $original_ratio;
    protected $source_width;
    protected $source_height;

    // 輸出圖檔參數
    protected $save_file;
    protected $new_ratio;
    protected $max_width;
    protected $max_height;

    protected function _init( string $source_file ) : self
    {
        // 設定編輯核心
        self::_setCore( $source_file );
        // 設定原始圖片寬高
        self::_setSourceWH();
        // 預設輸出品質
        self::quality( self::DEFAULT_QUALITY );
        // 預設輸出max寬高
        self::maxWH( self::DEFAULT_W, self::DEFAULT_H );
        // 預設輸出路徑
        self::saveAs( $source_file );
        return $this;
    }

    protected function _setCore( $source_file ) : void
    {
        $this->imagick = new \Imagick( $source_file );
    }

    protected function _setSourceWH() : void
    {
        $this->source_width = $this->imagick->getImageWidth();
        $this->source_height = $this->imagick->getImageHeight();
    }

    protected function _setMain() : void
    {
        $this->new_ratio = $this->max_width / $this->max_height;

        $this->original_ratio = $this->source_width / $this->source_height;

        $this->main = ( $this->new_ratio > $this->original_ratio );
    }

    protected function _crop() : void
    {
        if( $this->main )
        {
            // 以寬為主
            $cropWidth = $this->source_width;
            $cropHeight = $this->source_width / $this->new_ratio;
            $cropX = 0;
            $cropY = ( $this->source_height - $cropHeight ) / 2;
        }
        else
        {
            // 以高為主
            $cropWidth = $this->max_height * $this->new_ratio;
            $cropHeight = $this->max_height;
            $cropX = ( $this->source_width - $cropWidth ) / 2;
            $cropY = 0;
        }
        $this->imagick->cropImage( $cropWidth, $cropHeight, $cropX, $cropY );
    }

    protected function _reduce() : void
    {
        if( $this->mode == self::IS_CROP_MODE )
        {
            if( $this->main )
            {
                // 以寬為主 寬設定到 max
                $final_width = $this->max_width;
                $final_height = $this->source_height * $this->max_width / $this->source_width;
            }
            else
            {
                // 以高為主 高設定到 max
                $final_width = $this->source_width * $this->max_height / $this->source_height;
                $final_height = $this->max_height;
            }
        }

        if( $this->mode == self::NO_CROP_MODE )
        {
            $final_width = $this->max_width;
            $final_height = $this->max_height;
        }
        $this->imagick->thumbnailImage( $final_width, $final_height );
    }

    /**
     * saveAs 設定圖片產出路徑
     *
     * @param string $save_file
     *
     * @return PhotoCompressor
     *
     * @date 2018/4/26
     * @author York <jason945119@gmail.com>
     */
    public function saveAs( string $save_file ) : self
    {
        $this->save_file = $save_file;
        return $this;
    }

    /**
     * maxWH 設定最大寬高
     *
     * @param int $width
     * @param int $height
     *
     * @return PhotoCompressor
     *
     * @date 2018/4/26
     * @author York <jason945119@gmail.com>
     */
    public function maxWH( int $width, int $height ) : self
    {
        $this->max_width = $width;
        $this->max_height = $height;
        return $this;
    }

    /**
     * quality 設定品質
     *
     * @param int $quality
     *
     * @return PhotoCompressor
     *
     * @date 2018/4/26
     * @author York <jason945119@gmail.com>
     */
    public function quality( int $quality ) : self
    {
        $this->quality = $quality;
        return $this;
    }

    /**
     * compress 開始裁切縮放
     *
     * @param int $mode
     *
     * @date 2018/4/26
     * @author York <jason945119@gmail.com>
     */
    public function compress( $mode = self::IS_CROP_MODE ) : void
    {
        // 選定模式
        $this->_setMain();
        $this->mode = $mode;


        //裁切
        if( $this->mode == self::NO_CROP_MODE )
        {
            $this->_crop();
        }

        // 縮放
        if( ( $this->source_width > $this->max_width ) || ( $this->source_height > $this->max_height ) || ( $this->mode === self::NO_CROP_MODE ) )
        {
            $this->_reduce();
        }

        $this->imagick->setImageFormat( 'jpg' );
        $this->imagick->setCompressionQuality( $this->quality );
        $this->imagick->writeImage( $this->save_file );
    }

    public static function instance( string $source_file ) : self
    {
        static $obj;
        if( !isset( $obj ) )
        {
            $obj = new self();
        }
        $obj->source_file = $source_file;

        return $obj->_init( $source_file );
    }
}