NextJS 中的 Satori - 在 NodeJS 运行时将 SVG 转换为 PNG

问题描述 投票:0回答:1

我正在尝试理解 satori 并在我的 next.js api 路由中使用它。 (我无法使用

vercel/og
套件)。

我一切正常,但我不明白的一件事是如何将 satori 生成的

svg
图像变成
png
。在文档中它说:

If you want to render the generated SVG to another image format such as PNG, it would be better to use base64 encoded image data (or buffer) directly as props.src so no extra I/O is needed in Satori:

await satori(
  <img src="data:image/png;base64,..." width={200} height={300} />,
  // Or src={arrayBuffer}, src={buffer}
  options
)

链接:https://github.com/vercel/satori#images

我不太明白这是什么意思?

到目前为止,我的 nextjs api 路线(下一个 13)看起来像这样:

export async function GET(req, res) {
  let fontUrl = "/Users/anton/projects/new_test/src/app/assets/fonts/NotoSans/NotoSans-Bold.ttf"
  const fontArrayBuf = await fs.readFile(fontUrl)
 
  
  const svg = await satori(
    "<div style={{ color: red }}>hello, world</div>",
    {
      width: 600,
      height: 400,
      fonts: [
        {
          name: 'Noto Sans',
          data: fontArrayBuf,
          weight: 400,
          style: 'normal',
        },
      ],
    }
  );


  // this works, but here i struggle
  // i would like to:
  // 1. turn the svg above into a png
  // 2. return the png from my next api route

  return NextResponse.json({ data: "some response" })
}

我尝试过使用

resvg
,但收到错误消息,提示我没有配置正确的加载程序。而且,似乎 png 可以用 satori 实现(正如我在上面复制粘贴的文档中所暗示的那样),但我就是无法让它工作。

javascript node.js svg next.js buffer
1个回答
0
投票

你可以使用

@napi-rs/image
,具体来说,你在:

const transformer = Transformer.fromSvg(svg);

return await transformer.png();

这是一个完整的示例,取自https://ray.run

import { Transformer } from '@napi-rs/image';
import { readFile } from 'node:fs/promises';
import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
import satori from 'satori';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

export const generateOpenGraphImage = async (contents: { title: string }) => {
  const svg = await satori(
    <div
      style={{
        alignItems: 'flex-start',
        background: '#0E0E11',
        display: 'flex',
        flexDirection: 'column',
        fontFamily: 'Outfit',
        height: '100%',
        justifyContent: 'center',
        padding: '0 180px',
        width: '100%',
      }}
    >
      <div
        style={{
          color: '#fff',
          fontSize: 40,
          fontWeight: 400,
          letterSpacing: -2,
          padding: '20px',
        }}
      >
        Rayrun
      </div>
      <div
        style={{
          color: '#fff',
          fontSize: 80,
          fontWeight: 700,
          letterSpacing: -2,
          padding: '20px',
        }}
      >
        {contents.title}
      </div>
    </div>,
    {
      fonts: [
        {
          data: await readFile(join(__dirname, '../fonts/Outfit-Regular.ttf')),
          name: 'Outfit',
          style: 'normal',
          weight: 400,
        },
        {
          data: await readFile(join(__dirname, '../fonts/Outfit-Bold.ttf')),
          name: 'Outfit',
          style: 'normal',
          weight: 700,
        },
      ],
      height: 600,
      width: 1_200,
    },
  );

  const transformer = Transformer.fromSvg(svg);

  return await transformer.png();
};
© www.soinside.com 2019 - 2024. All rights reserved.