ProductService.php 5.6 KB

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