Canvas.php 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
  8. // +----------------------------------------------------------------------
  9. // | Author: CRMEB Team <admin@crmeb.com>
  10. // +----------------------------------------------------------------------
  11. namespace crmeb\utils;
  12. /**
  13. * Class Canvas
  14. * @package crmeb\utils
  15. * @method $this setFileName(string $fileName) 设置文件名
  16. * @method $this setPath(string $path) 设置存放路径
  17. * @method $this setImageType(string $imageType) 设置图片类型
  18. * @method $this setBackgroundHeight(int $backgroundHeight) 设置背景高
  19. * @method $this setBackgroundWidth(int $backgroundWidth) 设置背景宽
  20. * @method $this setFontSize(int $fontSize) 设置字体大小
  21. * @method $this setFontColor($fontColor) 设置字体颜色
  22. * @method $this setFontLeft(int $fontLeft) 设置字体距离左侧位置
  23. * @method $this setFontTop(int $fontTop) 设置字体距离顶部位置
  24. * @method $this setFontText(string $fontText) 设置文字
  25. * @method $this setFontPath(string $fontPath) 设置字体文件路径
  26. * @method $this setFontAngle(int $fontAngle) 设置字体角度
  27. * @method $this setImageUrl(string $imageUrl) 设置图片路径
  28. * @method $this setImageLeft(int $imageLeft) 设置图片距离左侧位置
  29. * @method $this setImageTop(int $imageTop) 设置图片距离顶部位置
  30. * @method $this setImageRight(int $imageRight) 设置图片距离左侧位置
  31. * @method $this setImageStream(bool $imageStream) 设置图片是否未流文件
  32. * @method $this setImageBottom(int $imageBottom) 设置图片距离底部位置
  33. * @method $this setImageWidth(int $imageWidth) 设置图片宽
  34. * @method $this setImageHeight(int $imageHeight) 设置图片高
  35. * @method $this setImageOpacity(int $imageOpacity) 设置图片透明度
  36. */
  37. class Canvas
  38. {
  39. const FONT = 'statics/font/Alibaba-PuHuiTi-Regular.otf';
  40. /**
  41. * 背景宽
  42. * @var int
  43. */
  44. protected $backgroundWidth = 600;
  45. /**
  46. * 背景高
  47. * @var int
  48. */
  49. protected $backgroundHeight = 1000;
  50. /**
  51. * 图片类型
  52. * @var string
  53. */
  54. protected $imageType = 'jpeg';
  55. /**
  56. * 保存地址
  57. * @var string
  58. */
  59. protected $path = 'uploads/routine/';
  60. /**
  61. * 文件名
  62. * @var string
  63. */
  64. protected $fileName;
  65. /**
  66. * 规则
  67. * @var array
  68. */
  69. protected $propsRule = ['fileName', 'path', 'imageType', 'backgroundHeight', 'backgroundWidth'];
  70. /**
  71. * 字体数据集
  72. * @var array
  73. */
  74. protected $fontValue = [];
  75. /**
  76. * 字体默认可设置vlaue
  77. * @var array
  78. */
  79. protected $defaultFontValue = [
  80. 'fontSize' => 0,
  81. 'fontColor' => '231,180,52',
  82. 'fontLeft' => 0,
  83. 'fontTop' => 0,
  84. 'fontText' => '',
  85. 'fontPath' => self::FONT,
  86. 'fontAngle' => 0,
  87. ];
  88. protected $defaultFont;
  89. /**
  90. * 图片数据集
  91. * @var array
  92. */
  93. protected $imageValue = [];
  94. /**
  95. * 图片可设置属性
  96. * @var array
  97. */
  98. protected $defaultImageValue = [
  99. 'imageUrl' => '',
  100. 'imageLeft' => 0,
  101. 'imageTop' => 0,
  102. 'imageRight' => 0,
  103. 'imageBottom' => 0,
  104. 'imageWidth' => 0,
  105. 'imageHeight' => 0,
  106. 'imageOpacity' => 0,
  107. 'imageStream' => false,
  108. ];
  109. /**
  110. * 实例化本身
  111. * @var self
  112. */
  113. protected static $instance;
  114. protected $defaultImage;
  115. protected function __construct()
  116. {
  117. $this->defaultImage = $this->defaultImageValue;
  118. $this->defaultFont = $this->defaultFontValue;
  119. }
  120. /**
  121. * 实例化本类
  122. * @return Canvas
  123. */
  124. public static function instance()
  125. {
  126. if (is_null(self::$instance)) {
  127. self::$instance = new self();
  128. }
  129. return self::$instance;
  130. }
  131. /**
  132. * 创建一个新图象
  133. * @param string $file
  134. * @return array
  135. */
  136. public function createFrom(string $file): array
  137. {
  138. $file = str_replace('https', 'http', $file);
  139. $imagesize = getimagesize($file);
  140. $type = image_type_to_extension($imagesize[2], true);
  141. switch ($type) {
  142. case '.png':
  143. $canvas = imagecreatefrompng($file);
  144. break;
  145. case '.jpg':
  146. case '.jpeg':
  147. $canvas = imagecreatefromjpeg($file);
  148. break;
  149. case '.gif':
  150. $canvas = imagecreatefromgif($file);
  151. break;
  152. }
  153. return [$canvas, $imagesize];
  154. }
  155. /**
  156. * 放入字体
  157. * @return $this
  158. */
  159. public function pushFontValue()
  160. {
  161. array_push($this->fontValue, $this->defaultFontValue);
  162. $this->defaultFontValue = $this->defaultFont;
  163. return $this;
  164. }
  165. /**
  166. * 放入图片
  167. * @return $this
  168. */
  169. public function pushImageValue()
  170. {
  171. array_push($this->imageValue, $this->defaultImageValue);
  172. $this->defaultImageValue = $this->defaultImage;
  173. return $this;
  174. }
  175. /**
  176. * 创建背景
  177. * @param int $w
  178. * @param int $h
  179. * @return false|resource
  180. */
  181. public function createTrueColor(int $w = 0, int $h = 0)
  182. {
  183. return imagecreatetruecolor($w ? $w : $this->backgroundWidth, $h ? $h : $this->backgroundHeight);
  184. }
  185. /**
  186. * 开始画图
  187. * @param bool $force 生成错误时是否抛出异常
  188. * @return string
  189. * @throws \Exception
  190. */
  191. public function starDrawChart(bool $force = false): string
  192. {
  193. try {
  194. $image = $this->createTrueColor();
  195. foreach ($this->imageValue as $item) {
  196. if ($item['imageUrl']) {
  197. if ($item['imageStream']) {
  198. $res = getimagesizefromstring($item['imageUrl']);
  199. $mer = imagecreatefromstring($item['imageUrl']);
  200. } else {
  201. [$mer, $res] = $this->createFrom($item['imageUrl']);
  202. }
  203. if ($mer && $res) {
  204. $scrW = $res[0] ?? 0;
  205. $scrH = $res[1] ?? 0;
  206. $imageWidth = $item['imageWidth'] ?: $scrW;
  207. $imageHeight = $item['imageHeight'] ?: $scrH;
  208. imagecopyresampled($image, $mer, $item['imageLeft'], $item['imageTop'], $item['imageRight'], $item['imageBottom'], $imageWidth, $imageHeight, $scrW, $scrH);
  209. unset($scrW, $scrH, $imageWidth, $imageHeight, $res, $mer);
  210. }
  211. }
  212. }
  213. foreach ($this->fontValue as $val) {
  214. if (!is_array($val['fontColor']))
  215. $fontColor = explode(',', $val['fontColor']);
  216. else
  217. $fontColor = $val['fontColor'];
  218. if (count($fontColor) < 3)
  219. throw new \RuntimeException('fontColor Separation of thousand bits');
  220. [$r, $g, $b] = $fontColor;
  221. $fontColor = imagecolorallocate($image, $r, $g, $b);
  222. $val['fontLeft'] = $val['fontLeft'] < 0 ? $this->backgroundWidth - abs($val['fontLeft']) : $val['fontLeft'];
  223. $val['fontTop'] = $val['fontTop'] < 0 ? $this->backgroundHeight - abs($val['fontTop']) : $val['fontTop'];
  224. imagettftext($image, $val['fontSize'], $val['fontAngle'], $val['fontLeft'], $val['fontTop'], $fontColor, $val['fontPath'], $val['fontText']);
  225. unset($r, $g, $b, $fontColor);
  226. }
  227. if (is_null($this->fileName)) {
  228. $this->fileName = md5(time());
  229. }
  230. $strlen = stripos($this->path, 'uploads');
  231. $path = $this->path;
  232. if ($strlen !== false) {
  233. $path = substr($this->path, 8);
  234. }
  235. make_path($path, 4, true);
  236. $save_file = $this->path . $this->fileName . '.' . $this->imageType;
  237. switch ($this->imageType) {
  238. case 'jpeg':
  239. case 'jpg':
  240. imagejpeg($image, public_path() . $save_file, 70);
  241. break;
  242. case 'png':
  243. imagepng($image, public_path() . $save_file, 70);
  244. break;
  245. case 'gif':
  246. imagegif($image, public_path() . $save_file, 70);
  247. break;
  248. default:
  249. throw new \RuntimeException('Incorrect type set:' . $this->imageType);
  250. }
  251. imagedestroy($image);
  252. return $save_file;
  253. } catch (\Throwable $e) {
  254. if ($force || $e instanceof \RuntimeException)
  255. throw new \Exception($e->getMessage());
  256. return '';
  257. }
  258. }
  259. /**
  260. * Magic access..
  261. *
  262. * @param $method
  263. * @param $args
  264. * @return $this
  265. */
  266. public function __call($method, $args): self
  267. {
  268. if (0 === stripos($method, 'set') && strlen($method) > 3) {
  269. $method = lcfirst(substr($method, 3));
  270. }
  271. $imageValueKes = array_keys($this->defaultImageValue);
  272. $fontValueKes = array_keys($this->defaultFontValue);
  273. if (in_array($method, $imageValueKes)) {
  274. $this->defaultImageValue[$method] = array_shift($args);
  275. }
  276. if (in_array($method, $fontValueKes)) {
  277. $this->defaultFontValue[$method] = array_shift($args);
  278. }
  279. if (in_array($method, $this->propsRule)) {
  280. $this->{$method} = array_shift($args);
  281. }
  282. return $this;
  283. }
  284. }