LearnReportShareImage.php 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. <?php
  2. namespace App\Http\Controllers\Api\Video;
  3. use App\Facades\Servers\WechatMini\Mini;
  4. use App\Http\Controllers\Api\Api;
  5. use App\Models\Video\Course;
  6. use App\Models\Video\LearnRecord;
  7. use Intervention\Image\Facades\Image;
  8. use Intervention\Image\Gd\Font;
  9. class LearnReportShareImage extends Api
  10. {
  11. /**
  12. * 学习中报告图片 /api/learn_report_share_image/get
  13. * @param LearnRecord $learnRecordModel
  14. * @param Course $courseModel
  15. * @return array|string
  16. * @throws \App\Exceptions\Api\LoginException
  17. */
  18. public function get_share_image(LearnRecord $learnRecordModel, Course $courseModel)
  19. {
  20. // 登录信息
  21. $uid = $this->checkLogin();
  22. //$uid = 7741;
  23. // 接收参数
  24. $courseId = request('course_id',0);
  25. $fontPath = public_path().'/fonts/msyh14.ttf';// 指定字体文件路径
  26. //学习课程名称
  27. $courseName = $courseModel->query()->where([['id','=',$courseId]])->value('name');
  28. $courseName = str_replace(' ', '', $courseName); //去除课程名称中的空格
  29. //获取总积分(客户)
  30. $totalScore = $learnRecordModel->query()->where([['course_id','=',$courseId], ['custom_uid','=',$uid]])->sum('get_score');
  31. try {
  32. // 加载图片
  33. $image = Image::make(public_path('uploads/images/default/') . 'learn_report_share_base.png');
  34. $lineHeight = 30; // 行高
  35. $fontSize = 24;
  36. $maxWidth = 330;
  37. // 课程名称过长的时候需要截断
  38. $lines = $this->truncateText($courseName, $fontPath, $fontSize, $maxWidth);
  39. $y = 170; // 初始 y 坐标
  40. foreach ($lines as $line) {
  41. $image->text($line, 30, $y, function ($font) use ($fontPath, $fontSize) {
  42. $font->file($fontPath);
  43. $font->size($fontSize);
  44. $font->color('#2B3D7c');
  45. $font->align('left');
  46. });
  47. $y += $lineHeight; // 下一行的 y 坐标
  48. }
  49. // 给图片写入文字(课程名称)
  50. // $image->text($courseName, 30, 170, function (Font $font) use ($fontPath) {
  51. // $font->file($fontPath); // 字体文件地址
  52. // $font->size(24); // 字体大小
  53. // $font->color('#2B3D7c');
  54. // $font->align('left');
  55. // });
  56. // 给图片写入文字(总积分)
  57. $image->text($totalScore, 90, 310, function (Font $font) use ($fontPath) {
  58. $font->file($fontPath); // 字体文件地址
  59. $font->size(30); // 字体大小
  60. $font->color('#E86D8F');
  61. $font->align('center');
  62. });
  63. //TODO 测试的时候用
  64. //$outputImagePath = public_path('uploads/images/default/output.jpg'); // 替换为你希望保存的路径
  65. //$image->save($outputImagePath);
  66. $image = $image->encode('jpg', 90)->__toString();
  67. // 转base64
  68. $base64 = 'data:image/jpg;base64,' . base64_encode($image);
  69. return json_send(['code'=>'success','msg'=>'图片生成成功','data'=>$base64]);
  70. //return $base64;
  71. } catch (\Throwable $th) {
  72. // 返回路径
  73. //return ['error'=>$th->getMessage()];
  74. return json_send(['code'=>'error','msg'=>'图片生成失败', 'errorCode'=>$th->getMessage()]);
  75. }
  76. }
  77. //获取课后分析的答题数量
  78. public function get_after_study_report_image_share(LearnRecord $learnRecordModel)
  79. {
  80. // 登录信息(客户id)
  81. $uid = $this->checkLogin();
  82. //$uid = 7741;
  83. // 接收参数
  84. $courseId = request('course_id',0);
  85. //获取总积分(客户)
  86. $totalQuestionNum = $learnRecordModel->query()->where([['course_id','=',$courseId], ['custom_uid','=',$uid]])->sum('question_total');
  87. $correctNum = $learnRecordModel->query()->where([['course_id','=',$courseId], ['custom_uid','=',$uid]])->sum('isanswer_total');
  88. $inCorrectNum = $totalQuestionNum - $correctNum;
  89. $accuracy = $correctNum/$totalQuestionNum * 100;
  90. $url = 'pages/index/index';
  91. $position = 'bottom-left';
  92. $size = request('size',150);
  93. $scene = request('scene',0);
  94. $fontPath = public_path().'/fonts/msyh14.ttf';// 指定字体文件路径
  95. try {
  96. // 加载图片
  97. $image = Image::make(public_path('uploads/images/default/') . 'analysis_report_share_base.png');
  98. // // 生成小程序二维码
  99. $qrcode = Mini::getUnlimit($scene,['page'=>$url,'width'=>$size,'is_hyaline'=>true]);
  100. // // 错误提示
  101. if( isset($qrcode['error']) ) return $qrcode;
  102. if ($size < 280){
  103. // 加载图片 压缩
  104. $qrcode = Image::make($qrcode)->resize($size,$size);
  105. } else{
  106. // 加载图片
  107. $qrcode = Image::make($qrcode);
  108. }
  109. //插入二维码图片
  110. $image->insert($qrcode, $position,20,20);
  111. // 给图片写入文字总题数:
  112. $image->text($totalQuestionNum.'题', 260, 300, function (Font $font) use ($fontPath) {
  113. $font->file($fontPath); // 字体文件地址
  114. $font->size(24); // 字体大小
  115. $font->color('#FF7B01');
  116. $font->align('left');
  117. });
  118. // 给图片写入文字正确题数
  119. $image->text($correctNum.'题', 290, 388, function (Font $font) use ($fontPath) {
  120. $font->file($fontPath); // 字体文件地址
  121. $font->size(24); // 字体大小
  122. $font->color('#0E670F');
  123. $font->align('left');
  124. });
  125. // 给图片写入文字错误题数
  126. $image->text($inCorrectNum.'题', 290, 476, function (Font $font) use ($fontPath) {
  127. $font->file($fontPath); // 字体文件地址
  128. $font->size(24); // 字体大小
  129. $font->color('#FF0101');
  130. $font->align('left');
  131. });
  132. // 给图片写入文字 正确率
  133. $image->text($accuracy.'%', 100, 582, function (Font $font) use ($fontPath) {
  134. $font->file($fontPath); // 字体文件地址
  135. $font->size(36); // 字体大小
  136. $font->color('#FA9517');
  137. $font->align('left');
  138. });
  139. //TODO 测试的时候用
  140. //$outputImagePath = public_path('uploads/images/default/output_ana.jpg'); // 替换为你希望保存的路径
  141. //$image->save($outputImagePath);
  142. $image = $image->encode('jpg', 90)->__toString();
  143. // 转base64
  144. $base64 = 'data:image/jpg;base64,' . base64_encode($image);
  145. return json_send(['code'=>'success','msg'=>'图片生成成功','data'=>$base64]);
  146. } catch (\Throwable $th) {
  147. // 返回路径
  148. //return ['error'=>$th->getMessage()];
  149. return json_send(['code'=>'error','msg'=>'图片生成失败', 'errorCode'=>$th->getMessage()]);
  150. }
  151. }
  152. // 截断文字并添加省略号
  153. function truncateText($text, $fontFile, $fontSize, $maxWidth) {
  154. $lines = [];
  155. $textLength = mb_strlen($text);
  156. $charIndex = 0;
  157. // 第一行
  158. $firstLine = '';
  159. while ($charIndex < $textLength) {
  160. $firstLine .= mb_substr($text, $charIndex, 1);
  161. $testBox = imagettfbbox($fontSize, 0, $fontFile, $firstLine);
  162. $testWidth = abs($testBox[2] - $testBox[0]);
  163. if ($testWidth > $maxWidth) {
  164. // 第一行超出宽度,截断
  165. $firstLine = mb_substr($firstLine, 0, -1);
  166. break;
  167. }
  168. $charIndex++;
  169. }
  170. $lines[] = $firstLine;
  171. // 第二行
  172. if ($charIndex < $textLength) {
  173. $secondLine = mb_substr($text, $charIndex);
  174. $testBox = imagettfbbox($fontSize, 0, $fontFile, $secondLine);
  175. $testWidth = abs($testBox[2] - $testBox[0]);
  176. if ($testWidth > $maxWidth) {
  177. // 第二行超出宽度,截断并添加省略号
  178. while ($charIndex < $textLength) {
  179. $secondLine = mb_substr($secondLine, 0, -1);
  180. $testBox = imagettfbbox($fontSize, 0, $fontFile, $secondLine);
  181. $testWidth = abs($testBox[2] - $testBox[0]);
  182. if ($testWidth <= $maxWidth) {
  183. $secondLine .= '...';
  184. break;
  185. }
  186. }
  187. }
  188. $lines[] = $secondLine;
  189. }
  190. return $lines;
  191. }
  192. }