Poster.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. <?php
  2. namespace extend;
  3. use Intervention\Image\ImageManagerStatic as Image;
  4. class Poster
  5. {
  6. private $poster;
  7. private $width;
  8. private $height;
  9. public function __construct($width, $height)
  10. {
  11. $this->width = $width;
  12. $this->height = $height;
  13. $this->poster = imagecreatetruecolor($width, $height);
  14. }
  15. /**
  16. * 设置背景色
  17. * @param unknown $red
  18. * @param unknown $green
  19. * @param unknown $blue
  20. */
  21. public function setBackground($red, $green, $blue)
  22. {
  23. $color = $this->createColor($red, $green, $blue);
  24. imagefilledrectangle($this->poster, 0, 0, $this->width, $this->height, $color);
  25. }
  26. /**
  27. * 创建颜色
  28. * @param unknown $red
  29. * @param unknown $green
  30. * @param unknown $blue
  31. * @return number
  32. */
  33. private function createColor($red, $green, $blue)
  34. {
  35. $color = imagecolorallocate($this->poster, $red, $green, $blue);
  36. return $color;
  37. }
  38. /**
  39. * 创建透明色
  40. * @param unknown $red
  41. * @param unknown $green
  42. * @param unknown $blue
  43. * @param unknown $alpha 0不透明 127完全透明
  44. */
  45. public function createAlphaColor($red, $green, $blue, $alpha)
  46. {
  47. $color = imagecolorallocatealpha($this->poster, $red, $green, $blue, $alpha);
  48. return $color;
  49. }
  50. /**
  51. * 将图片写入海报
  52. * @param unknown $image_path
  53. * @param unknown $x
  54. * @param unknown $y
  55. * @param unknown $width
  56. * @param unknown $height
  57. */
  58. public function imageCopy($image_path, $x, $y, $width, $height, $shape, int $radius = 0, $is_view)
  59. {
  60. if ($shape == 'square') {
  61. $image = $this->getImageResources($image_path);
  62. if ($radius > 0) $image = $this->radius($image_path, $radius);
  63. } else {
  64. $image = $this->circular($image_path);
  65. }
  66. if ($is_view > 0) {
  67. imagecopyresampled($this->poster, $image[ 'image' ], $x, $y, 0, 0, $width, $height, $image[ 'width' ], $image[ 'height' ]);
  68. }
  69. }
  70. /**
  71. * 将图片转为圆形后写入海报
  72. * @param unknown $image_path
  73. * @param unknown $x
  74. * @param unknown $y
  75. * @param unknown $width
  76. * @param unknown $height
  77. */
  78. public function imageCircularCopy($image_path, $x, $y, $width, $height)
  79. {
  80. $image = $this->circular($image_path);
  81. imagecopyresampled($this->poster, $image[ 'image' ], $x, $y, 0, 0, $width, $height, $image[ 'width' ], $image[ 'height' ]);
  82. }
  83. /**
  84. * 将文字写入海报
  85. * @param string $text
  86. * @param int $size 文字大小
  87. * @param array $color 文字颜色 [$red, $green, $blue]
  88. * @param int $x x轴起始点
  89. * @param int $y y轴起始点
  90. * @param number $max_width 最大宽度
  91. * @param number $max_line 最大行数
  92. * @param string $blod 是否加粗
  93. */
  94. public function imageText(string $text, int $size, array $color, int $x, int $y, $max_width = 0, $max_line = 1, $blod = false, $is_view = 1, $fontfile = PUBLIC_PATH . 'static/font/Microsoft.ttf')
  95. {
  96. $text = $this->handleStr($text, $size, $max_width, $max_line, $fontfile);
  97. $color = $this->createColor(...$color);
  98. if ($is_view > 0) {
  99. imagettftext($this->poster, $size, 0, $x, $y, $color, $fontfile, $text);
  100. // if ($blod) imagettftext($this->poster, $size, 0, ( $x + 1 ), ( $y + 1 ), $color, $fontfile, $text);
  101. }
  102. }
  103. /**
  104. * 字符串处理
  105. * @param unknown $str
  106. * @param unknown $size
  107. * @param unknown $max_width
  108. * @param unknown $max_line
  109. */
  110. private function handleStr($str, $size, $max_width, $max_line, $fontfile)
  111. {
  112. if (empty($str)) return $str;
  113. mb_internal_encoding("UTF-8");
  114. $letter = [];
  115. $content = '';
  116. $line = 1;
  117. for ($i = 0; $i < mb_strlen($str); $i++) {
  118. $letter[] = mb_substr($str, $i, 1);
  119. }
  120. foreach ($letter as $l) {
  121. $temp_str = $content . " " . $l;
  122. $fontBox = imagettfbbox($size, 0, $fontfile, $temp_str);
  123. if (( $fontBox[ 2 ] > $max_width ) && ( $content !== "" )) {
  124. $content .= "\n";
  125. $line += 1;
  126. }
  127. if ($line <= $max_line) {
  128. $content .= $l;
  129. } else {
  130. $content = mb_substr($content, 0, ( mb_strlen($content) - 2 )) . '...';
  131. break;
  132. }
  133. }
  134. return $content;
  135. }
  136. /**
  137. * 将图片转正圆
  138. * @param unknown $filename
  139. */
  140. private function circular($filename)
  141. {
  142. $image_info = $this->getImageResources($filename);
  143. $width = min($image_info[ 'width' ], $image_info[ 'height' ]);
  144. $height = $width;
  145. // 如果图片不是正方形
  146. if ($image_info[ 'width' ] != $image_info[ 'height' ]) {
  147. $temp_file_path = 'upload/temp_' . uniqid() . '.' . $image_info[ 'ext' ];
  148. $image_manager = Image::make($filename)->fit($width, $height, function($constraint) {
  149. }, 'center');
  150. $image_manager->save($temp_file_path);
  151. $image_info = $this->getImageResources($temp_file_path);
  152. unlink($temp_file_path);
  153. }
  154. $image = imagecreatetruecolor($width, $height);
  155. imagesavealpha($image, true);
  156. $bg = imagecolorallocatealpha($image, 255, 255, 255, 127);
  157. imagefill($image, 0, 0, $bg);
  158. $r = $width / 2; //圆半径
  159. $y_x = $r; //圆心X坐标
  160. $y_y = $r; //圆心Y坐标
  161. for ($x = 0; $x < $width; $x++) {
  162. for ($y = 0; $y < $height; $y++) {
  163. $rgbColor = imagecolorat($image_info[ 'image' ], $x, $y);
  164. if (( ( ( $x - $r ) * ( $x - $r ) + ( $y - $r ) * ( $y - $r ) ) < ( $r * $r ) )) {
  165. imagesetpixel($image, $x, $y, $rgbColor);
  166. }
  167. }
  168. }
  169. $image_info[ 'image' ] = $image;
  170. return $image_info;
  171. }
  172. /**
  173. * 图片设置圆角
  174. * @param string $filename
  175. * @param int $radius
  176. */
  177. private function radius(string $filename, int $radius)
  178. {
  179. $image_info = $this->getImageResources($filename);
  180. // 创建画布
  181. $image = imagecreatetruecolor($image_info[ 'width' ], $image_info[ 'height' ]);
  182. imagesavealpha($image, true);
  183. $bg = imagecolorallocatealpha($image, 255, 255, 255, 127); // 创建一个完全透明色
  184. imagefill($image, 0, 0, $bg);
  185. for ($x = 0; $x < $image_info[ 'width' ]; $x++) {
  186. for ($y = 0; $y < $image_info[ 'height' ]; $y++) {
  187. $rgb_color = imagecolorat($image_info[ 'image' ], $x, $y);//获取像素索引
  188. if (( $x >= $radius && $x <= ( $image_info[ 'width' ] - $radius ) ) || ( $y >= $radius && $y <= ( $image_info[ 'height' ] - $radius ) )) {
  189. //不在四角的范围内,直接画
  190. imagesetpixel($image, $x, $y, $rgb_color);
  191. } else {
  192. //在四角的范围内选择画
  193. //上左
  194. $y_x = $radius; //圆心X坐标
  195. $y_y = $radius; //圆心Y坐标
  196. if (( ( ( $x - $y_x ) * ( $x - $y_x ) + ( $y - $y_y ) * ( $y - $y_y ) ) <= ( $radius * $radius ) )) {
  197. imagesetpixel($image, $x, $y, $rgb_color);
  198. }
  199. //上右
  200. $y_x = $image_info[ 'width' ] - $radius; //圆心X坐标
  201. $y_y = $radius; //圆心Y坐标
  202. if (( ( ( $x - $y_x ) * ( $x - $y_x ) + ( $y - $y_y ) * ( $y - $y_y ) ) <= ( $radius * $radius ) )) {
  203. imagesetpixel($image, $x, $y, $rgb_color);
  204. }
  205. //下左
  206. $y_x = $radius; //圆心X坐标
  207. $y_y = $image_info[ 'height' ] - $radius; //圆心Y坐标
  208. if (( ( ( $x - $y_x ) * ( $x - $y_x ) + ( $y - $y_y ) * ( $y - $y_y ) ) <= ( $radius * $radius ) )) {
  209. imagesetpixel($image, $x, $y, $rgb_color);
  210. }
  211. //下右
  212. $y_x = $image_info[ 'width' ] - $radius; //圆心X坐标
  213. $y_y = $image_info[ 'height' ] - $radius; //圆心Y坐标
  214. if (( ( ( $x - $y_x ) * ( $x - $y_x ) + ( $y - $y_y ) * ( $y - $y_y ) ) <= ( $radius * $radius ) )) {
  215. imagesetpixel($image, $x, $y, $rgb_color);
  216. }
  217. }
  218. }
  219. }
  220. $image_info[ 'image' ] = $image;
  221. return $image_info;
  222. }
  223. /**
  224. * 划线
  225. * @param $x1
  226. * @param $y1
  227. * @param $x2
  228. * @param $y2
  229. */
  230. private function imageline($x1, $y1, $x2, $y2, $rgb){
  231. $color = $this->createColor(...$rgb);
  232. imageline($this->poster, $x1, $y1, $x2, $y2, $color);
  233. }
  234. /**
  235. * 创建海报内容
  236. * @param unknown $data
  237. * @return \extend\Poster|multitype:
  238. */
  239. public function create($data)
  240. {
  241. try {
  242. foreach ($data as $item) {
  243. $action = $item[ 'action' ];
  244. $this->$action(...$item[ 'data' ]);
  245. }
  246. return $this;
  247. } catch (\Exception $e) {
  248. return error(-1, $e->getMessage() . $e->getFile() . $e->getLine());
  249. }
  250. }
  251. /**
  252. * 获取图片资源
  253. * @param $filename
  254. * @return array
  255. */
  256. private function getImageResources($filename)
  257. {
  258. try {
  259. [ 0 => $width, 1 => $height, 'mime' => $mime ] = getimagesize($filename);
  260. } catch (\Exception $e) {
  261. $filename = 'public/static/img/default_img/square.png'; // 默认图片
  262. [ 0 => $width, 1 => $height, 'mime' => $mime ] = getimagesize($filename);
  263. }
  264. $ext = explode('/', $mime)[ 1 ];
  265. switch ( $ext ) {
  266. case "png":
  267. $image = @imagecreatefrompng($filename);
  268. break;
  269. case "jpeg":
  270. $image = @imagecreatefromjpeg($filename);
  271. break;
  272. case "jpg":
  273. $image = @imagecreatefromjpeg($filename);
  274. break;
  275. case "gif":
  276. $image = @imagecreatefromgif($filename);
  277. break;
  278. case "webp":
  279. $image = @imagecreatefromwebp($filename);
  280. break;
  281. }
  282. return [
  283. 'width' => $width,
  284. 'height' => $height,
  285. 'mime' => $mime,
  286. 'ext' => $ext,
  287. 'image' => $image
  288. ];
  289. }
  290. /**
  291. * 校验目录是否可写
  292. * @param $path
  293. * @return array
  294. */
  295. private function checkPath($path)
  296. {
  297. if (is_dir($path) || mkdir($path, intval('0755', 8), true)) {
  298. return success();
  299. }
  300. return error(-1, "directory {$path} creation failed");
  301. }
  302. /**
  303. * 输出jpeg格式的海报
  304. * @param string $path 图片生成路径
  305. * @param string $name 图片名称
  306. */
  307. public function jpeg($path, $name)
  308. {
  309. $check_res = $this->checkPath($path);
  310. if ($check_res[ 'code' ] < 0) return $check_res;
  311. try {
  312. $filename = $path . '/' . $name . '.jpg';
  313. header("Content-type: image/jpeg"); // 定义输出类型
  314. imagejpeg($this->poster, $filename, 100); // 输出图片
  315. imagedestroy($this->poster); // 销毁图片资源
  316. header("Content-type: text/plain");
  317. return success(0, '', [ 'path' => $filename ]);
  318. } catch (\Exception $e) {
  319. return error(-1, $e->getMessage());
  320. }
  321. }
  322. }