Node.js终极文本转图指南

引言

简要介绍文字转图片的应用场景(如社交媒体分享、水印生成、动态海报等),以及Node.js在图像处理中的优势。提及ultimate-text-to-image库的核心功能和特点。

环境准备

所需工具和库的版本要求:

  • Node.js

  • npm或yarn包管理器

  • ultimate-text-to-image库的安装命令:

    bash 复制代码
    npm install ultimate-text-to-image

UltimateTextToImage 基本用法

UltimateTextToImage 是一个用于将文本转换为图像的 Node.js 库,支持多种自定义选项如字体、颜色、对齐方式等。通过简单的配置,可以生成不同风格的文本图像。

将文本`abc xyz 0123456789 零一二三四五六七八九`转化为图片,图片宽度为200像素,字体为'Sans,Arial',首选'Sans',次选'Arial'。将图片保存到项目的根目录下,图片名称为'image1.png'

javascript 复制代码
const { UltimateTextToImage } = require("ultimate-text-to-image");
const path = require("path");

new UltimateTextToImage(`abc xyz 0123456789 零一二三四五六七八九`, {
  width: 200,
  fontFamily: "Sans,Arial", //有些字体可能不支持中文
})
  .render()
  .toFile(path.join(__dirname, "image1.png"));

执行后的效果图:

高级配置选项

该库提供了丰富的配置参数,允许用户精细控制文本的显示效果。包括字体大小、颜色、背景、边框等属性,满足不同场景需求。

javascript 复制代码
let textToImage = new UltimateTextToImage(
  "abc xyz 0123456789 零一二三四五六七八九",
  {
    width: 400,          // 初始画布宽度(px),若文本超出会自动调整
    maxWidth: 1000,      // 画布最大宽度(px),防止无限扩展
    maxHeight: 1000,     // 画布最大高度(px),超出可能截断
    fontFamily: "Sans",  // 字体(系统支持的字体,如 "Arial"、"SimSun")
    fontColor: "#00FF00", // 文字颜色(十六进制或RGB,支持透明度如 `#00FF0080`)
    fontSize: 72,        // 初始字体大小(px)
    minFontSize: 10,     // 最小字体大小
    lineHeight: 50,      // 基础行高(px)
    autoWrapLineHeightMultiplier: 1.2, //换行时的行高倍数
    margin: 20,        // 四周边距(px),会被 `marginBottom` 覆盖
    marginBottom: 40,  // 底部边距(优先级高于 `margin`)
    align: "center",   // 水平对齐:"left" | "center" | "right"
    valign: "middle",  // 垂直对齐:"top" | "middle" | "bottom"
    borderColor: 0xff000099, // 边框颜色(十六进制或十进制,支持透明度)
    borderSize: 2,           // 边框宽度(px)
    backgroundColor: "0080FF33", // 背景色(支持透明度,如 `"rgba(0,128,255,0.2)"`)
    underlineColor: "#00FFFF33", // 下划线颜色(支持透明度)
    underlineSize: 2,            // 下划线粗细(px)
  }
);

textToImage.render().toFile(path.join(__dirname, "image2.png"));

运行后的效果图:

图像属性获取

生成图像后,可以获取各种属性信息,如画布尺寸、渲染时间等。这些属性对于调试和优化图像生成过程非常有用。

javascript 复制代码
let textToImage = new UltimateTextToImage(
  "文本内容",
  {
    width: 400,
  }
);

//等待渲染
await textToImage.render();

// 画布的最终宽度
const width = textToImage.width; 

// 画布的最终高度
const height = textToImage.height;

// 画布的渲染时间
const renderedTime = textToImage.renderedTime;

//包含文本在渲染前的详细测量信息,例如每行文本的尺寸、位置等
const measuredParagraph = textToImage.measuredParagraph; 

获取画布对象
const canvas = textToImage.canvas; 

//是否已执行过渲染操作(render() 方法是否被调用过)。
const hasRendered = textToImage.hasRendered;

运行后的结果:

javascript 复制代码
画布宽度: 929
画布高度: 210
画布渲染时间(ms): 673.5504
文字信息: {
  text: 'abc xyz 0123456789 零一二三四五六七八九',
  width: 890.859375,
  height: 158,
  fontSize: 72,
  fontFamily: 'Sans',
  fontStyle: false,
  fontWeight: false,
  spaceWidth: 22.5,
  boundingHeight: 150,
  boundingWidth: 889.859375,
  paddingTop: -15,
  paddingBottom: 7,
  paddingLeft: 3,
  paddingRight: -1,
  measuredLines: [
    {
      text: 'abc xyz 0123456789 零一二',
      width: 890.859375,
      paddingTop: -15,
      paddingBottom: 14,
      paddingLeft: 1,
      paddingRight: -2,
      nextLineHeight: 86,
      measuredWords: [Array]
    },
    {
      text: '三四五六七八九',
      width: 504,
      paddingTop: -13,
      paddingBottom: 7,
      paddingLeft: 3,
      paddingRight: -1,
      nextLineHeight: 0,
      measuredWords: [Array]
    }
  ]
}
画布对象: [Canvas 929x210]
画布是否渲染 true

动态修改与重新渲染

支持动态修改配置选项并重新渲染图像。这种灵活性使得可以在不创建新实例的情况下调整图像样式。

javascript 复制代码
let textToImage = new UltimateTextToImage(`abc xyz 0123456789 零一二三四五六七八九`, {
  width: 200,
  fontFamily: "Sans", 
})
  .render()
  .toFile(path.join(__dirname, "image1.png"));

textToImage.options.fontFamily = "Comic Sans MS";
textToImage.render().toFile("updated.png");

运行后的结果(Comic Sans MS字体不支持中文):

数据URL输出

除了保存为文件,还可以将图像转换为数据URL格式,便于网页直接使用或嵌入其他应用。

javascript 复制代码
//默认png
let textToImage = new UltimateTextToImage("Hello World").render();
const dataUrlPng = textToImage.toDataUrl(); // image/png by default
console.log(dataUrlPng);


// 0 到 100,其中 100 表示最高质量(无损但文件最大),
//80 表示一个较高的质量但文件大小相对较小。
const dataUrlJpeg = textToImage.toDataUrl("image/jpeg", { quality: 80 });
console.log(dataUrlJpeg);

运行后的效果:

javascript 复制代码
data:image/png;base64,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

缓冲流输出

支持将图像转换为缓冲流,便于进一步处理或传输。提供多种格式选项和压缩参数,平衡质量与大小。

javascript 复制代码
// 图片转buffer
const buffer = textToImage.toBuffer(); // 默认png
//0 表示无压缩(文件最大但最快),9 表示最大压缩
const bufferPng = textToImage.toBuffer("image/png", { compressionLevel: 6 });
// progressive设置渐进式 JPEG 图像,在加载时会逐渐从低分辨率到高分辨率显示
const bufferJpeg = textToImage.toBuffer("image/jpeg", {
   //100:最高质量(几乎无损,文件最大)。0:最低质量(严重失真,文件最小)。
   quality: 80,  
   progressive: true,
 });

画布转换为流并保存为图片

将文本生成的图片转换为可读流,然后通过管道传输到可写流中完成文件保存。

javascript 复制代码
let textToImage = new UltimateTextToImage("Hello World").render();

// 图片转stream
const streamPng = textToImage.toStream(); // 默认生成png格式
const streamJpeg = textToImage.toStream("image/jpeg"); // 指定生成jpeg格式
const out = fs.createWriteStream(path.join(__dirname, "imageE4.png"));
streamPng.pipe(out);

运行后的效果:

多种格式的图像拼接

以下代码展示了如何使用 UltimateTextToImage 库加载多种格式的图像数据(URL、Base64、Buffer、ArrayBuffer),并通过不同方式将这些图像绘制到画布上:

javascript 复制代码
const {
  UltimateTextToImage,
  getCanvasImage
} = require("ultimate-text-to-image");

(async () => {
  const url =
    "https://www.npmjs.com/npm-avatar/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdmF0YXJVUkwiOiJodHRwczovL3MuZ3JhdmF0YXIuY29tL2F2YXRhci8yNjljMGE1MzNiNTQ1MDNkMDg2Y2EwYWJlMzBkODkwNT9zaXplPTEwMCZkZWZhdWx0PXJldHJvIn0.W4Iy2ZRyJ3XX_ju-P_zdYhVlRrONO0ZYJn4iRQw5eFM";
  const buffer = new UltimateTextToImage("repeatX").render().toBuffer();
  const base64 = new UltimateTextToImage("fitY")
    .render()
    .toBuffer()
    .toString("base64");
  const arrayBuffer = new Uint8Array(
    new UltimateTextToImage("repeat").render().toBuffer()
  );

  const canvasImage1 = await getCanvasImage({ url });
  const canvasImage2 = await getCanvasImage({ base64 });
  const canvasImage3 = await getCanvasImage({ buffer });
  const canvasImage4 = await getCanvasImage({ arrayBuffer });

  const textToImage = new UltimateTextToImage("Image Example", {
    width: 600,
    height: 600,
    alignToCenterIfLinesLE: 1,
    fontSize: 72,
    backgroundColor: "#FFFFFF99",
    images: [
      { canvasImage: canvasImage1, layer: -1, repeat: "fit" },
      {
        canvasImage: canvasImage2,
        layer: 0,
        repeat: "fitY",
        x: 10,
        y: 10,
        width: 100,
        height: 100,
      },
      {
        canvasImage: canvasImage3,
        layer: 1,
        repeat: "repeatX",
        sx: -400,
        sy: 100,
        width: 300,
        height: 300,
      },
      {
        canvasImage: canvasImage4,
        layer: 1,
        repeat: "repeat",
        sx: -200,
        sy: -300,
        tx: -50,
        ty: -50,
      },
    ],
  })
    .render()
    .toFile(path.join(__dirname, "image4.png"));
})();

核心功能说明

  1. 图像加载

    代码中使用四种不同来源加载图像:URL、Base64字符串、Buffer对象和ArrayBuffer对象。getCanvasImage函数处理这些不同格式的输入并返回可绘制的图像对象。

  2. 图像绘制参数

    • layer: 控制图像的绘制层级,数值越小越先绘制
    • repeat: 指定图像的重复模式(fit/fitY/repeatX/repeat)
    • x/y: 图像绘制的位置坐标
    • width/height: 控制绘制尺寸
    • sx/sy: 源图像裁剪起始点
    • tx/ty: 目标画布绘制起始点
  3. 输出处理

    最终通过toFile()方法将合成结果保存为PNG文件,也可以使用toBuffer()获取二进制数据用于进一步处理。

运行后的效果图:

文本到图像的渲染控制

动态生成图像时,同时利用 preRenderposRender 回调函数在渲染前后执行自定义逻辑。例如:

javascript 复制代码
let textToImage = new UltimateTextToImage(
  "Rendering",
  {},
  {
    preRender: (canvas) => {
      // 在绘制任何内容前触发(调用 render() 时)
      console.log("before");
      console.log(canvas);
    },
    posRender: (canvas) => {
      // 在绘制完所有文本和图像后触发
      console.log("after");
      console.log(canvas);
    },
  }
).render();

关键点说明

  • preRender:在渲染开始前调用,可用于初始化画布状态或记录调试信息。
  • posRender:在渲染完成后调用,适合对生成的图像进行后处理或保存操作。

混合布局图像

javascript 复制代码
const {
  UltimateTextToImage,
  HorizontalImage,
  VerticalImage,
} = require("ultimate-text-to-image");
const path = require("path");

const textToImage1 = new UltimateTextToImage("Image1", {
  backgroundColor: "#0080FF33",
  fontSize: 60,
});
const textToImage2 = new UltimateTextToImage("Image2 ".repeat(10).trim(), {
  maxWidth: 200,
  backgroundColor: "#00FF0033",
  fontSize: 40,
});

const horizontalImage = new HorizontalImage(
  [
    textToImage1,
    textToImage2,
    new HorizontalImage([
      new UltimateTextToImage("Horizontal 1"),
      new UltimateTextToImage("Horizontal 2", { fontSize: 50 }),
    ]),
    new VerticalImage([
      new UltimateTextToImage("Vertical 1"),
      new UltimateTextToImage("Vertical 2", { fontColor: "#FF0000" }),
    ]),
  ],
  { valign: "bottom", backgroundColor: "#AAAAAA", margin: 100 }
);

horizontalImage.render().toFile(path.join(__dirname, "imageMixed1.jpg"));

功能说明

  • 基础文本图像textToImage1textToImage2 分别生成带有不同背景色和字体大小的文本图像。
  • 嵌套布局HorizontalImageVerticalImage 实现水平和垂直方向的混合布局。
  • 样式配置 :通过 valignbackgroundColormargin 参数控制整体对齐、背景色和边距。
  • 输出文件 :最终图像通过 render().toFile() 保存为本地文件。

运行后的效果图:

相关推荐
GIS之路7 分钟前
GDAL 实现矢量裁剪
前端·python·信息可视化
是一个Bug10 分钟前
后端开发者视角的前端开发面试题清单(50道)
前端
Amumu1213812 分钟前
React面向组件编程
开发语言·前端·javascript
持续升级打怪中34 分钟前
Vue3 中虚拟滚动与分页加载的实现原理与实践
前端·性能优化
GIS之路38 分钟前
GDAL 实现矢量合并
前端
hxjhnct40 分钟前
React useContext的缺陷
前端·react.js·前端框架
冰暮流星1 小时前
javascript逻辑运算符
开发语言·javascript·ecmascript
前端 贾公子1 小时前
从入门到实践:前端 Monorepo 工程化实战(4)
前端
菩提小狗1 小时前
Sqlmap双击运行脚本,双击直接打开。
前端·笔记·安全·web安全
前端工作日常1 小时前
我学习到的AG-UI的概念
前端