需求背景:
在小程序上生成海报图,但在保存图片时,只能保存其中的小程序码图片,保存下来的图片过于单调,且无法确认该图片的作用性,所以需要调整为保存一整张海报图。
需求分析:
在海报图中,背景图、头像、文字、还有小程序码都是各自独立的部分,我们需要把这些图片合并起来,然后输出为一整张图片,这样就可以直接长按保存图片了。
合并图片可以用以下方法:
因为当前是在小程序开发这个需求,考虑到未来可能会替换海报上的一些文字、图片等情况,而每次修改小程序代码都需要提交版本审核,耗时耗力,所以决定在后端进行图片合成,输出图片到前端。
注意:若背景图片有透明的部分,处理过后,透明部分会变成黑色,在Grafika中暂未找到能合并透明图片的方法,感觉有点坑,不过有搜到说可以直接用gd来合成,有空再研究研究吧。(目前的解决方法是换张白色背景的图片)
composer require kosinix/grafika:dev-master --prefer-dist
function create($slogan, $avatar, $qr){
// 背景图片
$bg_img = 'images/qr_code_bg.png';
// 实例化图像编辑器
$editor = Grafika::createEditor(['Gd']);
// 打开海报背景图
$editor->open($backdropImage, $bg_img);
$bgWidth = $backdropImage->getWidth();
// 生成圆形用户头像
$avatarUrlName = 'temp/avatar.png';
$this->circular($avatar_url, $avatarUrlName);
// 打开用户头像
$editor->open($avatarImage, $avatarUrlName);
// 重设用户头像宽高
$avatarWidth = 310;
$editor->resizeExact($avatarImage, $avatarWidth, $avatarWidth);
// 用户头像添加到背景图
$avatarX = 401;
$avatarY = 36;
$editor->blend($backdropImage, $avatarImage, 'normal', 1.0, 'top-left', $avatarX, $avatarY);
// 打开小程序码
$editor->open($qrcodeImage, $qr);
// 重设小程序码宽高
$qrcodeWidth = 430;
$editor->resizeExact($qrcodeImage, $qrcodeWidth, $qrcodeWidth);
// 小程序码添加到背景图
$qrcodeX = 340;
$qrcodeY = 720;
$editor->blend($backdropImage, $qrcodeImage, 'normal', 1.0, 'top-left', $qrcodeX, $qrcodeY);
// 处理文字
$color = new Color('#FFFFFF');
$fontPath = Grafika::fontsDir() . '/st-heiti-light.ttc';
$fontSize = 50;
// 处理用户昵称
$nicknameBox = $this->get_text_box($nickname, $fontSize, $fontPath);
$fontY = 410;
$fontX = ($bgWidth / 2) - ($nicknameBox[0] / 2);
$editor->text($backdropImage, $nickname, $fontSize, $fontX, $fontY, $color, $fontPath);
$str1 = "邀请您注册成为分销员";
$strBox1 = $this->get_text_box($str1, $fontSize, $fontPath);
$str1x = ($bgWidth / 2) - ($strBox1[0] / 2);
$editor->text($backdropImage, "邀请您注册成为分销员", $fontSize, $str1x, $fontY + 100, $color, $fontPath);
$str2 = "一起赚佣金";
$strBox2 = $this->get_text_box($str2, $fontSize, $fontPath);
$str2x = ($bgWidth / 2) - ($strBox2[0] / 2);
$editor->text($backdropImage,'一起赚佣金', $fontSize, $str2x, 1220, $color, $fontPath);
// 保存图片
$editor->save($backdropImage, $qr);
}
// 生成圆形用户头像
function circular($imgpath, $saveName = ''){
$ext = pathinfo($imgpath);
$srcImg = null;
switch ($ext['extension']) {
case 'jpg':
case 'jpeg':
$srcImg = imagecreatefromjpeg($imgpath);
break;
case 'png':
$srcImg = imagecreatefrompng($imgpath);
break;
}
// 获取图片尺寸
$w = imagesx($srcImg);
$h = imagesy($srcImg);
// 设定图片宽高(正方形)
$w = $h = min($w, $h);
$newImg = imagecreatetruecolor($w, $h);
// 必须
imagesavealpha($newImg, true);
// 拾取一个完全透明的颜色,最后一个参数127为全透明
$bg = imagecolorallocatealpha($newImg, 255, 255, 255, 127);
imagefill($newImg, 0, 0, $bg);
$r = $w / 2; //圆半径
for ($x = 0; $x < $w; $x++) {
for ($y = 0; $y < $h; $y++) {
$rgbColor = imagecolorat($srcImg, $x, $y);
if (((($x - $r) * ($x - $r) + ($y - $r) * ($y - $r)) < ($r * $r))) {
imagesetpixel($newImg, $x, $y, $rgbColor);
}
}
}
// 输出图片到文件
imagepng($newImg, $saveName);
// 释放空间
imagedestroy($srcImg);
imagedestroy($newImg);
}
// 获取字符串宽高
function get_text_box($text, $size, $font){
$point = imagettfbbox($size, 0, $font, $text);
$width = $point[4] - $point[6];
$height = $point[1] - $point[7];
return [$width, $height];
}
因为目前无法生成用于前端展示的透明背景的图片,所以改成前端展示的还是一个弹窗,弹窗上添加一个长按事件,触发下载合成海报图片到用户相册
// 长按点击事件
downloadQrCode(){
wx.showLoading({
title: "加载中",
mask: true
});
if(this.data.download_qr_code){
this.downloadSaveImage(this.data.download_qr_code);
}else{
App._get("user/download_agent_qr_code", {}, (result) => {
if(!result.res){
wx.showToast({ icon: 'none', title: result.msg });
return false;
}
this.setData({download_qr_code: result.data.url});
this.downloadSaveImage(result.data.url);
}, null, (res) => {
wx.hideLoading();
});
}
},
/**
* 下载图片,并保存到用户相册
* @param {string} url 图片地址
*/
downloadSaveImage(url){
wx.getImageInfo({
src: url,
success: function (ret) {
var path = ret.path;
wx.saveImageToPhotosAlbum({
filePath: path,
success(result) {
wx.hideLoading();
wx.showToast({ icon: 'none', title: "已保存图片到相册" });
},
fail(result) {
wx.hideLoading();
if(result.errMsg.indexOf("saveImageToPhotosAlbum:fail auth deny") !== -1){
wx.showToast({ icon: 'none', title: "请允许小程序“保存图片到相册”" });
}
console.log(result)
}
});
},
fail: function(result){
wx.hideLoading();
console.log(result)
}
});
},
参考:
Grafika官方文档
PHP 将图片切成圆角