Goods.php 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. <?php
  2. namespace app\common\service\qrcode;
  3. use Grafika\Color;
  4. use Grafika\Grafika;
  5. class Goods extends Base
  6. {
  7. /* @var \app\common\model\Goods $goods 商品信息 */
  8. private $goods;
  9. /* @var int $user_id 用户id */
  10. private $user_id;
  11. /* @var int $goodsType 商品类型:10商城商品 20拼团商品 */
  12. private $goodsType;
  13. /* @var array $pages 小程序码链接 */
  14. private $pages = [
  15. 10 => 'pages/goods/index',
  16. 20 => 'pages/sharing/goods/index'
  17. ];
  18. /**
  19. * 构造方法
  20. * Goods constructor.
  21. * @param $goods
  22. * @param $user
  23. * @param int $goodsType
  24. */
  25. public function __construct($goods, $user, $goodsType = 10)
  26. {
  27. parent::__construct();
  28. // 商品信息
  29. $this->goods = $goods;
  30. // 当前用户id
  31. $this->user_id = $user ? $user['user_id'] : 0;
  32. // 商品类型:10商城商品 20拼团商品
  33. $this->goodsType = $goodsType;
  34. }
  35. /**
  36. * @return mixed
  37. * @throws \app\common\exception\BaseException
  38. * @throws \think\exception\DbException
  39. * @throws \Exception
  40. */
  41. public function getImage()
  42. {
  43. // 判断海报图文件存在则直接返回url
  44. if (file_exists($this->getPosterPath())) {
  45. return $this->getPosterUrl();
  46. }
  47. // 小程序id
  48. $wxappId = $this->goods['wxapp_id'];
  49. // 商品海报背景图
  50. $backdrop = __DIR__ . '/resource/goods_bg.png';
  51. // 下载商品首图
  52. $goodsUrl = $this->saveTempImage($wxappId, $this->goods['image'][0]['file_path'], 'goods');
  53. // 小程序码参数
  54. $scene = "gid:{$this->goods['goods_id']},uid:" . ($this->user_id ?: '');
  55. // 下载小程序码
  56. $qrcode = $this->saveQrcode($wxappId, $scene, $this->pages[$this->goodsType]);
  57. // 拼接海报图
  58. return $this->savePoster($backdrop, $goodsUrl, $qrcode);
  59. }
  60. /**
  61. * 拼接海报图
  62. * @param $backdrop
  63. * @param $goodsUrl
  64. * @param $qrcode
  65. * @return string
  66. * @throws \Exception
  67. */
  68. private function savePoster($backdrop, $goodsUrl, $qrcode)
  69. {
  70. // 实例化图像编辑器
  71. $editor = Grafika::createEditor(['Gd']);
  72. // 字体文件路径
  73. $fontPath = Grafika::fontsDir() . '/' . 'st-heiti-light.ttc';
  74. // 打开海报背景图
  75. $editor->open($backdropImage, $backdrop);
  76. // 打开商品图片
  77. $editor->open($goodsImage, $goodsUrl);
  78. // 重设商品图片宽高
  79. $editor->resizeExact($goodsImage, 690, 690);
  80. // 商品图片添加到背景图
  81. $editor->blend($backdropImage, $goodsImage, 'normal', 1.0, 'top-left', 30, 30);
  82. // 商品名称处理换行
  83. $fontSize = 30;
  84. $goodsName = $this->wrapText($fontSize, 0, $fontPath, $this->goods['goods_name'], 680, 2);
  85. // 写入商品名称
  86. $editor->text($backdropImage, $goodsName, $fontSize, 30, 750, new Color('#333333'), $fontPath);
  87. // 写入商品价格
  88. $priceType = [10 => 'goods_price', 20 => 'sharing_price'];
  89. $editor->text($backdropImage, $this->goods['sku'][0][$priceType[$this->goodsType]], 38, 62, 964, new Color('#ff4444'));
  90. // 打开小程序码
  91. $editor->open($qrcodeImage, $qrcode);
  92. // 重设小程序码宽高
  93. $editor->resizeExact($qrcodeImage, 140, 140);
  94. // 小程序码添加到背景图
  95. $editor->blend($backdropImage, $qrcodeImage, 'normal', 1.0, 'top-left', 570, 914);
  96. // 保存图片
  97. $editor->save($backdropImage, $this->getPosterPath());
  98. return $this->getPosterUrl();
  99. }
  100. /**
  101. * 处理文字超出长度自动换行
  102. * @param integer $fontsize 字体大小
  103. * @param integer $angle 角度
  104. * @param string $fontface 字体名称
  105. * @param string $string 字符串
  106. * @param integer $width 预设宽度
  107. * @param null $max_line 最多行数
  108. * @return string
  109. */
  110. private function wrapText($fontsize, $angle, $fontface, $string, $width, $max_line = null)
  111. {
  112. // 这几个变量分别是 字体大小, 角度, 字体名称, 字符串, 预设宽度
  113. $content = "";
  114. // 将字符串拆分成一个个单字 保存到数组 letter 中
  115. $letter = [];
  116. for ($i = 0; $i < mb_strlen($string, 'UTF-8'); $i++) {
  117. $letter[] = mb_substr($string, $i, 1, 'UTF-8');
  118. }
  119. $line_count = 0;
  120. foreach ($letter as $l) {
  121. $testbox = imagettfbbox($fontsize, $angle, $fontface, $content . ' ' . $l);
  122. // 判断拼接后的字符串是否超过预设的宽度
  123. if (($testbox[2] > $width) && ($content !== "")) {
  124. $line_count++;
  125. if ($max_line && $line_count >= $max_line) {
  126. $content = mb_substr($content, 0, -1, 'UTF-8') . "...";
  127. break;
  128. }
  129. $content .= "\n";
  130. }
  131. $content .= $l;
  132. }
  133. return $content;
  134. }
  135. /**
  136. * 海报图文件路径
  137. * @return string
  138. */
  139. private function getPosterPath()
  140. {
  141. // 保存路径
  142. $tempPath = WEB_PATH . 'temp' . '/' . $this->goods['wxapp_id'] . '/';
  143. !is_dir($tempPath) && mkdir($tempPath, 0755, true);
  144. return $tempPath . $this->getPosterName();
  145. }
  146. /**
  147. * 海报图文件名称
  148. * @return string
  149. */
  150. private function getPosterName()
  151. {
  152. return 'goods_' . md5("{$this->user_id}_{$this->goodsType}_{$this->goods['goods_id']}") . '.png';
  153. }
  154. /**
  155. * 海报图url
  156. * @return string
  157. */
  158. private function getPosterUrl()
  159. {
  160. return \base_url() . 'temp/' . $this->goods['wxapp_id'] . '/' . $this->getPosterName() . '?t=' . time();
  161. }
  162. }