当前位置:网站首页>PHP使用Grafika合成图片,生成海报图
PHP使用Grafika合成图片,生成海报图
2022-06-21 12:18:00 【Pannikin】
需求背景:
在小程序上生成海报图,但在保存图片时,只能保存其中的小程序码图片,保存下来的图片过于单调,且无法确认该图片的作用性,所以需要调整为保存一整张海报图。
海报效果图:
需求分析:
在海报图中,背景图、头像、文字、还有小程序码都是各自独立的部分,我们需要把这些图片合并起来,然后输出为一整张图片,这样就可以直接长按保存图片了。
合并图片可以用以下方法:
- 在前端合成,使用画布canvas,把各个元素“画”进去;
- 在后端合成,使用插件Grafika,把各个组成部分合并在一起;
因为当前是在小程序开发这个需求,考虑到未来可能会替换海报上的一些文字、图片等情况,而每次修改小程序代码都需要提交版本审核,耗时耗力,所以决定在后端进行图片合成,输出图片到前端。
注意:若背景图片有透明的部分,处理过后,透明部分会变成黑色,在Grafika中暂未找到能合并透明图片的方法,感觉有点坑,不过有搜到说可以直接用gd来合成,有空再研究研究吧。(目前的解决方法是换张白色背景的图片)
使用Grafika
安装:
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);
}
- 使用open()打开图片并获得该图片对象,使用blend()依次合并图片。
- 在处理头像图片时,需要先指定临时的头像文件,便于后续使用。
- 添加文字到图片上时text(),Grafika默认的字体不兼容中文,所以需要指定字体文件路径。
// 生成圆形用户头像
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);
}
- 方法的大概思路是:创建一个正方形的透明图片,通过循环,把透明图片上的圆形部分的像素点画上(替换)头像图片对应的像素点,此时得到的图片就是一个圆形的头像图片。
- 方法中使用了imagecreatetruecolor(),创建真彩图像。此时需要保证使用的图片位数>24(图片文件>属性>详细信息>位深度),否则无法渲染图像成功,结果得到的图片是黑色的。
- 除了使用php内置函数实现圆形图片外,还可以安装Imagick扩展,更方便。
// 获取字符串宽高
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];
}
- 使用imagettfbbox()来获取字符串所在的坐标轴,从而可以拿到字符串文本框的宽高,把字符串居中合并到背景图上。
因为目前无法生成用于前端展示的透明背景的图片,所以改成前端展示的还是一个弹窗,弹窗上添加一个长按事件,触发下载合成海报图片到用户相册
// 长按点击事件
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)
}
});
},
- App._get() 为发送get请求公共方法
边栏推荐
猜你喜欢

Ansible operating instructions for configuring SSH authentication free for the first time

Musk's "good friend" impacts the largest IPO of Hong Kong stocks in 2022

Redis-bitmap 位图

3D Slicer将分割结果保存

HMS core machine learning service ID card identification function to achieve efficient information entry

External attention tensorflow (under update)

PWM (pulse width modulation) of STM32 notes

子网掩码计算

MySQL 5.6.49 企业版设置密码复杂度策略

RPC(远程过程调用协议)
随机推荐
Summary of UART problems in stm32cubemx
i.MX - RT1052 SDCard操作(SDIO接口)
自定义view绘制折线图(支持缩放)
配电室环境监控系统技术方案
uniapp中常用到的方法(部分) - 时间戳问题及富文本解析图片问题
Hands on data analysis data reconstruction
PWM (pulse width modulation) of STM32 notes
1.内存分区模型
Understand Flink operatorchain object reuse
【无标题】
[untitled]
i. MX - rt1052 SPI and I2C interfaces
EKF 扩展卡尔曼滤波适用于全向地盘的修改方法
STL basic container test
3D Slicer将分割结果保存
巨头局终战:即时零售
Understand restful architecture
2022年CIO需要关注的九个趋势和优先事项
Understand UML class diagram and sequence diagram
Introduction to CPU, MPU, MCU, SOC and MCM