├── .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 | ![img_2.png](img_2.png) 3 | 4 | 使用GD库实现多图片与文字的合成处理 5 | * 项目重写,发布为 composer 包方便使用 6 | * 大幅删减和优化,完善的注释上手使用更简单 7 | * 自带思源黑体,可免费商用无需担心版权 8 | 9 | ### 安装 10 | composer require saopanda/image-make 11 | 12 | ### 使用 13 | 仅三个方法!支持链式调用,后面调用的会覆盖在前面之上 14 | ![img.png](img.png) 15 | ![img_1.png](img_1.png) 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 | --------------------------------------------------------------------------------