加载grafika
use Grafika\Color;
use Grafika\Grafika;
use app\common\library\wechat\WxBase;
use app\common\library\wechat\Qrcode;
- 控制器
$data=[ 'distribut_id'=>$distribut_id, 'avator'=>$storeInfo['head'], 'nickname'=>$storeInfo['store_name'], 'date'=>date('Y_m_d'), ]; //生成打卡审核图片 $posterModel = new posterModel($data); $posters=$posterModel->getImage();
- 模型
Poster.php ``` <?php namespace app\api\model; use Grafika\Color; use Grafika\Grafika; use app\common\library\wechat\WxBase; use app\common\library\wechat\Qrcode; use think\Db; /**- 生成海报类
- Class Qrcode
- @package app\common\service / class Poster extends Base{ / @var array $config 海报设置 / private $config; / @var int $sdata data数据 */ private $sdata; /**
- 构造方法
- Poster constructor.
- @param $data
- [distribut_id] => 2
- [avator] => 2020_01_11
- [nickname] => 4
- @throws \Exception */ public function __construct($data=[]){ $this->sdata=$data; // 微信设置 $this->config = Db::name(‘wechatconfig’)->where(‘wechat’,’wechat’)->find(); } /**
- 获取海报
- @return string
- @throws \app\common\exception\BaseException
- @throws \think\exception\DbException
- @throws \Exception */ public function getImage(){ if (file_exists($this->getPosterPath())) { return $this->getPosterUrl(); } // 小程序id $wxappId = $this->config[‘wxappid’]; // 1. 下载背景图 $backdrop = $this->getBg(); // 2. 下载用户头像 $avatarUrl = $this->saveTempImage($wxappId,$this->sdata[‘avator’],’head’); // 3. 下载小程序码 $qrcode = $this->saveQrcode($wxappId,’referee_id:’.$this->sdata[‘distribut_id’]); // 4. 拼接海报图 return $this->savePoster($backdrop, $avatarUrl, $qrcode); } /**
- 保存小程序码到文件
- @param $wxapp_id
- @param $scene
- @param null $page
- @return string
- @throws \app\common\exception\BaseException
- @throws \think\exception\DbException */ private function saveQrcode($wxapp_id, $scene, $page = null){ // 文件目录 $dirPath = ROOT_PATH.’public/uploads/qrcode’; !is_dir($dirPath) && mkdir($dirPath, 0755, true); // 文件名称 $fileName = ‘qrcode_‘.md5($wxapp_id.$scene.$page).’.png’; // 文件路径 $savePath = “{$dirPath}/{$fileName}”; if (file_exists($savePath)) return $savePath; // 小程序配置信息 // 请求api获取小程序码 $qrcode = new Qrcode($this->config[‘wxappid’],$this->config[‘wxappsecret’]); $content = $qrcode->getQrcode($scene, $page); // 保存到文件 file_put_contents($savePath, $content); return $savePath; } /**
- 获取网络图片到临时目录
- @param $wxapp_id
- @param $url
- @param string $mark
- @return string */ private function saveTempImage($wxapp_id,$url,$mark=’head’,$ssl=false){ $dirPath = ROOT_PATH.’public/uploads/store/head’; !is_dir($dirPath) && mkdir($dirPath, 0755, true); $savePath = $dirPath . ‘/’ . $mark . ‘_’ . $url . ‘.png’; if (file_exists($savePath)) return $savePath; $ch = curl_init($url); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); if(!empty($ssl)){ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); } curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_BINARYTRANSFER, 1); $img = curl_exec($ch); curl_close($ch); $fp = fopen($savePath, ‘w’); fwrite($fp, $img); fclose($fp); return $savePath; } /**
- 拼接海报图
- @param $backdrop
- @param $avatarUrl
- @param $qrcode
- @return string
- @throws \Exception */ private function savePoster($backdrop, $avatarUrl, $qrcode){ vendor(‘grafika.src.autoloader’); // 实例化图像编辑器 $editor = Grafika::createEditor([‘Gd’]); // 打开海报背景图 $editor->open($backdropImage, $backdrop); $backdropImage_w=$backdropImage->getWidth(); $backdropImage_h=$backdropImage->getHeight(); // 生成圆形用户头像 $this->circular($avatarUrl, $avatarUrl); // 打开用户头像 $editor->open($avatarImage, $avatarUrl); // 重设用户头像宽高 $avatarWidth = 160; $editor->resizeExact($avatarImage, $avatarWidth, $avatarWidth); // 用户头像添加到背景图 $avatarX = ($backdropImage_w/2)-80; $avatarY = ($backdropImage_h/2)-60; $editor->blend($backdropImage, $avatarImage, ‘normal’, 1.0, ‘top-left’, $avatarX, $avatarY); // 生成圆形小程序码 // $this->circular($qrcode, $qrcode); // 打开小程序码 $editor->open($qrcodeImage, $qrcode); // 重设小程序码宽高 $qrcodeWidth = 180; $editor->resizeExact($qrcodeImage, $qrcodeWidth, $qrcodeWidth); // 小程序码添加到背景图 $qrcodeX = ($backdropImage_w/2)-90; $qrcodeY = ($backdropImage_h/2)+340; $editor->blend($backdropImage, $qrcodeImage, ‘normal’, 1.0, ‘top-left’, $qrcodeX, $qrcodeY); // 写入用户昵称 $Color = new Color(‘#333333’); $fontPath = Grafika::fontsDir() . DS . ‘st-heiti-light.ttc’; $fontBox = imagettfbbox(20,0,$fontPath,$this->sdata[‘nickname’]);//获取文字所需的尺寸大小 $editor->text($backdropImage, $this->sdata[‘nickname’],20,ceil((($backdropImage_w-$fontBox[2])/2)),($backdropImage_h/2)+120,$Color,$fontPath); // 保存图片 $editor->save($backdropImage, $this->getPosterPath()); return $this->getPosterUrl(); } /**
- 生成圆形图片
- @param static $imgpath 图片地址
- @param string $saveName 保存文件名,默认空。 */ private function circular($imgpath, $saveName = ‘’,$alpha=’127’){ // print_r($imgpath);exit; $srcImg = imagecreatefromstring(file_get_contents($imgpath)); $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, $alpha); 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); } /**
- 处理文字超出长度自动换行
- @param integer $fontsize 字体大小
- @param integer $angle 角度
- @param string $fontface 字体名称
- @param string $string 字符串
- @param integer $width 预设宽度
- @param null $max_line 最多行数
- @return string */ private function wrapText($fontsize, $angle, $fontface, $string, $width, $max_line = null){ // 这几个变量分别是 字体大小, 角度, 字体名称, 字符串, 预设宽度 $content = “”; // 将字符串拆分成一个个单字 保存到数组 letter 中 $letter = []; for ($i = 0; $i < mb_strlen($string, ‘UTF-8’); $i++) { $letter[] = mb_substr($string, $i, 1, ‘UTF-8’); } $line_count = 0; foreach ($letter as $l) { $testbox = imagettfbbox($fontsize, $angle, $fontface, $content . ‘ ‘ . $l); // 判断拼接后的字符串是否超过预设的宽度 if (($testbox[2] > $width) && ($content !== “”)) { $line_count++; if ($max_line && $line_count >= $max_line) { $content = mb_substr($content, 0, -1, ‘UTF-8’) . “…”; break; } $content .= “\n”; } $content .= $l; } return $content; } /**
- 海报图文件路径
- @return string */ private function getPosterPath(){ // 保存路径 $tempPath =ROOT_PATH.’public/uploads/store/poster/’; !is_dir($tempPath) && mkdir($tempPath, 0755, true); return $tempPath.$this->getPosterName(); } /**
- 海报图文件名称
- @return string */ private function getPosterName(){ return ‘poster_‘.md5($this->sdata[‘date’].’_’.$this->sdata[‘distribut_id’]).’.png’; } /**
- 海报图url
- @return string */ private function getPosterUrl(){ return \base_url().’uploads/store/poster/’.$this->getPosterName().’?t=’.time(); } /**
- 获取随机背景图
- @param $where
-
@return null static - @throws \think\exception\DbException
*/
private function getBg(){
$mt_rand=mt_rand(1,4);
$bg=ROOT_PATH.’public/uploads/store/share_bg_’.$mt_rand.’.jpg’;
return $bg;
}
}
3.前端 poster.js
Page({ /**
- 页面的初始数据
*/
data: {
modalHidden: false
},
posters:function(){
let _this=this;
let msg=’临沂市兰山区颐高上海街’;
wx.showModal({
title: ‘提示’,
content: ‘确认定位在:’ + msg+’?’,
success: function (res) {
if (res.confirm) {
console.log(‘用户点击确定’);
App._get(‘Store/posters’, {}, function (result) {
if (result.code==1){
_this.setData({
posters: result.data.posters,
modalHidden: true
});
}
console.log(result);
});
} else if (res.cancel) {
console.log(‘用户点击取消’)
}
}
})
},
onHideCheckPoster:function(){
var _this = this;
_this.setData({
modalHidden: false
})
},
// 保存图片
saveImg: function (e) {
let _this = this;
//获取相册授权
wx.getSetting({
success(res) {
if (!res.authSetting[‘scope.writePhotosAlbum’]) {
wx.authorize({
scope: ‘scope.writePhotosAlbum’,
success() {
//这里是用户同意授权后的回调
_this.saveImgToLocal();
},
fail() {//这里是用户拒绝授权后的回调
_this.setData({
openSettingBtnHidden: false
})
}
})
} else {//用户已经授权过了
_this.saveImgToLocal();
}
}
})
},
saveImgToLocal: function (e) {
let _this = this;
let imgSrc = _this.data.posters;
wx.downloadFile({
url: imgSrc,
success: function (res) {
//图片保存到本地
wx.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success: function (data) {
wx.showToast({
title: ‘保存成功’,
icon: ‘success’,
duration: 2000
})
},
})
}
})
},
// 授权
handleSetting: function (e) {
let _this = this;
// 对用户的设置进行判断,如果没有授权,即使用户返回到保存页面,显示的也是“去授权”按钮;同意授权之后才显示保存按钮
if (!e.detail.authSetting[‘scope.writePhotosAlbum’]) {
// wx.showModal({
// title: ‘警告’,
// content: ‘若不打开授权,则无法将图片保存在相册中!’,
// showCancel: false
// })
_this.setData({
openSettingBtnHidden: false
})
} else {
// wx.showModal({
// title: ‘提示’,
// content: ‘您已授权,赶紧将图片保存在相册中吧!’,
// showCancel: false
// })
_this.setData({
openSettingBtnHidden: true
})
}
},
});
poster.wxss
/* 遮罩层 / .mask { width: 100%; height: 100%; position: fixed; top: 0; left: 0; background: #000; z-index: 9000; opacity: 0.5; } / 分销海报 / .modalPoster { width: 90%; height:90vh; position: fixed; top: 30px; left: 0; right: 0; z-index: 99999; margin: 0 auto; display: flex; flex-direction: column; align-items: center; border-radius: 15rpx; background: #fff; } .modalPoster .close{ position: absolute; width: 60rpx; height: 60rpx; top: -30rpx; right: -30rpx; } .modalPoster .close image{ width: 100%; height: 100%; } / 分销海报的图片 */ .modalPoster .check-box,.modalPoster .shimg image { height:80vh; margin: 9rpx; } .saveImg{ width: 40%; height: 65rpx; line-height: 65rpx; font-size: 32rpx; background: #fec627; border: 1rpx solid #fec627; border-radius: 50rpx; color: #fff; text-align: center; margin: 20rpx; }
poster.wxml
``` 附件下载:https://file.alonesky.com/file/poster_tplay_tp5.zip