PHP 裁剪图片成圆形、不规则形状

  • 第一种方法:
<?php
function createImg($srcFile) {
    $data = getimagesize($srcFile);
    switch ($data['2']) {
        case 1:
            $im = imagecreatefromgif($srcFile);
            break;
        case 2:
            $im = imagecreatefromjpeg($srcFile);
            break;
        case 3:
            $im = imagecreatefrompng($srcFile);
            break;
        case 6:
            $im = imagecreatefromwbmp($srcFile);
            break;
    }
    return $im;
}

/**
 * 图片圆角处理函数
 *
 * @param source  $srcImg GD图片资源
 * @param integer $radius 圆角大小 = 最短边的长度 / $radius
 */
function roundImgs($srcImg, $radius=2) {
    $w = imagesx($srcImg);
    $h = imagesy($srcImg);
    $radius = min($w, $h) / $radius;
    $img = imagecreatetruecolor($w, $h);
    imagesavealpha($img, true); // 设置透明通道
    $bg = imagecolorallocatealpha($img, 255, 255, 255, 127); // 拾取一个完全透明的颜色, 最后一个参数127为全透明
    imagefill($img, 0, 0, $bg);
    $r = $radius; // 圆 角半径
    for ($x = 0; $x < $w; $x++) {
        for ($y = 0; $y < $h; $y++) {
            $rgbColor = imagecolorat($srcImg, $x, $y);
            if (($x >= $radius && $x <= ($w - $radius)) || ($y >= $radius && $y <= ($h - $radius))) {
                imagesetpixel($img, $x, $y, $rgbColor); // 不在四角的范围内,直接画
            } else { // 在四角的范围内选择画
                // 上左
                $yx = $r; // 圆心X坐标
                $yy = $r; // 圆心Y坐标
                if (((($x - $yx) * ($x - $yx) + ($y - $yy) * ($y - $yy)) <= ($r * $r))) {
                    imagesetpixel($img, $x, $y, $rgbColor);
                }
                // 上右
                $yx = $w - $r; // 圆心X坐标
                $yy = $r; // 圆心Y坐标
                if (((($x - $yx) * ($x - $yx) + ($y - $yy) * ($y - $yy)) <= ($r * $r))) {
                    imagesetpixel($img, $x, $y, $rgbColor);
                }
                // 下左
                $yx = $r; // 圆心X坐标
                $yy = $h - $r; // 圆心Y坐标
                if (((($x - $yx) * ($x - $yx) + ($y - $yy) * ($y - $yy)) <= ($r * $r))) {
                    imagesetpixel($img, $x, $y, $rgbColor);
                }
                // 下右
                $yx = $w - $r; // 圆心X坐标
                $yy = $h - $r; // 圆心Y坐标
                if (((($x - $yx) * ($x - $yx) + ($y - $yy) * ($y - $yy)) <= ($r * $r))) {
                    imagesetpixel($img, $x, $y, $rgbColor);
                }
            }
        }
    }
    return $img;
}

function cropImg($img, $axisx, $axisy) {
    $width = imagesx($img);
    $height = imagesy($img);
    $setRatio = $axisx / $axisy;
    $curRatio = $width / $height;
    if ($setRatio > $curRatio) {
        $resizeX = $width;
        $resizeY = $resizeX * $axisy / $axisx;
        $x = 0;
        $y = ($height - $resizeY) / 2;
    } elseif ($setRatio < $curRatio) {
        $resizeY = $height;
        $resizeX = $resizeY * $axisx / $axisy;
        $x = ($width - $resizeX) / 2;
        $y = 0;
    } else {
        $resizeX = $width;
        $resizeY = $height;
        $x = $y = 0;
    }
    $im = imagecreatetruecolor($resampleX, $resampleY);
    imagecopyresampled($im, $img, 0, 0, $x, $y, $resampleX, $resampleY, $resampleX, $resampleY);
    imagedestroy($img);
    return $im;
}

$url = 'https://upload-images.jianshu.io/upload_images/8396841-829819a83d4a77e4.jpg';
$img = createImg($url); // 创建GD图像资源
$img = cropImg($img, 1, 1); // 为了美观居中裁剪成正方形
$img = roundImgs($img); // 将四个角画成透明的
imagepng($img, './roundBirds.png');
imagedestroy($img);
原图
裁剪后
  • 第二种方法:使用PHP Imagick库进行图片圆角处理,Imagick是自带的图片圆角处理,在执行效率上也比GD的要胜上一筹。
/**
 * Imagick裁剪圆形图片
 *
 * @param strimg $imgPath 图片路径
 * @param string $saveName 保存路径
 * @return source 生成的图片
 */
function roundImg($imgPath, $saveName){
    $image = new Imagick($imgPath);
    $image->setImageFormat('png');
    $width = $image->getImageWidth();
    $height = $image->getImageHeight();
    $image->roundCorners($width/2, $height/2);
    $saveName = $saveName ? : substr(md5(time()), 0, 5).'.png';
    $image->writeImage($saveName);
    $image->destroy();
}
  • 第三种方法:使用PHP GD库进行处理。速度:快。缺点:imagecopyresampled时透明部分会失真,要缩放只能用imagecopyresesize
/**
 * 处理圆角图片
 * @param  srting $imgpath 源图片的路径
 * @return [type]          [description]
 */
function roundedCorners($imgpath){
    list($width,$height,$type) = getimagesize($imgpath);//获取上传图片大小
    if ($width != $height) {//如果上传图片不是正方形,取最小宽度作为最终生成图的大小
        if ($width > $height) {
            $imsize = $height;
        } else {
            $imsize = $width;
        }
    }
    $im = imagecreatetruecolor($imsize, $imsize);//这里创建第一个图像
    $white = imagecolorallocate($im, 255, 255, 255);// 随便取两个颜色,这里取黑色和白色
    $black = imagecolorallocate($im, 0, 0, 0);
    imagefill($im, 0, 0, $white);//将图片填充为白色
    imagefilledellipse($im, $imsize/2, $imsize/2, $imsize, $imsize, $black);//然后再图片中间画一个黑色的圆
    imagecolortransparent($im, $black);//将黑色设为透明的,则现在四个角是白色的,然后中间是透明的
    switch ($type) {
        case '2':
            $img = imagecreatefromjpeg($imgpath);//这里创建的是第二个图像
            break;
        default:
            $img = imagecreatefrompng($imgpath);//这里创建的是第二个图像
            break;
    }
    $final = imagecreatetruecolor($imsize, $imsize);//再创建一个图像,第三个图像
    imagecopyresampled($final, $img, 0, 0, ($width-$imsize)/2, ($height-$imsize)/2, $imsize, $imsize, $imsize, $imsize);//先将第二个图像(图片)压在空白的图像上,根据最小宽度,居中裁剪,成为第四个图像
    imagecopymerge($final, $im, 0, 0, 0, 0, $imsize, $imsize, 100);//再将第一个图像压在第四个图像上,由于中间是透明的,所以现在图像上中间是图片,四个角都是白色的,第五个图
    imagecolortransparent($im, $white);//然后将白色设置为透明的,现在这个图四个角是透明的,然后中间是黑色的
    imagecopymerge($im, $final, 0, 0, 0, 0, $imsize, $imsize, 100);//将第五个图压在最后的图像上,就可以得到最后的圆形的图了
    return $im;//返回图片
}
  • 要裁剪不规则图形则需要借助另外的图片来完成任务。需要借助二值图作为模板图,或者给出的模板图片上,要抠出来的部分须为不透明的,要去掉的部分则为透明的,传入模板图片和原始图片地址,返回一个图片资源。
/**
 * 根据给出的模板抠图
 * @param  string $templateImgUrl 模板图片地址
 * @param  string $userImgUrl     原始图片地址
 * @return source $img         图片资源
 */
function createImg($srcFile) {
    $data = getimagesize($srcFile);
    switch ($data['2']) {
        case 1:
            $im = imagecreatefromgif($srcFile);
            break;
        case 2:
            $im = imagecreatefromjpeg($srcFile);
            break;
        case 3:
            $im = imagecreatefrompng($srcFile);
            break;
        case 6:
            $im = imagecreatefromwbmp($srcFile);
            break;
    }
    return $im;
}

function cropImgByTemplate($templateImgUrl, $userImgUrl) {
    list($w, $h) = getimagesize($userImgUrl);
    $uimg = createImg($userImgUrl);
    $tempImg = imagecreatefrompng($templateImgUrl);
    list($width,$height) = getimagesize($templateImgUrl);
    $uim = imagecreatetruecolor($width, $height); // 将用户图片的尺寸大小缩放到模板的大小方便裁剪
    imagecopyresampled($uim, $uimg, 0, 0, 0, 0, $width, $height, $w, $h);
    $img = imagecreatetruecolor($width, $height); // 创建一个底图,大小和模板一致
    imagesavealpha($img, true); // 设置alpha通道为true,显示透明部分
    $bg = imagecolorallocatealpha($img, 255, 255, 255, 127); // 摄取一个透明的颜色
    imagefill($img, 0, 0, $bg); // 将透明颜色填满底图,得到一张全透明的图片

    for ($i=0; $i < $width; $i++) { // 遍历图片的像素点
        for ($j=0; $j < $height; $j++) {
            $rgb = imagecolorat($tempImg, $i, $j); // 获取模板上某个点的色值
            if (!$rgb) { // 不是透明的
                $color = imagecolorat($uim, $i, $j); // 在用户的图片上对应的地方取色值
                imagesetpixel($img, $i, $j, $color); // 在透明底图上画出要裁剪出来的部分
            }
        }
    }
    return $img;
}

$tempUrl = 'https://upload-images.jianshu.io/upload_images/8396841-50c151628048a0cf.png';
$url = 'https://upload-images.jianshu.io/upload_images/8396841-829819a83d4a77e4.jpg';
$img = cropImgByTemplate($tempUrl, $url);
imagepng($img, './test.png');
imagedestroy($img);
模板图
原图
裁剪结果
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,417评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,921评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,850评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,945评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,069评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,188评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,239评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,994评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,409评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,735评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,898评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,578评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,205评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,916评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,156评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,722评论 2 363
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,781评论 2 351

推荐阅读更多精彩内容

  • 图像处理(ImageMagick) 介绍安装/配置要求安装运行时配置资源类型预定义常数例子基本用法Imagick ...
    daos阅读 2,348评论 0 1
  • 更改ip和dnsVi /etc/sysconfig/network-scripts/ifcfg-eth0vi /...
    Xwei_阅读 1,807评论 0 3
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,094评论 1 32
  • ¥开启¥ 【iAPP实现进入界面执行逐一显】 〖2017-08-25 15:22:14〗 《//首先开一个线程,因...
    小菜c阅读 6,381评论 0 17
  • 作者:Erica Sadun,原文链接,原文日期:2015-12-03译者:pmst;校对:Cee;定稿:numb...
    梁杰_numbbbbb阅读 891评论 0 0