Poster.php 10 KB

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