You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
210 lines
7.4 KiB
210 lines
7.4 KiB
<?php
|
|
// +----------------------------------------------------------------------
|
|
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
|
|
// +----------------------------------------------------------------------
|
|
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
|
|
// +----------------------------------------------------------------------
|
|
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
|
|
// +----------------------------------------------------------------------
|
|
// | Author: 萤火科技 <admin@yiovo.com>
|
|
// +----------------------------------------------------------------------
|
|
declare (strict_types=1);
|
|
|
|
namespace app\common\service\qrcode;
|
|
|
|
use Exception;
|
|
use Grafika\Color;
|
|
use Grafika\Grafika;
|
|
use cores\exception\BaseException;
|
|
use app\common\model\dealer\User as DealerUserModel;
|
|
use app\common\model\dealer\Setting as SettingModel;
|
|
|
|
/**
|
|
* 分销二维码
|
|
* Class Qrcode
|
|
* @package app\common\service
|
|
*/
|
|
class Poster extends BaseQRcode
|
|
{
|
|
// 分销商用户信息
|
|
private ?DealerUserModel $dealer;
|
|
|
|
// 分销商海报设置
|
|
private string $channel;
|
|
|
|
// 分销商海报设置
|
|
private $config;
|
|
|
|
/**
|
|
* 构造方法
|
|
* Poster constructor.
|
|
* @param DealerUserModel $dealer
|
|
* @param string $channel 二维码渠道(小程序码、h5码)
|
|
* @throws \think\db\exception\DataNotFoundException
|
|
* @throws \think\db\exception\DbException
|
|
* @throws \think\db\exception\ModelNotFoundException
|
|
*/
|
|
public function __construct(DealerUserModel $dealer, string $channel = 'H5')
|
|
{
|
|
parent::__construct();
|
|
// 分销商用户信息
|
|
$this->dealer = $dealer;
|
|
// 二维码渠道
|
|
$this->channel = $channel;
|
|
// 分销商海报设置
|
|
$this->config = SettingModel::getItem('poster', $this->getStoreId());
|
|
}
|
|
|
|
/**
|
|
* 获取分销二维码
|
|
* @return string
|
|
* @throws BaseException
|
|
* @throws \think\db\exception\DataNotFoundException
|
|
* @throws \think\db\exception\DbException
|
|
* @throws \think\db\exception\ModelNotFoundException
|
|
* @throws Exception
|
|
*/
|
|
public function getImage(): string
|
|
{
|
|
// 如果已生成过,则直接返回url
|
|
if (file_exists($this->getPosterPath())) {
|
|
return $this->getPosterUrl();
|
|
}
|
|
// 商城ID
|
|
$storeId = (int)$this->dealer['store_id'];
|
|
// 1. 下载背景图
|
|
$backdrop = $this->saveTempImage($storeId, $this->config['backdrop']['src'], 'backdrop');
|
|
// 2. 下载用户头像
|
|
$avatarUrl = $this->userAvatar();
|
|
$avatar = $this->saveTempImage($storeId, $avatarUrl, 'avatar');
|
|
// 3. 下载二维码
|
|
$scene = 'uid:' . $this->dealer['user_id'];
|
|
$qrcode = $this->getQrcode($storeId, $scene, null, $this->channel);
|
|
// 4. 拼接海报图
|
|
return $this->savePoster($backdrop, $avatar, $qrcode);
|
|
}
|
|
|
|
/**
|
|
* 获取用户头像
|
|
* @return string
|
|
*/
|
|
private function userAvatar(): string
|
|
{
|
|
$avatar = $this->dealer['user']['avatar'];
|
|
return !empty($avatar) ? $avatar['external_url'] : $this->config['avatar']['src'];
|
|
}
|
|
|
|
/**
|
|
* 海报图文件路径
|
|
* @return string
|
|
*/
|
|
private function getPosterPath(): string
|
|
{
|
|
// 保存路径
|
|
$tempPath = web_path() . "temp/{$this->dealer['store_id']}/";
|
|
!is_dir($tempPath) && mkdir($tempPath, 0755, true);
|
|
return $tempPath . $this->getPosterName();
|
|
}
|
|
|
|
/**
|
|
* 海报图文件名称
|
|
* @return string
|
|
*/
|
|
private function getPosterName(): string
|
|
{
|
|
return md5("poster_{$this->channel}_{$this->dealer['user_id']}") . '.png';
|
|
}
|
|
|
|
/**
|
|
* 海报图url
|
|
* @return string
|
|
*/
|
|
private function getPosterUrl(): string
|
|
{
|
|
return base_url() . "temp/{$this->dealer['store_id']}/" . $this->getPosterName() . '?t=' . time();
|
|
}
|
|
|
|
/**
|
|
* 拼接海报图
|
|
* @param string $backdrop 背景图路径
|
|
* @param string $avatar 头像路径
|
|
* @param string $qrcode 二维码路径
|
|
* @return string
|
|
* @throws Exception
|
|
*/
|
|
private function savePoster(string $backdrop, string $avatar, string $qrcode): string
|
|
{
|
|
// 实例化图像编辑器
|
|
$editor = Grafika::createEditor(['Gd']);
|
|
// 打开海报背景图
|
|
$editor->open($backdropImage, $backdrop);
|
|
// 生成圆形用户头像
|
|
$this->config['avatar']['style'] === 'circle' && $this->circular($avatar, $avatar);
|
|
// 打开用户头像
|
|
$editor->open($avatarImage, $avatar);
|
|
// 重设用户头像宽高
|
|
$avatarWidth = $this->config['avatar']['width'] * 2;
|
|
$editor->resizeExact($avatarImage, $avatarWidth, $avatarWidth);
|
|
// 用户头像添加到背景图
|
|
$avatarX = $this->config['avatar']['left'] * 2;
|
|
$avatarY = $this->config['avatar']['top'] * 2;
|
|
$editor->blend($backdropImage, $avatarImage, 'normal', 1.0, 'top-left', $avatarX, $avatarY);
|
|
|
|
// 生成圆形二维码
|
|
// $this->config['qrcode']['style'] === 'circle' && $this->circular($qrcode, $qrcode);
|
|
// 打开二维码
|
|
$editor->open($qrcodeImage, $qrcode);
|
|
// 重设二维码宽高
|
|
$qrcodeWidth = $this->config['qrcode']['width'] * 2;
|
|
$editor->resizeExact($qrcodeImage, $qrcodeWidth, $qrcodeWidth);
|
|
// 二维码添加到背景图
|
|
$qrcodeX = $this->config['qrcode']['left'] * 2;
|
|
$qrcodeY = $this->config['qrcode']['top'] * 2;
|
|
$editor->blend($backdropImage, $qrcodeImage, 'normal', 1.0, 'top-left', $qrcodeX, $qrcodeY);
|
|
|
|
// 写入用户昵称
|
|
$fontSize = $this->config['nickName']['fontSize'] * 2 * 0.76;
|
|
$fontX = $this->config['nickName']['left'] * 2;
|
|
$fontY = $this->config['nickName']['top'] * 2;
|
|
$Color = new Color($this->config['nickName']['color']);
|
|
$fontPath = Grafika::fontsDir() . '/st-heiti-light.ttc';
|
|
$editor->text($backdropImage, $this->dealer['user']['nick_name'], $fontSize, $fontX, $fontY, $Color, $fontPath);
|
|
|
|
// 保存图片
|
|
$editor->save($backdropImage, $this->getPosterPath());
|
|
return $this->getPosterUrl();
|
|
}
|
|
|
|
/**
|
|
* 生成圆形图片
|
|
* @param string $imgpath 图片地址
|
|
* @param string $saveName 保存文件名,默认空。
|
|
*/
|
|
private function circular(string $imgpath, string $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);
|
|
}
|
|
} |