JavaScript 动态生成海报

三种在浏览器和 Node.js 中动态生成海报图片的实现方案

问题

如何使用 JavaScript 动态生成海报图片?

解答

方案一:DOM → Canvas → Image

将 DOM 节点绘制到 canvas 画布,再导出为图片。

绘制阶段

选择目标 DOM 节点,根据 nodeType 属性调用 canvas 对应的 API 进行绘制。

const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');

// 对于图片元素使用 drawImage
const img = document.querySelector('img');
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);

// 对于文本使用 fillText
ctx.font = '16px Arial';
ctx.fillText('Hello World', 10, 50);

导出阶段

使用 canvas 的导出接口生成图片。

// 导出为 base64
const dataURL = canvas.toDataURL('image/png');

// 或获取图片数据
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);

方案二:DOM → SVG → Canvas → Image

将 HTML 作为 SVG 的外联元素,利用 SVG 导出为图片。

const svg = `
  <svg xmlns="http://www.w3.org/2000/svg" width="800" height="600">
    <foreignObject width="100%" height="100%">
      <div xmlns="http://www.w3.org/1999/xhtml">
        ${htmlContent}
      </div>
    </foreignObject>
  </svg>
`;

const blob = new Blob([svg], { type: 'image/svg+xml' });
const url = URL.createObjectURL(blob);

const img = new Image();
img.onload = () => {
  ctx.drawImage(img, 0, 0);
  const dataURL = canvas.toDataURL('image/png');
};
img.src = url;

方案三:Node.js 调用浏览器

在后端使用 Puppeteer 等库调用浏览器截图。

const puppeteer = require('puppeteer');

async function generatePoster() {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  
  await page.setContent('<div>海报内容</div>');
  await page.screenshot({ 
    path: 'poster.png',
    fullPage: true 
  });
  
  await browser.close();
}

关键点

  • 方案一适合简单场景,需手动处理各类 DOM 节点的绘制逻辑
  • 方案二通过 SVG 的 foreignObject 可以保留 HTML 样式,但存在浏览器兼容性问题
  • 方案三在服务端生成,性能稳定,适合批量生成海报的场景
  • Canvas 导出时注意跨域图片需设置 crossOrigin 属性