<?php /** * Created by PhpStorm. * User: Zero * Date: 2020/7/27 * Time: 11:44 */ namespace Meibuyu\Micro\Tools; use Exception; use Hyperf\Contract\ConfigInterface; use PhpOffice\PhpSpreadsheet\Worksheet\Drawing; use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; class Drawer { /** * @var ConfigInterface */ protected $config; private $rootPath; private $savePath = ''; private $ossDomain = 'http://huaperfect-file-service.oss-cn-hangzhou.aliyuncs.com'; public function __construct() { $this->config = container(ConfigInterface::class); $this->rootPath = $this->config->get('server.settings.document_root', BASE_PATH . '/public'); } private function parseImagePath($imagePath) { if (strstr($imagePath, 'http') !== false) { $imagePath = $this->downloadWebImage($imagePath); } return $imagePath; } /** * 下载网络图片 * @param string $url * @param string $path * @return string */ public function downloadWebImage($url, $path = null) { $url = $this->parseUrl($url); // excel画图中下载图片时对图片名做urlencode处理,防止中文名不能正常画图片的bug $pathinfo = pathinfo($url); $filename = trim($pathinfo['filename']); $ext = strtolower($pathinfo['extension']); $filename = "$filename.$ext"; $savePath = $this->parseSavePath($pathinfo['dirname'], $path); if (!is_dir($savePath)) { // 判断路径是否存在,不存在,则创建 mkdir($savePath, 0777, true); } $filePath = $savePath . '/' . $filename; if (!file_exists($filePath)) { $ch = curl_init(); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 信任任何证书 curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30); $file = curl_exec($ch); curl_close($ch); $resource = fopen($filePath, 'a'); fwrite($resource, $file); fclose($resource); } return $filePath; } private function parseUrl($url) { if (!preg_match('/%[0-9A-Z]{2}/', $url)) { $url = rawurlencode($url); $url = str_replace("%3A", ":", $url); $url = str_replace("%2F", "/", $url); $url = str_replace("%3F", "?", $url); $url = str_replace("%3D", "=", $url); $url = str_replace("%26", "&", $url); } return $this->handleOssUrl($url); } /** * 处理保存路径 * @param $dirname * @param $path * @return string * @author Zero */ private function parseSavePath($dirname, $path) { $path = trim($path, '/'); $path = $this->rootPath . '/download/images/' . ($path ?: $this->savePath) . '/'; if (strstr($dirname, $this->ossDomain) !== false) { // 以oss的原路径为保存路径 $dirname = str_replace($this->ossDomain, '', $dirname); $dirname = trim($dirname, '/'); $path = $path . $dirname . '/'; } return $path; } // 替换阿里云图片内部地址 private function handleOssUrl($url) { if ($this->config->get('app_env') !== 'dev') { $url = str_replace('oss-cn-hangzhou.aliyuncs.com', 'oss-accelerate.aliyuncs.com', $url); $this->ossDomain = 'http://huaperfect-file-service.oss-accelerate.aliyuncs.com'; } return $url; } /** * description:下载文件到服务端 增加判断是否是webp 格式的图片处理 * author: fuyunnan * @param string $url * @param string $path 文件路径 * @return string * @throws * Date: 2020/11/20 */ public function downLoadImgWebpChannel($url, $path = '') { $originUrl = $url; //如果shopify 去掉版本号 if (strpos($url, 'shopify') !== false) { $url = substr($url, 0, strpos($url, '?v=')); } $savePath = $this->rootPath . '/download/images/' . ($path ? $path . '/' : $this->savePath); create_file_dir($savePath); $filePath = $this->toWebpImg($url, $savePath); if (!file_exists($filePath)) { $filename = trim(pathinfo($url, PATHINFO_FILENAME)); $ext = strtolower(pathinfo($url, PATHINFO_EXTENSION)); $filePath = $savePath . "$filename.$ext"; $ch = curl_init(); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 信任任何证书 curl_setopt($ch, CURLOPT_URL, $originUrl); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30); $file = curl_exec($ch); curl_close($ch); $resource = fopen($filePath, 'a'); fwrite($resource, $file); fclose($resource); $filePath = $this->toWebpImg($filePath, $savePath); } return $filePath; } /** * description:将图像绘到excel表格上 * author: fuyunnan * @param string $url 图片地址 * @param string $childPath 图片地址 用sku名作为文件夹名称 * @param int $h 图片高度 * @param string $p 单元格索引 * @param Worksheet $sheet * @return void * @throws * Date: 2020/11/23 */ public function drawImgExcel($url, $childPath, $h, $p, $sheet) { try { //下载图片到本地 $absPath = $this->downLoadImgWebpChannel($url, $childPath); $drawing = new Drawing(); $drawing->setPath($absPath) ->setCoordinates($p) ->setHeight($h) ->setOffsetX(1) ->setOffsetY(1) ->setWorksheet($sheet); } catch (Exception $e) { put_log($e->getMessage(), 'draw2Excel.log'); } } /** * description:检查文件是否是webp格式的文件 * 如果是,转化为jpeg格式的文件,并且返回文件的绝对地址. * author: fuyunnan * @param string $filePath 文件的绝对地址 * @param string $savePath 文件重新保存的地址 * @return string * @throws * Date: 2020/11/23 */ private function toWebpImg($filePath, $savePath) { $filename = trim(pathinfo($filePath, PATHINFO_FILENAME)); $ext = strtolower(pathinfo($filePath, PATHINFO_EXTENSION)); $imgInfo = ''; //如果存在直接返回 防止每次获取文件资源 if (file_exists($savePath . "$filename.$ext")) { return $savePath . "$filename.$ext"; } $filePath && $imgInfo = getimagesize($filePath); if ($imgInfo && end($imgInfo) == "image/webp") { $filename = trim(pathinfo($filePath, PATHINFO_FILENAME)); $im = imagecreatefromwebp($filePath); // 加载 WebP 文件 switch ($ext) { case 'jpg': $toNewFileName = $savePath . $filename . '.jpg'; break; case 'png': $toNewFileName = $savePath . $filename . '.png'; break; case 'jpeg': $toNewFileName = $savePath . $filename . '.jpeg'; break; default: $toNewFileName = $savePath . $filename . '.jpeg'; break; } imagejpeg($im, $toNewFileName, 30);//转化图片比例 imagedestroy($im); return $toNewFileName; } return $savePath . "$filename.$ext"; } /** * @param $imgPath * @param int $px * @return bool|string * @throws Exception */ public function addBoard($imgPath, $px = 2) { $imgPath = $this->parseImagePath($imgPath); $imgPathInfo = pathinfo($imgPath); $filename = $imgPathInfo['filename']; // 图片名称 $ext = $this->getImgExt($imgPath); [$img_w, $img_h] = getimagesize($imgPath); // 图片大小 $savePath = $this->rootPath . '/download/board/' . $this->savePath; if (!is_dir($savePath)) { // 判断路径是否存在,不存在,则创建 mkdir($savePath, 0777, true); } $imgNewPath = $savePath . '/' . $filename . '.' . $ext; if (file_exists($imgNewPath)) { return $imgNewPath; } switch ($ext) { case 'jpeg': case 'jpg': $img_create_func = 'imagecreatefromjpeg'; $img_save_func = 'imagejpeg'; break; case 'png': $img_create_func = 'imagecreatefrompng'; $img_save_func = 'imagepng'; break; case 'bmp': $img_create_func = 'imagecreatefrombmp'; $img_save_func = 'imagebmp'; break; case 'gif': $img_create_func = 'imagecreatefromgif'; $img_save_func = 'imagegif'; break; case 'vnd.wap.wbmp': $img_create_func = 'imagecreatefromwbmp'; $img_save_func = 'imagewbmp'; break; case 'xbm': $img_create_func = 'imagecreatefromxbm'; $img_save_func = 'imagexbm'; break; default: throw new Exception("图片类型不支持"); } // 黑色背景图片 $im = @imagecreatetruecolor(($img_w + $px), ($img_h + $px)) or die ("Cannot Initialize new GD image stream"); // 为真彩色画布创建背景,再设置为透明 $color = imagecolorallocate($im, 0, 0, 0); imagefill($im, 0, 0, $color); imageColorTransparent($im, $color); // 把图片放到黑色背景图片上。边框是1px $resource = $img_create_func($imgPath); imagecopy($im, $resource, $px / 2, $px / 2, 0, 0, $img_w, $img_h); $res = $img_save_func($im, $imgNewPath); imagedestroy($im); return $res ? $imgNewPath : false; } /** * 拼图 * @param $imgPathList * @param string $name * @return bool|string */ public function mergeImages($imgPathList, $name = '') { $maxW = $maxH = 0; $filenameList = []; $imageList = []; foreach ($imgPathList as $k => $path) { $path = $this->parseImagePath($path); $imgPathInfo = pathinfo($path); $filename = $imgPathInfo['filename']; // 图片名称 $ext = $imgPathInfo['extension']; // 图片扩展名 [$w, $h] = getimagesize($path); // 图片大小 $imageList[$k] = [ 'path' => $path, 'filename' => $filename, 'ext' => $ext, 'w' => $w, 'h' => $h, ]; $filenameList[] = $filename; $maxW += $w; if ($maxH < $h) { $maxH = $h; } } $filenameList = collect($filenameList)->unique()->sort()->toArray(); $filename = implode('_', $filenameList); $savePath = $this->rootPath . '/download/merge/' . $this->savePath; if (!is_dir($savePath)) { // 判断路径是否存在,不存在,则创建 mkdir($savePath, 0777, true); } $imgNewPath = $savePath . '/' . ($name ?: $filename) . '.png'; if (file_exists($imgNewPath)) { return $imgNewPath; } // 黑色背景图片 $im = @imagecreatetruecolor($maxW, $maxH) or die ("Cannot Initialize new GD image stream"); // 为真彩色画布创建背景,再设置为透明 $color = imagecolorallocate($im, 0, 0, 0); imagefill($im, 0, 0, $color); imageColorTransparent($im, $color); // 循环画图片 $dstX = 0; foreach ($imageList as $item) { $resource = imagecreatefromstring(file_get_contents($item['path'])); imagecopy($im, $resource, $dstX, 0, 0, 0, $item['w'], $item['h']); $dstX += $item['w']; } $res = imagepng($im, $imgNewPath); imagedestroy($im); return $res ? $imgNewPath : false; } /** * 画图片 * @param string $path 图片路径 * @param int $h 图片高度 * @param string $p 单元格索引 * @param Worksheet $sheet * @param int $boardPx */ public function draw2Excel($path, $h, $p, $sheet, $boardPx = 0) { try { $path = $this->parseImagePath($path); if ($boardPx) { $path = $this->addBoard($path, $boardPx); } $drawing = new Drawing(); $drawing->setPath($path)->setCoordinates($p)->setHeight($h)->setOffsetX(1)->setOffsetY(1)->setWorksheet($sheet); } catch (Exception $e) { put_log($e->getMessage(), 'draw2Excel.log'); } } public function setSavePath($path) { $this->savePath = trim($path, '/'); } /** * 获取图片扩展名 * @param $path * @return bool|mixed|string * @author Zero */ public function getImgExt($path) { $ext = false; $info = getimagesize($path); if (isset($info['mime']) && $info['mime']) { $ext = explode('/', $info['mime'])[1]; } else { $ext = strtolower(pathinfo($path, PATHINFO_EXTENSION)); $ext = explode('?', $ext)[0] ?? $ext; } return $ext; } }