├── .gitignore
├── .idea
├── .gitignore
├── imageManage.iml
├── modules.xml
├── php.xml
└── vcs.xml
├── README.md
├── composer.json
├── img.png
├── img_1.png
├── img_2.png
├── src
├── ImageMake.php
├── ImageMakeConfig.php
└── SourceHanSansSC-Medium.ttf
└── test
├── make.jpeg
├── make2.jpeg
└── test.php
/.gitignore:
--------------------------------------------------------------------------------
1 | /vendor/
2 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # 默认忽略的文件
2 | /shelf/
3 | /workspace.xml
4 | # 基于编辑器的 HTTP 客户端请求
5 | /httpRequests/
6 | # Datasource local storage ignored files
7 | /dataSources/
8 | /dataSources.local.xml
9 |
--------------------------------------------------------------------------------
/.idea/imageManage.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/php.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ImageMake
2 | 
3 |
4 | 使用GD库实现多图片与文字的合成处理
5 | * 项目重写,发布为 composer 包方便使用
6 | * 大幅删减和优化,完善的注释上手使用更简单
7 | * 自带思源黑体,可免费商用无需担心版权
8 |
9 | ### 安装
10 | composer require saopanda/image-make
11 |
12 | ### 使用
13 | 仅三个方法!支持链式调用,后面调用的会覆盖在前面之上
14 | 
15 | 
16 |
17 | #### ImageMakeConfig (可选)
18 | 提供了一些额外可更改的配置
19 | * 默认透明度开启
20 | * 全局默认字体大小 16,可在`str()`单独设置大小
21 | * 默认第一个调用`img()`传入的图片会被作为底图
22 | * 输出格式 `1=>GIF` `2=>JPG` `3=>PNG`,默认`png`
23 | * ⚠️ 所有待操作图片以及输出格式建议保持统一,可提升图片生成效率
24 | * 默认自带思源黑体,指定其他字体时请使用系统绝对路径,或[参考文档](https://www.php.net/manual/zh/function.imagettftext.php) ->`fontfile`
25 |
26 | ```php
27 | $config = new ImageMakeConfig();
28 | $config
29 | ->alpha(true) // 设置透明度支持
30 | ->fontSize(20) // 设置默认字体大小
31 | ->exportSize(1920, 1080) // 设置底图大小
32 | ->exportType(2) // 设置输出图片格式
33 | ->font('/font/abc'); // 设置默认字体
34 |
35 | ImageMake::new($config); // 传入 new()
36 | ImageMake::new(); // 使用默认设置
37 | ```
38 |
39 | #### img() 叠加图片
40 | * `$value` 图片路径 或 二进制字符串
41 | * `$x`, `$y` 位置,叠加在底图的哪里,默认左上角 0,0
42 | * `$new_width`, `$new_height` 把这张图拉伸为新宽高,不填为原图大小
43 | * 当此图被作为底图使用时,`$x, $y, $new_width, $new_height `参数无效
44 |
45 | ```php
46 | public function img(string $value, int $x = 0, int $y = 0, int $new_width = 0, int $new_height = 0)
47 | ```
48 |
49 | #### str() 叠加文字
50 | * `$value` 要叠加的文字
51 | * `$x`, `$y` 位置,注意:基点在文字左下角,非左上角
52 | * `$config` 配置数组:
53 |
54 | ```php
55 | [
56 | 'color' => string 支持带透明度的16进制颜色,
57 | 'size' => int 字体大小,
58 | 'wrap' => false | array [
59 | 20, // int 多少字自动换行
60 | 10 // int 行高
61 | ],
62 | 'font' => string 字体路径,
63 | 'deg' => int 旋转角度,设置排列方向,效果:左到右、上到下
64 | ]
65 | ```
66 |
67 | ```php
68 | public function str(string $value, int $x = 0, int $y = 10, array $config = [])
69 | ```
70 |
71 | #### get() 直接输出图片 或 输出图片文件路径
72 | * `$filepath` 指定输出的相对路径 + 文件名,否则直接输出图像
73 |
74 | ```php
75 | public function get(string $filepath = null)
76 | ```
77 |
78 | #### demo
79 | 见 `./test/test.php`
80 |
81 | 快速启动测试
82 | ```
83 | cd ./test/
84 | php -S localhost:8080
85 | ```
86 |
87 | ### 其他
88 | * 思源黑体 https://github.com/adobe-fonts/source-han-sans/tree/release
89 | * GD 和图像处理 函数 https://www.php.net/manual/zh/ref.image.php
90 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "saopanda/image-make",
3 | "description": "使用GD库实现多图片与文字的合成处理",
4 | "type": "library",
5 | "license": "MIT",
6 | "autoload": {
7 | "psr-4": {
8 | "saopanda\\": "src/"
9 | }
10 | },
11 | "authors": [
12 | {
13 | "name": "saopanda"
14 | }
15 | ],
16 | "require": {
17 | "ext-gd": "*",
18 | "ext-mbstring": "*",
19 | "ext-json": "*"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/img.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Saopanda/ImageMake/c27beb6352909dc69153677a3010d88f11f881f9/img.png
--------------------------------------------------------------------------------
/img_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Saopanda/ImageMake/c27beb6352909dc69153677a3010d88f11f881f9/img_1.png
--------------------------------------------------------------------------------
/img_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Saopanda/ImageMake/c27beb6352909dc69153677a3010d88f11f881f9/img_2.png
--------------------------------------------------------------------------------
/src/ImageMake.php:
--------------------------------------------------------------------------------
1 | config = $config->config;
33 | return self::$instance;
34 | }
35 |
36 | /**
37 | * 处理背景图
38 | * @param string $value
39 | * @return bool 是否需要继续处理
40 | */
41 | private function makeBGImg(string $value): bool
42 | {
43 | if ($this->bgImg) return true;
44 | list($width,$height) = [$this->config['width'],$this->config['height']];
45 |
46 | if ($width != 0 && $height != 0){
47 | // 创建指定大小的空底图
48 | $this->bgImg = imagecreatetruecolor($width,$height);
49 | imagesavealpha($this->bgImg,$this->config['alpha']);
50 | return true;
51 | }else{
52 | // 根据图片创建底图
53 | $this->bgImg = imagecreatefromstring($value);
54 | imagesavealpha($this->bgImg,$this->config['alpha']);
55 | $this->config['width'] = $width;
56 | $this->config['height'] = $height;
57 | return false;
58 | }
59 | }
60 |
61 | /**
62 | * 叠加图片
63 | * @param string $value 图片路径|二进制字符串
64 | * @param int $x 相对于底图的 X 坐标
65 | * @param int $y 相对于底图的 Y 坐标
66 | * @param int $new_width 图片的新宽度
67 | * @param int $new_height 图片的新高度
68 | * @return $this
69 | */
70 | public function img(string $value, int $x = 0, int $y = 0, int $new_width = 0, int $new_height = 0): ImageMake
71 | {
72 | if(is_file($value))
73 | $value=file_get_contents($value);
74 | // 处理底图
75 | $result = $this->makeBGImg($value);
76 | if (!$result)
77 | return $this;
78 |
79 | list($width, $height) = getimagesizefromstring($value);
80 | $img = imagecreatefromstring($value);
81 | imagesavealpha($img,$this->config['alpha']);
82 |
83 | $new_height != 0 ? : $new_height = $height;
84 | $new_width != 0 ? : $new_width = $width;
85 |
86 | imagecopyresampled($this->bgImg, $img, $x, $y, 0, 0, $new_width, $new_height,$width,$height);
87 | imagedestroy($img);
88 | return $this;
89 | }
90 |
91 | /**
92 | * 叠加文字
93 | * @param string $value 要叠加的文字
94 | * @param int $x 相对于底图的 X 坐标
95 | * @param int $y 相对于底图的 Y 坐标 注意:基点在字体左下角,非左上角
96 | * @param array $config 配置数组:
97 | * [
98 | * 'color' => string 字体颜色,
99 | * 'size' => int 字体大小,
100 | * 'wrap' => false | array [
101 | * 20, // int 多少字换行
102 | * 10 // int 行高
103 | * ],
104 | * 'font' => string 字体,
105 | * 'deg' => int 旋转角度,设置排列方向,效果:左到右、上到下
106 | * ]
107 | * @return $this
108 | * @throws \Exception
109 | */
110 | public function str(string $value, int $x = 0, int $y = 10, array $config = []): ImageMake
111 | {
112 | $config = array_merge([
113 | 'color' => '#000',
114 | 'size' => $this->config['font_size'],
115 | 'wrap' => false,
116 | 'font' => $this->config['font'],
117 | 'deg' => 0,
118 | ],$config);
119 |
120 | if (!is_file($config['font']))
121 | throw new \Exception('错误的字体路径');
122 |
123 | $color_config = $this->toRgb($config['color']);
124 | $color = imagecolorallocatealpha($this->bgImg, $color_config['r'], $color_config['g'], $color_config['b'], $color_config['a']);
125 |
126 | if ($color === false)
127 | throw new \Exception('颜色添加失败,检查底图是否过大。'.json_encode($color_config));
128 |
129 | if ($config['wrap']){
130 | $new_value = $this->mb_str_split($value,$config['wrap'][0]);
131 | foreach ($new_value as $v) {
132 | imagefttext($this->bgImg, $config['size'], $config['deg'], $x, $y, $color, $config['font'], $v);
133 | $y += $config['wrap'][1];
134 | }
135 | }else{
136 | imagefttext($this->bgImg, $config['size'], $config['deg'], $x, $y, $color, $config['font'], $value);
137 | }
138 | return $this;
139 | }
140 |
141 | /**
142 | * 获取图片文件或直接输出
143 | * @param string|null $filepath 指定输出的相对路径 + 文件名,否则直接输出图像
144 | * @return string|null
145 | */
146 | public function get(string $filepath = null)
147 | {
148 | $type = $this->config['img_type'];
149 | switch ($type) {
150 | case 1:
151 | $filepath ? $filepath .= '.gif' : header('Content-Type:image/gif');
152 | imagegif($this->bgImg, $filepath);
153 | break;
154 | case 2:
155 | $filepath ? $filepath .= '.jpg' : header('Content-Type:image/jpg');
156 | imagejpeg($this->bgImg, $filepath);
157 | break;
158 | case 3:
159 | $filepath ? $filepath .= '.png' : header('Content-Type:image/png');
160 | imagepng($this->bgImg, $filepath);
161 | break;
162 | }
163 | imagedestroy($this->bgImg);
164 | $this->bgImg = null;
165 | return $filepath;
166 | }
167 |
168 | /**
169 | * 支持带透明度的十六进制
170 | * @throws \Exception
171 | */
172 | private function toRgb($hexColor) {
173 | $color = str_replace('#', '', $hexColor);
174 | $length = strlen($color);
175 | $a = 0;
176 | if ( $length == 3) {
177 | $r = substr($color, 0, 1) . substr($color, 0, 1);
178 | $g = substr($color, 1, 1) . substr($color, 1, 1);
179 | $b = substr($color, 2, 1) . substr($color, 2, 1);
180 | } elseif( $length == 6 || $length == 8) {
181 | $r = substr($color, 0, 2);
182 | $g = substr($color, 2, 2);
183 | $b = substr($color, 4, 2);
184 | if ($length == 8){
185 | $a = (int)(hexdec(substr($color, 6, 2) )/2);
186 | }
187 | }else{
188 | throw new \Exception('错误的颜色值');
189 | }
190 | return array(
191 | 'r' => hexdec($r),
192 | 'g' => hexdec($g),
193 | 'b' => hexdec($b),
194 | 'a' => $a
195 | );
196 | }
197 | // 中文字符串进行 str_split 切割成数组
198 | private function mb_str_split($str,$split_length=1){
199 | if(func_num_args()==1){
200 | return preg_split('/(? 0,
14 | 'height' => 0,
15 | 'alpha' => true,
16 | 'font' => null,
17 | 'font_size' => 16,
18 | 'img_type' => 3,
19 | ];
20 |
21 | /**
22 | * 输出图片大小,默认为底图宽高
23 | * @param int $width
24 | * @param int $height
25 | * @return ImageMakeConfig
26 | */
27 | public function exportSize(int $width, int $height): ImageMakeConfig
28 | {
29 | $this->config['width'] = $width;
30 | $this->config['height'] = $height;
31 | return $this;
32 | }
33 |
34 | /**
35 | * 设置输出图片格式
36 | * @param int $type 1 = GIF,2 = JPG,3 = PNG
37 | * @return ImageMakeConfig
38 | * @throws \Exception
39 | */
40 | public function exportType(int $type): ImageMakeConfig
41 | {
42 | if (preg_match('/[1-3]/',$type) == 0)
43 | throw new \Exception('错误的图片格式');
44 |
45 | $this->config['img_type'] = $type;
46 | return $this;
47 | }
48 |
49 | /**
50 | * 是否启用透明度
51 | * @param bool $boolean
52 | * @return ImageMakeConfig
53 | */
54 | public function alpha(bool $boolean ): ImageMakeConfig
55 | {
56 | $this->config['alpha'] = $boolean;
57 | return $this;
58 | }
59 |
60 | /**
61 | * 设置默认字体
62 | * @param string $font
63 | * @return ImageMakeConfig
64 | * @throws \Exception
65 | */
66 | public function font(string $font ): ImageMakeConfig
67 | {
68 | if (!is_file($font))
69 | throw new \Exception('错误的字体路径');
70 |
71 | $this->config['font'] = $font;
72 | return $this;
73 | }
74 |
75 | /**
76 | * 设置默认字体大小
77 | * @param int $font_size
78 | * @return $this
79 | */
80 | public function fontSize(int $font_size): ImageMakeConfig
81 | {
82 | $this->config['font_size'] = $font_size;
83 | return $this;
84 | }
85 |
86 | function __construct(){
87 | $this->config['font'] = __DIR__.'/SourceHanSansSC-Medium.ttf';
88 | }
89 | }
--------------------------------------------------------------------------------
/src/SourceHanSansSC-Medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Saopanda/ImageMake/c27beb6352909dc69153677a3010d88f11f881f9/src/SourceHanSansSC-Medium.ttf
--------------------------------------------------------------------------------
/test/make.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Saopanda/ImageMake/c27beb6352909dc69153677a3010d88f11f881f9/test/make.jpeg
--------------------------------------------------------------------------------
/test/make2.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Saopanda/ImageMake/c27beb6352909dc69153677a3010d88f11f881f9/test/make2.jpeg
--------------------------------------------------------------------------------
/test/test.php:
--------------------------------------------------------------------------------
1 | exportType(2);
9 |
10 | ImageMake::new($config)->img('./make.jpeg')
11 | ->img('./make2.jpeg',100,100)
12 | ->str('测试测试',200,120,['color'=>"#ff0066"])
13 | ->str('测试1测试',200,220,['size'=>40])
14 | ->str('测试2测试',400,420)
15 | ->str('测试3测试',440,620)
16 | ->str('欢迎使用 ImageMake',780,420,['size'=>60])
17 | ->get();
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------