【PHP】自有图片服务器,图片动态裁剪缩放

本文链接:https://www.cnblogs.com/tujia/p/14677098.html

 

背景:

1)几年前的PHP老项目,没用使用OSS来保存图片,而是用了一台独立的服务器来放图片。

2)但因为后台没有限制图片上传的大小,经营人员也没有手动裁剪图片,导致图片的尺寸很大,前端加载很慢,影响用户体验,也浪费带宽。

3)所以,我想着能不能改造一下图片服务器,像阿里云OSS那样,显示的时候,在url增加一个参数,就能动态裁剪(缩放)输出。

 

一、闲话少说,直接上代码吧(图片服务器根目录增加一个 crop.php 文件

/**
 * @Author      Tiac
 * @DateTime    2021-04-16
 * @Description 图片裁剪
 * @see https://www.cnblogs.com/tujia/p/14677098.html
 */
error_reporting(E_ALL);
ini_set('display_errors', 'On');

define('ROOT', str_replace('\\', '/', __DIR__));

$img = isset($_GET['img'])? trim($_GET['img']):'';
$debug = isset($_GET['debug'])? intval($_GET['debug']):0;

// 2022.01.05 兼容 阿里云 oss 参数

list($w, $h, $wm) = array(0, 0, '');
$ossString = isset($_GET['x-oss-process'])? $_GET['x-oss-process']:'';

if ($ossString == '') {
    $w = isset($_GET['w'])? intval($_GET['w']):0;
    $h = isset($_GET['h'])? intval($_GET['h']):0;
    $wm = isset($_GET['wm'])? $_GET['wm']:'';
} elseif (strpos($ossString, 'image/resize') !== false) {
    $process = explode(',', $ossString);
    $process = array_reduce($process, function($carry, $item){
        if (strrpos($item, '_') > 0) {
            list($k, $v) = explode('_', $item);
            $carry[$k] = $v;
        }
        return $carry;
    });
    $w = isset($process['w'])? intval($process['w']):0;
    $h = isset($process['h'])? intval($process['h']):0;
}

if (empty($img) || !file_exists(ROOT . $img)) {
    header('HTTP/1.1 404 Not Found');
    header("status: 404 Not Found");
    exit;
}

$src = ROOT . $img;

// CDN缓存
header('Cache-Control: max-age=604800');

if (function_exists('mime_content_type')) {
    $mime = mime_content_type($src);
} elseif (function_exists('finfo_open')) {
    $finfo = finfo_open(FILEINFO_MIME);
    $info = finfo_file($finfo, $src);
    finfo_close($finfo);
    list($mime, $charset) = explode('; ', $info);
} else {
    $parts = pathinfo($src);
    $extension = strtolower($parts['extension']);
    $mime = 'image/' . ($extension=='jpg'?'jpeg':$extension);
}

if ($debug == 0) {
    header('Content-Type: ' . $mime);
}

// 没设置宽高的,直接输出
if ($w == 0 && $h == 0 && $wm == '') {
    echo file_get_contents($src);
    exit;
}

switch($mime) {
    case 'image/jpeg':
        $img_r = @imagecreatefromjpeg($src);
        break;
    case 'image/png':
        $img_r = @imagecreatefrompng($src);
        break;
    case 'image/gif':
        $img_r = @imagecreatefromgif($src);
        break;
    case 'image/webp':
        $img_r = @imagecreatefromwbmp($src);
        break;
}

if ($img_r === false) {
    $mime = 'image/jpeg';
    $img_r = @imagecreatefromjpeg($src);
}

if ($debug == 1) {
    var_dump($img_r);exit;
}

// 水印
if (strpos($wm, '_') !== false) {
    list($wm_x, $wm_y) = explode('_', $wm);
    list($wm_w, $wm_h, $wm_type, $wm_attr) = getimagesize('wm.png');
    $wm = imagecreatefrompng('wm.png');
    imagecopy($img_r, $wm, $wm_x, $wm_y, 0, 0, $wm_w, $wm_h);
}

list($width, $height, $type, $attr) = getimagesize($src);

if ($w > 0 && $h > 0) {
    $minw = intval($width / $height * $h);
    $minh = intval($height / $width * $w);

    $w > $minw && $w = $minw;
    $h > $minh && $h = $minh;
} elseif ($w < 0 || $h < 0) {
    $width += $w;
    $height += $h;
    $w = $width;
    $h = $height;
} else {
    $w == 0 && $w = intval($width / $height * $h);
    $h == 0 && $h = intval($height / $width * $w);
}

if ($w > 0 && $h > 0) {
    $dst_r = ImageCreateTrueColor($w, $h);

    if (in_array($mime, ['image/png', 'image/gif'])) {
        $color = imagecolorallocate($dst_r, 255, 255, 255);
        // imagecolortransparent($dst_r, $color);
        imagefill($dst_r, 0, 0, $color);
    }

    $result = imagecopyresampled(
        $dst_r,
        $img_r,
        0,
        0,
        0,
        0,
        $w,
        $h,
        $width,
        $height
    );

    if ($result !== true) {
        die('wrong.');
    }
} else {
    $dst_r = $img_r;
}

switch($mime) {
    case 'image/jpeg':
        imagejpeg($dst_r, null, 100);
        break;
    case 'image/png':
        imagepng($dst_r);
        break;
    case 'image/gif':
        imagegif($dst_r);
        break;
    case 'image/webp':
        imagewebp($dst_r);
        break;
}

 

注:

1)创建好crop.php之后,就可以直接用 https://img.xxx.com/crop.php?img=/article/202103/31/161717171088039.jpg&w=500 这种url形式来动态缩放图片了;

2)但为了美观及小改动原代码,还需要增加一个rewrite规则;

3)服务器记得要打开 php_fileinfo 扩展;

4)2022.01.05 兼容 阿里云 oss 参数。

 

二、增加一个 nginx rewrite 规则

if ($query_string ~ [wh]=\d+) {
    rewrite ^([^\?]+)(.*) /crop.php?img=$1 last;
}

注:这里是判断query_string里有 w= 或 h= 关键字时才重写url,如果你的图片服务器url有冲突,那这个if条件你得改改。

 

三、最终url示例

https://img.xxx.com/article/202103/31/161717171088039.jpg?w=200&h=200

https://img.xxx.com/article/202103/31/161717171088039.jpg?w=500

https://img.xxx.com/article/202103/31/161717171088039.jpg?h=200

https://img.xxx.com/article/202103/31/161717171088039.jpg?x-oss-process=image/resize,w_200

https://img.xxx.com/article/202103/31/161717171088039.jpg?x-oss-process=image/resize,h_200

注:我只弄了等比例缩放,所以同时填了w和h参数时,会自动约束计算最小的宽和高,等比例缩放;如果想要强制拉抻图片效果的,改一下代码就可以了

 

本文链接:https://www.cnblogs.com/tujia/p/14677098.html


完。

 

posted @ 2021-04-19 15:39  Tiac  阅读(285)  评论(0编辑  收藏  举报