
使用 node-canvas 时,若文字出现在背景图片下方,根本原因是绘制顺序错误——必须先绘制背景(图片),再绘制文字;否则异步加载的图片会覆盖已绘制的文字。
使用 node-canvas 时,若文字出现在背景图片下方,根本原因是绘制顺序错误——必须先绘制背景(图片),再绘制文字;否则异步加载的图片会覆盖已绘制的文字。
在 node-canvas 中实现「图片为全尺寸背景 + 文字居中叠加」效果,关键在于严格控制绘制时序:背景图像必须在所有文字绘制之前完成渲染。原代码中 loadImage().then(...) 被放在最后执行,导致 fillText() 先被调用、文字绘制在空白画布上,随后加载的图片再通过 fillRect() 覆盖整个画布——自然遮住了文字。
✅ 正确做法是:将所有绘图逻辑(包括文字)放入 loadImage 的 then 回调中,确保图像资源加载完成后再执行后续绘制。
以下是优化后的完整示例(含健壮性增强):
const { createCanvas, loadImage } = require("canvas");
const fs = require("fs");
const width = 848;
const height = 600;
const canvas = createCanvas(width, height);
const ctx = canvas.getContext("2d");
// ✅ 关键:所有绘制操作必须在图片加载完成后进行
loadImage("./assets/jimp-cert-template.jpg")
.then((image) => {
// 1. 绘制全尺寸背景(拉伸填充,非平铺)
ctx.drawImage(image, 0, 0, width, height); // 推荐:比 createPattern + fillRect 更直观可靠
// 2. 设置文字样式
ctx.font = "bold 70pt 'PT Sans'";
ctx.textAlign = "center";
ctx.textBaseline = "middle"; // 避免 y 坐标定位偏差
ctx.fillStyle = "#764abc";
// 3. 绘制文字(坐标基于 canvas 中心或自定义布局)
ctx.fillText("TITLE 1", 600, 170);
ctx.font = "bold 100pt 'PT Sans'";
ctx.fillText("TITLE 2", 600, 270);
// 4. 输出图像
const buffer = canvas.toBuffer("image/jpeg", { quality: 0.95 });
fs.writeFileSync("./image.jpeg", buffer);
console.log("✅ Certificate generated successfully!");
})
.catch((err) => {
console.error("❌ Failed to load image or draw canvas:", err);
});⚠️ 注意事项:
-
避免
createPattern用于单张背景图:createPattern(image, 'no-repeat')默认不缩放,需额外设置pattern.setTransform(...)才能适配画布尺寸;直接使用ctx.drawImage(image, 0, 0, width, height)更简洁可控。 -
字体可靠性:确保
'PT Sans'已在系统中安装,或改用系统安全字体(如'sans-serif'),否则可能回退为默认字体导致排版异常。 -
异步安全:所有
ctx操作必须位于loadImage的then内部,不可跨异步边界调用。 -
坐标调试建议:启用
ctx.strokeStyle = 'red'; ctx.strokeRect(590, 160, 20, 20);辅助定位文字锚点。
总结:node-canvas 的绘制顺序即图层顺序——后绘制的内容位于上层。牢记「背景 → 前景」的渲染管线,并将全部绘图逻辑置于资源加载回调中,即可稳定实现图文叠加效果。

















