您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

Canvas.php 9.2KB

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