activity = $activity; // 当前用户id $this->user_id = $user ? $user['user_id'] : 0; $this->user = $user; //来源 $this->source = $source; } /** * 获取核销二维码 * @return mixed */ public function getVerifyImage() { // 保存目录 $savePath = $this->getPosterPath('verify'); // 删除目录下的文件 if(!$this->is_empty_dir($savePath)) { $this->deleteDir(substr($savePath, 0, -1)); } // mkdir($savePath, 0755, true); if ($this->source == 'wx') { // 下载小程序码 $scene = "activity_id:{$this->activity['activity_id']}"; print_r($scene);exit; $fileName = $this->saveBranchActivityQrcodeToDir($this->activity['app_id'], 'pages/branch/activity/detail/detail', $savePath, $scene); } else if ($this->source == 'mp' || $this->source == 'h5'){ $fileName = $this->saveBranchActivityVerifyMpQrcodeToDir('h5/pages/branch/activity/detail/detail',$savePath, $this->activity['activity_id'], $this->activity['app_id']); } if (!$fileName) { throw new BaseException(['msg' => '下载失败, 文件不存在']); } return $this->getVerifyUrl($fileName); // header('Content-Type: image/png'); // header('Content-disposition: attachment; filename='. $this->activity['name'] .'_'. $this->source . '.png'); // readfile($fullPath); // header('Content-Length: ' .filesize($fullPath)); } /** * @return mixed */ public function getImage() { // 判断海报图文件存在则直接返回url // if (file_exists($this->getPosterPath() . $this->getPosterName())) { // return $this->getPosterUrl(); // } // 小程序id $appId = $this->activity['app_id']; // 二维码区域背景 $mark_bg = __DIR__ . '/resource/activity_mark.png'; // 默认海报背景图 $backdrop = __DIR__ . '/resource/activity_bg.png'; // 如果上传了活动海报图 if ($this->activity['pic_id']) { $backdrop = $this->saveTempImage($appId, $this->activity['pic']['file_path'], 'activity'); } // 用户头像 if ($this->user['avatarUrl']) { $avatar = $this->saveTempImage($appId, $this->user['avatarUrl'], 'avatar'); } else { $avatar = base_url() . 'image/user/avatar.png'; } $qrcode = null; if($this->source == 'wx'){ // 小程序码参数 $scene = "activity_id:{$this->activity['activity_id']},uid:" . ($this->user_id ?: ''); // // 下载小程序码 // $qrcode = $this->saveQrcode($appId, $scene, $this->page); // 下载小程序码 $qrcode = $this->saveBranchActivityQrcodeToDir($this->activity['app_id'], 'pages/branch/activity/detail/detail', $this->getPosterPath(), $scene); }else if($this->source == 'mp' || $this->source == 'h5'){ $scene = "gid:{$this->activity['activity_id']},uid:" . ($this->user_id ?: ''); $qrcode = new QrCode(base_url().'h5/pages/activity/detail/detail?activity_id='.$this->activity['activity_id'].'&app_id='.$appId.'&referee_id='.$this->user_id ?: ''); $qrcode = $this->saveMpQrcode($qrcode, $appId, $scene, 'image_mp'); } // 拼接海报图 return $this->savePoster($backdrop, $mark_bg, $avatar, $qrcode); } /** * 拼接海报图 */ private function savePoster($backdrop, $mark_bg, $avatar, $qrcode) { // 实例化图像编辑器 $editor = Grafika::createEditor(['Gd']); // 字体文件路径 $fontPath = Grafika::fontsDir() . '/' . 'st-heiti-light.ttc'; // 打开海报背景图 $editor->open($backdropImage, $backdrop); // 打开活动图片 $editor->open($markImage, $mark_bg); // 重设活动图片宽高 $editor->resizeExact($backdropImage, 750, 1250); // 活动图片添加到背景图 $editor->blend($backdropImage, $markImage, 'normal', 1.0, 'top-left', 0, 0); // 活动名称处理换行 $fontSize = 22; $activityName = $this->wrapText($fontSize, 0, $fontPath, '邀您参加“'. $this->activity['name'] . '”', 460, 2); // 写入活动名称 $editor->text($backdropImage, $activityName, $fontSize, 228, 1092, new Color('#000000'), $fontPath); // 生成圆形用户头像 $this->circular($avatar, $avatar); // 打开用户头像 $editor->open($avatarImage, $avatar); // 重设活动图片宽高 $editor->resizeExact($avatarImage, 45, 45); // 头像添加到背景图 $editor->blend($backdropImage, $avatarImage, 'normal', 1.0, 'top-left', 228, 1026); // 添加用户名称 $user_name = $this->user['nickName'] ?: '匿名用户'; $editor->text($backdropImage, $user_name, 22, 288, 1036, new Color('#333333'), $fontPath); // 打开小程序码 $editor->open($qrcodeImage, $qrcode); // 重设小程序码宽高 $editor->resizeExact($qrcodeImage, 148, 148); // 小程序码添加到背景图 $editor->blend($backdropImage, $qrcodeImage, 'normal', 1.0, 'top-left', 60, 1020); // 保存图片 $editor->save($backdropImage, $this->getPosterPath() . $this->getPosterName()); return $this->getPosterUrl(); } /** * 处理文字超出长度自动换行 */ private function wrapText($fontsize, $angle, $fontface, $string, $width, $max_line = null) { // 这几个变量分别是 字体大小, 角度, 字体名称, 字符串, 预设宽度 $content = ""; // 将字符串拆分成一个个单字 保存到数组 letter 中 $letter = []; for ($i = 0; $i < mb_strlen($string, 'UTF-8'); $i++) { $letter[] = mb_substr($string, $i, 1, 'UTF-8'); } $line_count = 0; foreach ($letter as $l) { $testbox = imagettfbbox($fontsize, $angle, $fontface, $content . ' ' . $l); // 判断拼接后的字符串是否超过预设的宽度 if (($testbox[2] > $width) && ($content !== "")) { $line_count++; if ($max_line && $line_count >= $max_line) { $content = mb_substr($content, 0, -1, 'UTF-8') . "..."; break; } $content .= "\n"; } $content .= $l; } return $content; } /** * 海报图文件路径 */ private function getPosterPath($type = '') { $path = $type ? "branch/activity_{$type}_{$this->activity['activity_id']}/" : ''; // 保存路径 $tempPath = root_path('public') . 'temp' . '/' . $this->activity['app_id'] . '/' . $path . $this->source. '/'; !is_dir($tempPath) && mkdir($tempPath, 0755, true); return $tempPath; } /** * 海报图文件名称 */ private function getPosterName() { return 'activity_' . md5("{$this->user_id}_{$this->activity['activity_id']}") . '.png'; } /** * 海报图url */ private function getPosterUrl() { return \base_url() . 'temp/' . $this->activity['app_id'] . '/' .$this->source . '/' . $this->getPosterName() . '?t=' . time(); } /** * 核销码url */ private function getVerifyUrl($fileName) { $path = "branch/activity_verify_{$this->activity['activity_id']}/"; return \base_url() . 'temp/' . $this->activity['app_id'] . '/' .$path . $this->source . '/' . $fileName . '?t=' . time(); } /** * 生成圆形图片 */ private function circular($imgpath, $saveName = '') { $srcImg = imagecreatefromstring(file_get_contents($imgpath)); $w = imagesx($srcImg); $h = imagesy($srcImg); $w = $h = min($w, $h); $newImg = imagecreatetruecolor($w, $h); // 这一句一定要有 imagesavealpha($newImg, true); // 拾取一个完全透明的颜色,最后一个参数127为全透明 $bg = imagecolorallocatealpha($newImg, 255, 255, 255, 127); imagefill($newImg, 0, 0, $bg); $r = $w / 2; //圆半径 for ($x = 0; $x < $w; $x++) { for ($y = 0; $y < $h; $y++) { $rgbColor = imagecolorat($srcImg, $x, $y); if (((($x - $r) * ($x - $r) + ($y - $r) * ($y - $r)) < ($r * $r))) { imagesetpixel($newImg, $x, $y, $rgbColor); } } } // 输出图片到文件 imagepng($newImg, $saveName); // 释放空间 imagedestroy($srcImg); imagedestroy($newImg); } private function is_empty_dir($fp) { if(!file_exists($fp)){ return false; } $H = @ opendir($fp); $i=0; while($_file=readdir($H)){ $i++; } closedir($H); if($i>2){ return false; }else{ return true; } } /** * 删除当前目录及其目录下的所有目录和文件 * @param string $path 待删除的目录 * @note $path路径结尾不要有斜杠/(例如:正确[$path='./static/image'],错误[$path='./static/image/']) */ private function deleteDir($path) { if (is_dir($path)) { //扫描一个目录内的所有目录和文件并返回数组 $dirs = scandir($path); foreach ($dirs as $dir) { //排除目录中的当前目录(.)和上一级目录(..) if ($dir != '.' && $dir != '..') { //如果是目录则递归子目录,继续操作 $sonDir = $path.'/'.$dir; if (is_dir($sonDir)) { //递归删除 $this->deleteDir($sonDir); //目录内的子目录和文件删除后删除空目录 @rmdir($sonDir); } else { //如果是文件直接删除 @unlink($sonDir); } } } @rmdir($path); } } }