308 lines
10 KiB
PHP
308 lines
10 KiB
PHP
<?php
|
||
|
||
namespace app\common\library\share;
|
||
|
||
/**
|
||
* 分享海报
|
||
*/
|
||
class Poster
|
||
{
|
||
|
||
//海报元素最小变局
|
||
protected static $minPadding = 0.9;
|
||
//海报基准宽度
|
||
protected static $basicWidth = 1024;
|
||
|
||
|
||
/**
|
||
* 创建海报
|
||
* @param $nickName 昵称
|
||
* @param $avatar 头像
|
||
* @param $qrCode 二维码
|
||
* @param $themes 风格 blue balck steel
|
||
* @return false|string
|
||
*/
|
||
public static function mkPoster($nickName,$avatar,$qrCode,$themes='blue') {
|
||
$bgPath = MODULE_ROOT.'/public/assets/poster/'.$themes.'.jpg';
|
||
|
||
$fontPath = MODULE_ROOT."/public/assets/poster/font/ding/DingTalk_JinBuTi_Regular.ttf";
|
||
|
||
|
||
$posterItems = self::getPosterItems($themes,$nickName,$avatar,$qrCode);
|
||
|
||
//用户信息
|
||
//这是要插入到图片的文字
|
||
if ($bgPath) {
|
||
if (is_file($bgPath)) {
|
||
//创建画布
|
||
$bgCanvas = imagecreatefromstring(file_get_contents($bgPath));
|
||
|
||
$bgW = imagesx($bgCanvas);
|
||
$contrastSize =$bgW /self::$basicWidth ;
|
||
|
||
foreach ($posterItems as $item){
|
||
if($item['attr']['x'] < (1-self::$minPadding) * $bgW){
|
||
$item['attr']['x'] = (1-self::$minPadding) * $bgW;
|
||
}
|
||
|
||
$sizeFields = ['x','y','w','h','size'];
|
||
|
||
foreach ($item['attr'] as $key => $option){
|
||
if(in_array($key,$sizeFields)){
|
||
$item['attr'][$key] = $option * $contrastSize;
|
||
}
|
||
}
|
||
|
||
|
||
switch ($item['type']){
|
||
case 'text':
|
||
$fontBox = imagettfbbox($item['attr']['size'], 0, $fontPath, $item['attr']['text']);
|
||
$newText = self::handleTextAlign($bgW,$fontBox[2],$item['attr']['text']);
|
||
if($newText != $item['attr']['text']){
|
||
$item['attr']['text'] = $newText;
|
||
$fontBox = imagettfbbox($item['attr']['size'], 0, $fontPath, $item['attr']['text']);
|
||
}
|
||
if(isset($item['align']) && $item['align']=='center'){
|
||
$item['attr']['x'] = ceil(($bgW - $fontBox[2])/2);
|
||
}
|
||
$color = ImageColorAllocate($bgCanvas, $item['attr']['color'][0],$item['attr']['color'][1],$item['attr']['color'][2]);
|
||
|
||
imagettftext($bgCanvas, $item['attr']['size'], $item['attr']['angle'], $item['attr']['x'], $item['attr']['y'], $color,$fontPath, $item['attr']['text']);
|
||
break;
|
||
case 'image':
|
||
|
||
if(isset($item['align']) && $item['align']=='center'){
|
||
$item['attr']['x'] = ceil(($bgW - $item['attr']['w'])/2);
|
||
}
|
||
|
||
imagecopyresampled($bgCanvas, $item['attr']['src_image'], $item['attr']['x'], $item['attr']['y'], 0, 0, $item['attr']['w'], $item['attr']['h'], imagesx($item['attr']['src_image']), imagesy($item['attr']['src_image']));
|
||
break;
|
||
}
|
||
}
|
||
|
||
ob_start();
|
||
imagepng($bgCanvas);
|
||
$imgSrc = base64_encode(ob_get_contents());
|
||
ob_end_clean();
|
||
//生成图片
|
||
return $imgSrc;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* 处理规定宽度内自动换行(imagettftext)
|
||
* @return void
|
||
*/
|
||
private static function handleTextAlign($bgW,$txtW,$text)
|
||
{
|
||
|
||
$minBgWidth = $bgW * self::$minPadding;
|
||
|
||
if($txtW <= $minBgWidth){
|
||
return $text;
|
||
}
|
||
|
||
$maxLineWordsLength = ceil(mb_strlen($text) * ($minBgWidth/ $txtW));
|
||
|
||
$string = '';
|
||
foreach (mb_str_split($text) as $index => $t){
|
||
$string .= $t;
|
||
if($index > 0 && ($index % $maxLineWordsLength) == 0){
|
||
$string .= "\n";
|
||
}
|
||
}
|
||
|
||
return $string;
|
||
}
|
||
|
||
/**
|
||
* 获取海报元素
|
||
* @param $bgType 海报背景类型
|
||
* @param $nickName 昵称
|
||
* @param $avatar 头像
|
||
* @param $qrCode 二维码
|
||
* @return array|array[]
|
||
*/
|
||
public static function getPosterItems($bgType,$nickName,$avatar,$qrCode){
|
||
$items = [
|
||
'nickname'=>[
|
||
'type'=>'text',
|
||
'align'=>'center',
|
||
'attr'=>[
|
||
'size'=>36,//字体大小
|
||
'x'=>480,//x轴
|
||
'y'=>380,//y轴
|
||
'text'=>$nickName,//内容
|
||
'angle'=>0,//角度,
|
||
'color'=>[255,255,255]//字体颜色rgb
|
||
]
|
||
],
|
||
'recommend'=>[
|
||
'type'=>'text',
|
||
'align'=>'center',
|
||
'attr'=>[
|
||
'size'=>26,//字体大小
|
||
'x'=>360,//x轴
|
||
'y'=>430,//y轴
|
||
'text'=>'向你推荐优质知识店铺',//内容
|
||
'angle'=>0,//角度,
|
||
'color'=>[255,255,255]//字体颜色rgb
|
||
]
|
||
],
|
||
'tip'=>[
|
||
'type'=>'text',
|
||
'align'=>'center',
|
||
'attr'=>[
|
||
'size'=>20,//字体大小
|
||
'x'=>400,//x轴
|
||
'y'=>1010,//y轴
|
||
'text'=>'长按识别,查看好课',//内容
|
||
'angle'=>0,//角度,
|
||
'color'=>[0,0,0]//字体颜色rgb
|
||
]
|
||
],
|
||
|
||
'other'=>[
|
||
'type'=>'text',
|
||
'align'=>'center',
|
||
'attr'=>[
|
||
'size'=>30,//字体大小
|
||
'x'=>400,//x轴
|
||
'y'=>1210,//y轴
|
||
'text'=>'不可错过的精品课程',//内容
|
||
'angle'=>0,//角度,
|
||
'color'=>[255,255,255]//字体颜色rgb
|
||
]
|
||
],
|
||
'other1'=>[
|
||
'type'=>'text',
|
||
'align'=>'center',
|
||
'attr'=>[
|
||
'size'=>35,//字体大小
|
||
'x'=>400,//x轴
|
||
'y'=>1280,//y轴
|
||
'text'=>'邀请你和我一起成长',//内容
|
||
'angle'=>0,//角度,
|
||
'color'=>[255,255,255]//字体颜色rgb
|
||
]
|
||
],
|
||
'avatar'=>[
|
||
'type'=>'image',
|
||
'align'=>'center',
|
||
'attr'=>[
|
||
'x'=>440,//x轴
|
||
'y'=>140,//y轴
|
||
'w'=>160,//宽度
|
||
'h'=>160,//高度
|
||
'src_image'=>'',//图像资源
|
||
]
|
||
],
|
||
'qrcode'=>[
|
||
'type'=>'image',
|
||
'align'=>'center',
|
||
'attr'=>[
|
||
'x'=>400,//x轴
|
||
'y'=>730,//y轴
|
||
'w'=>240,//宽度
|
||
'h'=>240,//高度
|
||
'src_image'=>'',//图像资源
|
||
]
|
||
]
|
||
];
|
||
|
||
|
||
if($bgType=='steel'){
|
||
$items['other1']['attr']['color'] = [209,141,56];
|
||
$items['other']['attr']['color'] = [209,141,56];
|
||
$items['tip']['attr']['color'] = [255,255,255];
|
||
|
||
|
||
$items['qrcode']['attr']['y'] -= 160;
|
||
$items['tip']['attr']['y'] -= 160;
|
||
|
||
$items['other']['attr']['y'] -= 240;
|
||
$items['other1']['attr']['y'] -= 240;
|
||
}
|
||
|
||
if($bgType=='black'){
|
||
|
||
$items['qrcode']['attr']['y'] -= 100;
|
||
$items['tip']['attr']['y'] -= 100;
|
||
$items['tip']['attr']['color'] = [255,255,255];
|
||
$items['other']['attr']['y'] -= 100;
|
||
$items['other1']['attr']['y'] -= 100;
|
||
}
|
||
|
||
|
||
$items['qrcode']['attr']['src_image'] = imagecreatefromstring($qrCode);
|
||
$items['avatar']['attr']['src_image'] = imagecreatefromstring(self::convertToCircleFromData($avatar));
|
||
|
||
return $items;
|
||
}
|
||
|
||
|
||
/**
|
||
* 图片转圆形
|
||
* @param $imageData 二进制图片数据
|
||
* @return false|string
|
||
*/
|
||
public static function convertToCircleFromData($imageData) {
|
||
// 创建内存中的图像资源
|
||
$image = imagecreatefromstring($imageData);
|
||
if (!$image) {
|
||
return $imageData;
|
||
}
|
||
|
||
// 获取图像的宽度和高度
|
||
$width = imagesx($image);
|
||
$height = imagesy($image);
|
||
|
||
// 创建一个新的透明图像
|
||
$mask = imagecreatetruecolor($width, $height);
|
||
imagesavealpha($mask, true);
|
||
$transparent = imagecolorallocatealpha($mask, 0, 0, 0, 127);
|
||
imagefill($mask, 0, 0, $transparent);
|
||
|
||
// 绘制圆形
|
||
$centerX = $width / 2;
|
||
$centerY = $height / 2;
|
||
$radius = min($width, $height) / 2;
|
||
imagefilledellipse($mask, $centerX, $centerY, $radius * 2, $radius * 2, imagecolorallocate($mask, 255, 255, 255));
|
||
|
||
// 创建一个新的透明图像来存储最终结果
|
||
$output = imagecreatetruecolor($width, $height);
|
||
imagesavealpha($output, true);
|
||
imagefill($output, 0, 0, $transparent);
|
||
|
||
// 应用遮罩到原始图像
|
||
for ($x = 0; $x < $width; $x++) {
|
||
for ($y = 0; $y < $height; $y++) {
|
||
$maskColor = imagecolorat($mask, $x, $y);
|
||
$alpha = 127 - ($maskColor >> 24);
|
||
if ($alpha > 0) {
|
||
$imageColor = imagecolorat($image, $x, $y);
|
||
$r = ($imageColor >> 16) & 0xFF;
|
||
$g = ($imageColor >> 8) & 0xFF;
|
||
$b = $imageColor & 0xFF;
|
||
$newColor = imagecolorallocatealpha($output, $r, $g, $b, 127 - $alpha);
|
||
imagesetpixel($output, $x, $y, $newColor);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 保存处理后的图像到内存
|
||
ob_start();
|
||
imagepng($output);
|
||
$result = ob_get_clean();
|
||
|
||
// 释放图像资源
|
||
imagedestroy($image);
|
||
imagedestroy($mask);
|
||
imagedestroy($output);
|
||
|
||
return $result;
|
||
}
|
||
|
||
} |