<?php
|
|
namespace app\common\service\qrcode;
|
|
use Grafika\Color;
|
use Grafika\Grafika;
|
use Endroid\QrCode\QrCode;
|
use app\common\exception\BaseException;
|
|
class BranchActivityService extends Base
|
{
|
// 活动信息
|
private $activity;
|
|
// 用户id
|
private $user_id;
|
|
private $user;
|
|
// 来源,微信小程序,公众号
|
private $source;
|
|
// 小程序码链接
|
private $page = 'pages/branch/activity/detail/detail';
|
|
/**
|
* 构造方法
|
*/
|
public function __construct($activity, $user, $source)
|
{
|
parent::__construct();
|
// 活动信息
|
$this->activity = $activity;
|
// 当前用户id
|
$this->user_id = $user ? $user['user_id'] : 0;
|
|
$this->user = $user;
|
//来源
|
$this->source = $source;
|
}
|
|
/**
|
* 获取核销二维码
|
* @return mixed
|
*/
|
public function getVerifyImage()
|
{
|
// 保存目录
|
$savePath = $this->getPosterPath('verify');
|
// 删除目录下的文件
|
if(!$this->is_empty_dir($savePath)) {
|
$this->deleteDir(substr($savePath, 0, -1));
|
}
|
// mkdir($savePath, 0755, true);
|
if ($this->source == 'wx') {
|
// 下载小程序码
|
$scene = "activity_id:{$this->activity['activity_id']},user_verify:1";
|
$fileName = $this->saveBranchActivityQrcodeToDir($this->activity['app_id'], 'pages/branch/activity/detail/detail', $savePath, $scene);
|
} else if ($this->source == 'mp' || $this->source == 'h5'){
|
$fileName = $this->saveBranchActivityVerifyMpQrcodeToDir('h5/pages/branch/activity/detail/detail',$savePath, $this->activity['activity_id'], $this->activity['app_id']);
|
}
|
|
if (!$fileName) {
|
throw new BaseException(['msg' => '下载失败, 文件不存在']);
|
}
|
return $this->getVerifyUrl($fileName);
|
|
// header('Content-Type: image/png');
|
// header('Content-disposition: attachment; filename='. $this->activity['name'] .'_'. $this->source . '.png');
|
// readfile($fullPath);
|
// header('Content-Length: ' .filesize($fullPath));
|
}
|
|
/**
|
* 分享海报
|
* @return mixed
|
*/
|
public function getImage()
|
{
|
// 判断海报图文件存在则直接返回url
|
// if (file_exists($this->getPosterPath() . $this->getPosterName())) {
|
// return $this->getPosterUrl();
|
// }
|
// 小程序id
|
$appId = $this->activity['app_id'];
|
// 二维码区域背景
|
$mark_bg = __DIR__ . '/resource/activity_mark.png';
|
// 默认海报背景图
|
$backdrop = __DIR__ . '/resource/activity_bg.png';
|
// 如果上传了活动海报图
|
if ($this->activity['pic_id']) {
|
$backdrop = $this->saveTempImage($appId, $this->activity['pic']['file_path'], 'activity');
|
}
|
// 用户头像
|
if ($this->user['avatarUrl']) {
|
$avatar = $this->saveTempImage($appId, $this->user['avatarUrl'], 'avatar');
|
} else {
|
$avatar = base_url() . 'image/user/avatar.png';
|
}
|
$qrcode = null;
|
if($this->source == 'wx'){
|
// 小程序码参数
|
$scene = "activity_id:{$this->activity['activity_id']},uid:" . ($this->user_id ?: '');
|
// // 下载小程序码
|
// $qrcode = $this->saveQrcode($appId, $scene, $this->page);
|
// 下载小程序码
|
$qrcode = $this->saveBranchActivityQrcodeToDir($this->activity['app_id'], 'pages/branch/activity/detail/detail', $this->getPosterPath(), $scene);
|
}else if($this->source == 'mp' || $this->source == 'h5'){
|
$scene = "gid:{$this->activity['activity_id']},uid:" . ($this->user_id ?: '');
|
$qrcode = new QrCode(base_url().'h5/pages/activity/detail/detail?activity_id='.$this->activity['activity_id'].'&app_id='.$appId.'&referee_id='.$this->user_id ?: '');
|
$qrcode = $this->saveMpQrcode($qrcode, $appId, $scene, 'image_mp');
|
}
|
// 拼接海报图
|
return $this->savePoster($backdrop, $mark_bg, $avatar, $qrcode);
|
}
|
|
/**
|
* 拼接海报图
|
*/
|
private function savePoster($backdrop, $mark_bg, $avatar, $qrcode)
|
{
|
// 实例化图像编辑器
|
$editor = Grafika::createEditor(['Gd']);
|
// 字体文件路径
|
$fontPath = Grafika::fontsDir() . '/' . 'st-heiti-light.ttc';
|
// 打开海报背景图
|
$editor->open($backdropImage, $backdrop);
|
// 打开活动图片
|
$editor->open($markImage, $mark_bg);
|
// 重设活动图片宽高
|
$editor->resizeExact($backdropImage, 750, 1250);
|
// 活动图片添加到背景图
|
$editor->blend($backdropImage, $markImage, 'normal', 1.0, 'top-left', 0, 0);
|
// 活动名称处理换行
|
$fontSize = 22;
|
$activityName = $this->wrapText($fontSize, 0, $fontPath, '邀您参加“'. $this->activity['name'] . '”', 460, 2);
|
// 写入活动名称
|
$editor->text($backdropImage, $activityName, $fontSize, 228, 1092, new Color('#000000'), $fontPath);
|
// 生成圆形用户头像
|
$this->circular($avatar, $avatar);
|
// 打开用户头像
|
$editor->open($avatarImage, $avatar);
|
// 重设活动图片宽高
|
$editor->resizeExact($avatarImage, 45, 45);
|
// 头像添加到背景图
|
$editor->blend($backdropImage, $avatarImage, 'normal', 1.0, 'top-left', 228, 1026);
|
// 添加用户名称
|
$user_name = $this->user['nickName'] ?: '匿名用户';
|
$editor->text($backdropImage, $user_name, 22, 288, 1036, new Color('#333333'), $fontPath);
|
// 打开小程序码
|
$editor->open($qrcodeImage, $qrcode);
|
// 重设小程序码宽高
|
$editor->resizeExact($qrcodeImage, 148, 148);
|
// 小程序码添加到背景图
|
$editor->blend($backdropImage, $qrcodeImage, 'normal', 1.0, 'top-left', 60, 1020);
|
|
// 保存图片
|
$editor->save($backdropImage, $this->getPosterPath() . $this->getPosterName());
|
return $this->getPosterUrl();
|
}
|
|
/**
|
* 处理文字超出长度自动换行
|
*/
|
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;
|
}
|
|
/**
|
* 海报图文件路径
|
*/
|
private function getPosterPath($type = '')
|
{
|
$path = $type ? "branch/activity_{$type}_{$this->activity['activity_id']}/" : '';
|
// 保存路径
|
$tempPath = root_path('public') . 'temp' . '/' . $this->activity['app_id'] . '/' . $path . $this->source. '/';
|
!is_dir($tempPath) && mkdir($tempPath, 0755, true);
|
return $tempPath;
|
}
|
|
/**
|
* 海报图文件名称
|
*/
|
private function getPosterName()
|
{
|
return 'activity_' . md5("{$this->user_id}_{$this->activity['activity_id']}") . '.png';
|
}
|
|
/**
|
* 海报图url
|
*/
|
private function getPosterUrl()
|
{
|
return \base_url() . 'temp/' . $this->activity['app_id'] . '/' .$this->source . '/' . $this->getPosterName() . '?t=' . time();
|
}
|
|
/**
|
* 核销码url
|
*/
|
private function getVerifyUrl($fileName)
|
{
|
$path = "branch/activity_verify_{$this->activity['activity_id']}/";
|
return \base_url() . 'temp/' . $this->activity['app_id'] . '/' .$path . $this->source . '/' . $fileName . '?t=' . time();
|
}
|
|
/**
|
* 生成圆形图片
|
*/
|
private function circular($imgpath, $saveName = '')
|
{
|
$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, 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);
|
}
|
|
private function is_empty_dir($fp)
|
{
|
if(!file_exists($fp)){
|
return false;
|
}
|
$H = @ opendir($fp);
|
$i=0;
|
while($_file=readdir($H)){
|
$i++;
|
}
|
closedir($H);
|
if($i>2){
|
return false;
|
}else{
|
return true;
|
}
|
}
|
|
/**
|
* 删除当前目录及其目录下的所有目录和文件
|
* @param string $path 待删除的目录
|
* @note $path路径结尾不要有斜杠/(例如:正确[$path='./static/image'],错误[$path='./static/image/'])
|
*/
|
private function deleteDir($path) {
|
if (is_dir($path)) {
|
//扫描一个目录内的所有目录和文件并返回数组
|
$dirs = scandir($path);
|
foreach ($dirs as $dir) {
|
//排除目录中的当前目录(.)和上一级目录(..)
|
if ($dir != '.' && $dir != '..') {
|
//如果是目录则递归子目录,继续操作
|
$sonDir = $path.'/'.$dir;
|
if (is_dir($sonDir)) {
|
//递归删除
|
$this->deleteDir($sonDir);
|
//目录内的子目录和文件删除后删除空目录
|
@rmdir($sonDir);
|
} else {
|
//如果是文件直接删除
|
@unlink($sonDir);
|
}
|
}
|
}
|
@rmdir($path);
|
}
|
}
|
}
|