我正在尝试理解 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 实现(正如我在上面复制粘贴的文档中所暗示的那样),但我就是无法让它工作。
@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();
};