Canvas.php 8.9 KB

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