如何将Sharp合成图像存入Redis队列且不损坏文本
问题解决思路:Sharp生成SVG叠加图存Redis后文本变方块
核心问题分析
本地用sharp.toFile()生成的图片文本显示正常,但通过toBuffer()转JSON存入Redis后,消费得到的图片中文本变成方块,主要原因集中在字体渲染环境差异和Buffer序列化处理不当两点:
- 字体环境不一致:Sharp渲染SVG文本依赖系统字体,本地环境有默认字体(比如Arial),但生成图片的服务或消费服务的环境缺少对应字体,导致渲染时用方块替代缺失字符。
- Buffer序列化问题:直接将Buffer传入
JSON.stringify()会被转为{type: "Buffer", data: [...]}的嵌套结构,消费时若未正确还原为Buffer,可能导致图片数据异常。
解决方案
1. 强制SVG使用指定字体(推荐)
不要依赖系统默认字体,在SVG的<text>元素中明确指定字体文件路径,确保Sharp在任何环境下都能找到字体:
const label = Buffer.from( `<svg width="${1920}" height="${1080}"> <rect x="0" y="0" width="100%" height="100%" fill="#fff" /> <text x="10" y="20%" font-size="5em" text-anchor="top" dy="1.25em" font-family="/absolute/path/to/your/font.ttf">Sample Text</text> </svg>` );
也可以将字体嵌入SVG(通过<defs>和<font-face>),彻底避免依赖外部文件。
2. 统一所有环境的字体安装
在生成图片的服务、消费服务所在的服务器上,安装SVG默认使用的字体(比如常见的DejaVu Sans、Arial):
- Linux环境执行:
apt-get install fonts-dejavu-core(Debian/Ubuntu)或yum install dejavu-sans-fonts(CentOS) - 验证字体是否存在:执行
fc-list查看已安装字体列表
3. 正确处理Buffer的序列化与反序列化
将Buffer转为Base64字符串后再存入Redis,消费时再还原为Buffer,避免JSON序列化导致的数据异常:
// 生成图片Buffer并转Base64 const image = await sharp({ create: { width: 1920, height: 1080, channels: 4, background: { r: 255, g: 255, b: 255 } } }) .composite([{ input: label, gravity: 'north' }]) .jpeg() .toBuffer(); const imageBase64 = image.toString('base64'); // 发布到Redis await this.redisCon.publish( 'image', JSON.stringify({ id: request.id, data: imageBase64, // 存Base64字符串 hostname: 'engine-mock', errorCode: 0, errorMessage: 'noError' }) ); // 消费时还原Buffer const messageData = JSON.parse(receivedMessage); const imageBuffer = Buffer.from(messageData.data, 'base64');
4. 分步排查验证
- 先在生成服务中,将
toBuffer()得到的Buffer直接存文件,检查文本是否正常:如果不正常,说明是生成环境的字体问题;如果正常,再排查Redis序列化/消费环节的问题。 - 检查消费服务是否正确处理图片数据,确保还原后的Buffer能正常解码为图片。
内容的提问来源于stack exchange,提问作者Ole Maiwald
相关产品推荐
相关产品推荐

