You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Node canvas中实现文本自动换行?

解决方案

Node Canvas 没有内置文本自动换行API,你可以通过measureText()方法手动计算文本宽度实现换行,具体实现如下:


核心逻辑

  1. 预设文本区域的最大宽度,你当前文本从x=500的位置开始绘制,画布总宽1920,建议最大宽度设为1300,预留右侧边距
  2. 把待绘制的文本按空格拆分为单词,逐个拼接计算宽度,超过最大宽度就拆为新行
  3. 按行逐行绘制文本,每行的y坐标按行高递增即可

修改后完整代码

// 字体注册放到事件外,避免重复注册
const { registerFont, createCanvas, loadImage } = require('canvas')
registerFont('./disc2.otf', { family: 'Comic Sans' })
const Discord = require('discord.js')

// 自动换行工具函数:传入画布上下文、待绘制文本、最大宽度,返回拆分好的行数组
function wrapText(ctx, text, maxWidth) {
  let words = text.split(' ')
  let lines = []
  let currentLine = words[0]

  for (let i = 1; i < words.length; i++) {
    let word = words[i]
    let width = ctx.measureText(currentLine + ' ' + word).width
    if (width < maxWidth) {
      currentLine += ' ' + word
    } else {
      lines.push(currentLine)
      currentLine = word
    }
  }
  lines.push(currentLine)
  return lines
}

client.on("message", async (message) => {
  if (message.author.bot) return;
  if (message.content.startsWith("R!write")) {
    let sliced = message.content.slice(31)
    let msg = `"${sliced}" - 2021`
    const canvas = createCanvas(1920, 900);
    let background = await loadImage('./lmao.jpg');
    const ctx = canvas.getContext('2d')
    ctx.drawImage(background, 0, 0, canvas.width, canvas.height);

    const taggeduser = message.mentions.users.first();
    if (!taggeduser) return message.channel.send('mention someone pleb')

    let avatar = await loadImage(taggeduser.displayAvatarURL({ dynamic: false, format: 'jpg', size: 256 }));
    ctx.drawImage(avatar, 160, 340);

    ctx.font = '100px "Comic Sans"'
    ctx.fillStyle = '#000' // 可自行调整文本颜色
    // 拆分多行
    const lines = wrapText(ctx, msg, 1300)
    // 逐行绘制,行高设为120px,起始y坐标为500
    lines.forEach((line, index) => {
      ctx.fillText(line, 500, 500 + index * 120)
    })

    let attachment = new Discord.MessageAttachment(canvas.toBuffer(), 'example.png')
    return message.channel.send(attachment);
  }
});

可选优化

如果需要支持中文、emoji 等无空格分隔的字符,可以把拆分逻辑改成按单个字符拆分,逐个计算宽度即可,修改wrapText函数的拆分规则就行:

// 支持中文的换行版本
function wrapText(ctx, text, maxWidth) {
  let chars = text.split('')
  let lines = []
  let currentLine = chars[0]

  for (let i = 1; i < chars.length; i++) {
    let char = chars[i]
    let width = ctx.measureText(currentLine + char).width
    if (width < maxWidth) {
      currentLine += char
    } else {
      lines.push(currentLine)
      currentLine = char
    }
  }
  lines.push(currentLine)
  return lines
}

内容的提问来源于stack exchange,提问作者lelbro420

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 19:27:03