PHP实现文本转图片:按双空行分割文本并适配500×500区块
Hey,我来帮你搞定这两个问题,刚好之前处理过类似的场景,给你一步步拆解解决方案:
解决文本分割与转图片的两个核心需求
一、正确按双空行分割文本
你当前用#\n\n#无法匹配双空行,主要是没考虑不同系统的换行符差异(Windows是\r\n,Linux/macOS是\n),而且直接硬写换行符不够鲁棒。推荐用PHP正则里的\R来匹配任意换行序列,再配合数量限定符,就能完美解决:
// 匹配任意类型的双换行(包括\r\n\r\n、\n\n、\r\r),同时过滤空元素 $textBlocks = preg_split('/\R{2,}/', file_get_contents($file['tmp_name']), -1, PREG_SPLIT_NO_EMPTY);
解释下关键参数:
\R:自动匹配所有换行格式(\n、\r\n、\r),不用自己写一堆分支{2,}:匹配至少2个连续换行,能处理不小心多敲的空行PREG_SPLIT_NO_EMPTY:自动过滤分割后为空的块,避免后续处理无效内容
如果你的场景是严格的双空行(中间没有空格),也可以用'/(\r\n){2,}|\n{2,}|\r{2,}/',但\R{2,}更简洁通用。
二、将文本块转为500×500图片(自动换行不溢出)
这里用PHP自带的GD库就能实现,不用额外装扩展,下面是完整的可复用代码:
1. 先写个自动换行的辅助函数
这个函数会根据画布宽度和字体大小,把长文本拆成多行,避免溢出:
function wrapText($fontPath, $text, $maxWidth, $fontSize) { $words = preg_split('/\s+/', $text); $lines = []; $currentLine = ''; foreach ($words as $word) { $testLine = $currentLine . ($currentLine ? ' ' : '') . $word; // 计算当前测试行的宽度 $bbox = imagettfbbox($fontSize, 0, $fontPath, $testLine); $lineWidth = $bbox[2] - $bbox[0]; if ($lineWidth > $maxWidth && $currentLine !== '') { $lines[] = $currentLine; $currentLine = $word; } else { $currentLine = $testLine; } } if ($currentLine !== '') { $lines[] = $currentLine; } return $lines; }
2. 核心的图片生成函数
把文本块渲染成500×500的图片,还做了垂直居中,看起来更美观:
function textToImage($text, $savePath, $fontPath, $imageSize = 500) { // 创建500×500的画布 $image = imagecreatetruecolor($imageSize, $imageSize); // 设置背景色(白色) $bgColor = imagecolorallocate($image, 255, 255, 255); imagefill($image, 0, 0, $bgColor); // 设置文本颜色(黑色) $textColor = imagecolorallocate($image, 0, 0, 0); $fontSize = 16; // 字体大小,可根据需求调整 $padding = 20; // 左右内边距,避免文本贴边 $maxTextWidth = $imageSize - $padding * 2; // 调用自动换行函数拆分文本 $lines = wrapText($fontPath, trim($text), $maxTextWidth, $fontSize); // 计算文本总高度,实现垂直居中 $lineHeight = $fontSize * 1.5; // 行间距设为字体的1.5倍,更易读 $totalTextHeight = count($lines) * $lineHeight; $startY = ($imageSize - $totalTextHeight) / 2; // 逐行绘制文本 foreach ($lines as $index => $line) { $y = $startY + $index * $lineHeight; // 水平居中计算X坐标 $bbox = imagettfbbox($fontSize, 0, $fontPath, $line); $lineWidth = $bbox[2] - $bbox[0]; $x = ($imageSize - $lineWidth) / 2; imagettftext($image, $fontSize, 0, $x, $y, $textColor, $fontPath, $line); } // 保存为PNG图片(也可以用imagejpeg生成JPG) $success = imagepng($image, $savePath); // 释放内存资源 imagedestroy($image); return $success; }
3. 结合你的文件上传代码整合使用
把上面的函数和你现有的文件处理逻辑结合起来,完整流程如下:
$img = $_FILES['img']; function reArrayFiles($file) { $file_ary = array(); $file_count = count($file['name']); $file_key = array_keys($file); for($i=0;$i<$file_count;$i++) { foreach($file_key as $val) { $file_ary[$i][$val] = $file[$val][$i]; } } return $file_ary; } $img_desc = reArrayFiles($img); // 配置项,根据你的服务器路径调整 $fontPath = './fonts/msyh.ttf'; // 替换为你的字体文件路径(处理中文必须用中文字体) $saveDir = './generated_text_images/'; // 图片保存目录,确保有写入权限 // 创建保存目录(如果不存在) if (!is_dir($saveDir)) { mkdir($saveDir, 0755, true); } // 遍历处理每个上传的文件 foreach ($img_desc as $file) { // 只处理text/plain类型且上传成功的文件 if ($file['type'] === 'text/plain' && $file['error'] === UPLOAD_ERR_OK) { $originalText = file_get_contents($file['tmp_name']); // 1. 按双空行分割文本 $textBlocks = preg_split('/\R{2,}/', $originalText, -1, PREG_SPLIT_NO_EMPTY); // 2. 每个文本块生成一张图片 foreach ($textBlocks as $blockIndex => $block) { $cleanBlock = trim($block); if (empty($cleanBlock)) continue; // 跳过空内容 // 生成唯一文件名,避免重复 $fileName = uniqid('text_block_') . "_" . ($blockIndex + 1) . ".png"; $savePath = $saveDir . $fileName; // 生成图片 if (textToImage($cleanBlock, $savePath, $fontPath)) { echo "图片生成成功:{$savePath}<br>"; } else { echo "图片生成失败,请检查权限和字体路径<br>"; } } } }
几个重要的注意事项
- GD库启用:确保你的PHP环境已经启用GD库,可以通过
phpinfo()查看GD模块状态 - 字体文件:如果需要处理中文,必须使用支持中文的字体(比如微软雅黑、思源黑体),并确保字体路径正确
- 目录权限:
$saveDir所在的目录需要给PHP进程写入权限(通常设置为0755) - 超长文本处理:如果某个文本块内容太多,换行后总高度超过500,可以在
textToImage函数里添加逻辑,比如自动缩小字体大小,或者限制最大行数
内容的提问来源于stack exchange,提问作者Алексей Котов
相关产品推荐
相关产品推荐

