RoomService.php 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. <?php
  2. namespace app\common\service\qrcode;
  3. use app\common\model\settings\Setting as SettingModel;
  4. use Grafika\Color;
  5. use Grafika\Grafika;
  6. use Endroid\QrCode\QrCode;
  7. class RoomService extends Base
  8. {
  9. // 房间信息
  10. private $room;
  11. // 来源,微信小程序,公众号
  12. private $source;
  13. // 分享用户信息
  14. private $user;
  15. // 小程序码链接
  16. //private $pages = 'pages/pagesLive/live/live';
  17. private $pages = 'pages/index/index';
  18. /**
  19. * 构造方法
  20. */
  21. public function __construct($room, $user, $source)
  22. {
  23. parent::__construct();
  24. // 商品信息
  25. $this->room = $room;
  26. //来源
  27. $this->source = $source;
  28. $this->user = $user;
  29. }
  30. /**
  31. * @return mixed
  32. */
  33. public function getImage()
  34. {
  35. // 判断海报图文件存在则直接返回url
  36. if (file_exists($this->getPosterPath())) {
  37. return $this->getPosterUrl();
  38. }
  39. // 小程序id
  40. $appId = $this->room['app_id'];
  41. // 商品海报背景图
  42. $backdrop = __DIR__ . '/resource/room_bg.png';
  43. // 下载推广图
  44. $shareUrl = $this->saveTempImage($appId, $this->room['share']['file_path'], 'temp');
  45. // 2. 下载用户头像
  46. $avatarUrl = $this->saveTempImage($appId, $this->room['user']['avatarUrl'], 'avatar');
  47. // 3. 下载分享用户头像
  48. $shareAvatarUrl = $this->saveTempImage($appId, $this->user['avatarUrl'], 'avatar');
  49. $qrcode = null;
  50. if($this->source == 'wx'){
  51. // 小程序码参数
  52. $scene = "rid:{$this->room['room_id']}";
  53. // 下载小程序码
  54. $qrcode = $this->saveQrcode($appId, $scene, $this->pages);
  55. }else if($this->source == 'mp' || $this->source == 'h5'){
  56. $scene = "rid:{$this->room['room_id']}";
  57. $qrcode = new QrCode(base_url().'h5/'.$this->pages.'?roomId='.$this->room['room_id']).'&app_id='.$appId;
  58. $qrcode = $this->saveMpQrcode($qrcode, $appId, $scene, 'image_mp');
  59. }else if($this->source == 'app'){
  60. $appshare = SettingModel::getItem('appshare');
  61. $down_url = '';
  62. //下载页
  63. if($appshare['bind_type'] == 1){
  64. $down_url = $appshare['down_url'];
  65. }else{
  66. $down_url = base_url(). "/index.php/api/user.useropen/invite?app_id=".$appId."&referee_id=" .$this->user['user_id'];
  67. }
  68. $scene = 'uid:' . $this->user['user_id'];
  69. $qrcode = new QrCode($down_url);
  70. $qrcode = $this->saveMpQrcode($qrcode, $appId, $scene, 'image_app');
  71. }
  72. // 拼接海报图
  73. return $this->savePoster($backdrop, $shareUrl, $qrcode, $avatarUrl, $shareAvatarUrl);
  74. }
  75. /**
  76. * 拼接海报图
  77. */
  78. private function savePoster($backdrop, $shareUrl, $qrcode, $avatarUrl, $shareAvatarUrl)
  79. {
  80. // 实例化图像编辑器
  81. $editor = Grafika::createEditor(['Gd']);
  82. // 字体文件路径
  83. $fontPath = Grafika::fontsDir() . '/' . 'st-heiti-light.ttc';
  84. // 打开海报背景图
  85. $editor->open($backdropImage, $backdrop);
  86. // 生成圆形用户头像
  87. $this->circular($avatarUrl, $avatarUrl);
  88. // 打开用户头像
  89. $editor->open($avatarImage, $avatarUrl);
  90. // 重设用户头像宽高
  91. $avatarWidth = 110;
  92. $editor->resizeExact($avatarImage, $avatarWidth, $avatarWidth);
  93. // 用户头像添加到背景图
  94. $editor->blend($backdropImage, $avatarImage, 'normal', 1.0, 'top-left', 30, 30);
  95. // 写入用户昵称
  96. $editor->text($backdropImage, $this->room['user']['nickName'], 28, 150, 50, new Color('#333333'), $fontPath);
  97. // 写入开播时间
  98. $editor->text($backdropImage, '开播时间:'.substr($this->room['create_time'], 0, 16), 24, 150, 100, new Color('#ff0000'), $fontPath);
  99. // 打开分享图
  100. $editor->open($shareImage, $shareUrl);
  101. // 重设分享图宽高
  102. $editor->resizeExact($shareImage, 690, 690);
  103. // 分享图添加到背景图
  104. $editor->blend($backdropImage, $shareImage, 'normal', 1.0, 'top-left', 30, 160);
  105. // 直播间名称处理换行
  106. $fontSize = 30;
  107. $productName = $this->wrapText($fontSize, 0, $fontPath, $this->room['name'], 680, 2);
  108. // 写入商品名称
  109. $editor->text($backdropImage, $productName, $fontSize, 30, 900, new Color('#333333'), $fontPath);
  110. // 打开小程序码
  111. $editor->open($qrcodeImage, $qrcode);
  112. // 重设小程序码宽高
  113. $editor->resizeExact($qrcodeImage, 140, 140);
  114. // 小程序码添加到背景图
  115. $editor->blend($backdropImage, $qrcodeImage, 'normal', 1.0, 'top-left', 570, 914);
  116. //分享用户信息
  117. // 生成圆形用户头像
  118. $this->circular($shareAvatarUrl, $shareAvatarUrl);
  119. // 打开用户头像
  120. $editor->open($shareAvatarImage, $shareAvatarUrl);
  121. // 重设用户头像宽高
  122. $avatarWidth = 60;
  123. $editor->resizeExact($shareAvatarImage, $avatarWidth, $avatarWidth);
  124. // 用户头像添加到背景图
  125. $editor->blend($backdropImage, $shareAvatarImage, 'normal', 1.0, 'top-left', 30, 1000);
  126. // 写入用户昵称
  127. $editor->text($backdropImage, $this->user['nickName'].'向你推荐', 18, 100, 1020, new Color('#333333'), $fontPath);
  128. // 保存图片
  129. $editor->save($backdropImage, $this->getPosterPath());
  130. return $this->getPosterUrl();
  131. }
  132. /**
  133. * 处理文字超出长度自动换行
  134. */
  135. private function wrapText($fontsize, $angle, $fontface, $string, $width, $max_line = null)
  136. {
  137. // 这几个变量分别是 字体大小, 角度, 字体名称, 字符串, 预设宽度
  138. $content = "";
  139. // 将字符串拆分成一个个单字 保存到数组 letter 中
  140. $letter = [];
  141. for ($i = 0; $i < mb_strlen($string, 'UTF-8'); $i++) {
  142. $letter[] = mb_substr($string, $i, 1, 'UTF-8');
  143. }
  144. $line_count = 0;
  145. foreach ($letter as $l) {
  146. $testbox = imagettfbbox($fontsize, $angle, $fontface, $content . ' ' . $l);
  147. // 判断拼接后的字符串是否超过预设的宽度
  148. if (($testbox[2] > $width) && ($content !== "")) {
  149. $line_count++;
  150. if ($max_line && $line_count >= $max_line) {
  151. $content = mb_substr($content, 0, -1, 'UTF-8') . "...";
  152. break;
  153. }
  154. $content .= "\n";
  155. }
  156. $content .= $l;
  157. }
  158. return $content;
  159. }
  160. /**
  161. * 海报图文件路径
  162. */
  163. private function getPosterPath()
  164. {
  165. // 保存路径
  166. $tempPath = root_path('public') . 'temp' . '/' . $this->room['app_id'] . '/' . $this->source. '/';
  167. !is_dir($tempPath) && mkdir($tempPath, 0755, true);
  168. return $tempPath . $this->getPosterName();
  169. }
  170. /**
  171. * 海报图文件名称
  172. */
  173. private function getPosterName()
  174. {
  175. return 'room_' . md5("{$this->room['room_id']}}{$this->user['user_id']}}") . '.png';
  176. }
  177. /**
  178. * 海报图url
  179. */
  180. private function getPosterUrl()
  181. {
  182. return \base_url() . 'temp/' . $this->room['app_id'] . '/' .$this->source . '/' . $this->getPosterName() . '?t=' . time();
  183. }
  184. /**
  185. * 生成圆形图片
  186. */
  187. private function circular($imgpath, $saveName = '')
  188. {
  189. $srcImg = imagecreatefromstring(file_get_contents($imgpath));
  190. $w = imagesx($srcImg);
  191. $h = imagesy($srcImg);
  192. $w = $h = min($w, $h);
  193. $newImg = imagecreatetruecolor($w, $h);
  194. // 这一句一定要有
  195. imagesavealpha($newImg, true);
  196. // 拾取一个完全透明的颜色,最后一个参数127为全透明
  197. $bg = imagecolorallocatealpha($newImg, 255, 255, 255, 127);
  198. imagefill($newImg, 0, 0, $bg);
  199. $r = $w / 2; //圆半径
  200. for ($x = 0; $x < $w; $x++) {
  201. for ($y = 0; $y < $h; $y++) {
  202. $rgbColor = imagecolorat($srcImg, $x, $y);
  203. if (((($x - $r) * ($x - $r) + ($y - $r) * ($y - $r)) < ($r * $r))) {
  204. imagesetpixel($newImg, $x, $y, $rgbColor);
  205. }
  206. }
  207. }
  208. // 输出图片到文件
  209. imagepng($newImg, $saveName);
  210. // 释放空间
  211. imagedestroy($srcImg);
  212. imagedestroy($newImg);
  213. }
  214. }