satori

satori

HTML和CSS转SVG的轻量级开源解决方案

Satori是一个开源库,可将HTML和CSS转换为SVG。它采用JSX语法,简化了使用流程。该库能处理布局计算、字体和排版,生成的SVG与浏览器渲染效果一致。Satori支持多种HTML元素和CSS功能,包括Flexbox布局、文本样式和背景设置等。这个工具主要用于创建Open Graph图像和社交媒体卡片。

SatoriSVG生成HTMLCSSJSXGithub开源项目

Satori

Satori:将 HTML 和 CSS 转换为 SVG 的启发式库。

注意

要在你的项目中使用 Satori 生成 PNG 图像,如开放图谱图像和社交卡片,请查看我们的公告Vercel 的开放图谱图像生成 →

要在 Next.js 中使用它,请查看 Next.js 开放图谱图像生成模板 →

概述

Satori 支持 JSX 语法,这使得它非常易于使用。以下是基本用法概述:

// api.jsx import satori from 'satori' const svg = await satori( <div style={{ color: 'black' }}>你好,世界</div>, { width: 600, height: 400, fonts: [ { name: 'Roboto', // 使用 `fs`(仅限 Node.js)或 `fetch` 将字体读取为 Buffer/ArrayBuffer 并在此处提供 `data`。 data: robotoArrayBuffer, weight: 400, style: 'normal', }, ], }, )

Satori 将把元素渲染成一个 600×400 的 SVG,并返回 SVG 字符串:

'<svg ...><path d="..." fill="black"></path></svg>'

在底层,它处理布局计算、字体、排版等,生成与浏览器中完全相同的 HTML 和 CSS 的 SVG。

<br/>

文档

JSX

Satori 只接受纯粹且无状态的 JSX 元素。你可以使用 HTML 元素的子集(见下文),或自定义 React 组件,但不支持 React API,如 useStateuseEffectdangerouslySetInnerHTML

不使用 JSX

如果你没有启用 JSX 转译器,你可以直接传递具有 typeprops.childrenprops.style(以及其他属性)的类 React 元素对象:

await satori( { type: 'div', props: { children: '你好,世界', style: { color: 'black' }, }, }, options )

HTML 元素

由于其特殊用例,Satori 支持有限的 HTML 和 CSS 功能子集。通常,只实现了静态和可见的元素和属性。

例如,<input> HTML 元素、cursor CSS 属性不在考虑范围内。而且你不能使用 <style> 标签或通过 <link><script> 使用外部资源。

此外,Satori 不保证 SVG 会 100% 匹配浏览器渲染的 HTML 输出,因为 Satori 基于 SVG 1.1 规范实现了自己的布局引擎。

你可以在这里找到支持的 HTML 元素及其预设样式列表。

图像

你可以使用 <img> 嵌入图像。但建议设置 widthheight 属性:

await satori( <img src="https://picsum.photos/200/300" width={200} height={300} />, options )

使用 background-image 时,如果你没有指定尺寸,图像默认会被拉伸以适应元素。

如果你想将生成的 SVG 渲染为其他图像格式(如 PNG),最好直接使用 base64 编码的图像数据(或 buffer)作为 props.src,这样 Satori 就不需要额外的 I/O:

await satori( <img src="https://raw.githubusercontent.com/vercel/satori/main/data:image/png;base64,..." width={200} height={300} />, // 或 src={arrayBuffer}, src={buffer} options )

CSS

Satori 使用与 React Native 相同的 Flexbox 布局引擎,它不是一个完整的 CSS 实现。然而,它支持规范的一个子集,涵盖了大多数常用的 CSS 功能:

<table> <thead> <tr> <th>属性</th> <th>属性扩展</th> <th>支持的值</th> <th>示例</th> </tr> </thead> <tbody> <tr> <td colspan="2"><code>display</code></td> <td><code>none</code> 和 <code>flex</code>,默认为 <code>flex</code></td> <td></td> </tr> <tr> <td colspan="2"><code>position</code></td> <td><code>relative</code> 和 <code>absolute</code>,默认为 <code>relative</code></td> <td></td> </tr> <tr> <td colspan="2"><code>color</code></td> <td>支持</td> <td></td> </tr> <tr><td rowspan="5"><code>margin</code></td></tr> <tr><td><code>marginTop</code></td><td>支持</td><td></td></tr> <tr><td><code>marginRight</code></td><td>支持</td><td></td></tr> <tr><td><code>marginBottom</code></td><td>支持</td><td></td></tr> <tr><td><code>marginLeft</code></td><td>支持</td><td></td></tr> <tr><td rowspan="5">位置</td></tr> <tr><td><code>top</code></td><td>支持</td><td></td></tr> <tr><td><code>right</code></td><td>支持</td><td></td></tr> <tr><td><code>bottom</code></td><td>支持</td><td></td></tr> <tr><td><code>left</code></td><td>支持</td><td></td></tr> <tr><td rowspan="3">尺寸</td></tr> <tr><td><code>width</code></td><td>支持</td><td></td></tr> <tr><td><code>height</code></td><td>支持</td><td></td></tr> <tr><td rowspan="5">最小和最大尺寸</td></tr> <tr><td><code>minWidth</code></td><td>支持,除了 <code>min-content</code>、<code>max-content</code> 和 <code>fit-content</code></td><td></td></tr> <tr><td><code>minHeight</code></td><td>支持,除了 <code>min-content</code>、<code>max-content</code> 和 <code>fit-content</code></td><td></td></tr> <tr><td><code>maxWidth</code></td><td>支持,除了 <code>min-content</code>、<code>max-content</code> 和 <code>fit-content</code></td><td></td></tr> <tr><td><code>maxHeight</code></td><td>支持,除了 <code>min-content</code>、<code>max-content</code> 和 <code>fit-content</code></td><td></td></tr> <tr><td rowspan="5"><code>border</code></td></tr> <tr><td>宽度 (<code>borderWidth</code>, <code>borderTopWidth</code>, ...)</td><td>支持</td><td></td></tr> <tr><td>样式 (<code>borderStyle</code>, <code>borderTopStyle</code>, ...)</td><td><code>solid</code> 和 <code>dashed</code>,默认为 <code>solid</code></td><td></td></tr> <tr><td>颜色 (<code>borderColor</code>, <code>borderTopColor</code>, ...)</td><td>支持</td><td></td></tr> <tr><td> 简写 (<code>border</code>, <code>borderTop</code>, ...)</td><td>支持,如 <code>1px solid gray</code><br/> </td><td></td></tr> <tr><td rowspan="6"><code>borderRadius</code></td></tr> <tr><td><code>borderTopLeftRadius</code></td><td>支持</td><td></td></tr> <tr><td><code>borderTopRightRadius</code></td><td>支持</td><td></td></tr> <tr><td><code>borderBottomLeftRadius</code></td><td>支持</td><td></td></tr> <tr><td><code>borderBottomRightRadius</code></td><td>支持</td><td></td></tr> <tr><td>简写</td><td>支持,如 <code>5px</code>、<code>50% / 5px</code></td><td></td></tr> <tr><td rowspan="11">弹性布局</td></tr> <tr><td><code>flexDirection</code></td><td><code>column</code>、<code>row</code>、<code>row-reverse</code>、<code>column-reverse</code>,默认为<code>row</code></td><td></td></tr> <tr><td><code>flexWrap</code></td><td><code>wrap</code>、<code>nowrap</code>、<code>wrap-reverse</code>,默认为<code>wrap</code></td><td></td></tr> <tr><td><code>flexGrow</code></td><td>支持</td><td></td></tr> <tr><td><code>flexShrink</code></td><td>支持</td><td></td></tr> <tr><td><code>flexBasis</code></td><td>支持,除了<code>auto</code></td><td></td></tr> <tr><td><code>alignItems</code></td><td><code>stretch</code>、<code>center</code>、<code>flex-start</code>、<code>flex-end</code>、<code>baseline</code>、<code>normal</code>,默认为<code>stretch</code></td><td></td></tr> <tr><td><code>alignContent</code></td><td>支持</td><td></td></tr> <tr><td><code>alignSelf</code></td><td>支持</td><td></td></tr> <tr><td><code>justifyContent</code></td><td>支持</td><td></td></tr> <tr><td><code>gap</code></td><td>支持</td><td></td></tr> <tr><td rowspan="5">字体</td></tr> <tr><td><code>fontFamily</code></td><td>支持</td><td></td></tr> <tr><td><code>fontSize</code></td><td>支持</td><td></td></tr> <tr><td><code>fontWeight</code></td><td>支持</td><td></td></tr> <tr><td><code>fontStyle</code></td><td>支持</td><td></td></tr> <tr><td rowspan="12">文本</td></tr> <tr><td><code>tabSize</code></td><td>支持</td><td></td></tr> <tr><td><code>textAlign</code></td><td><code>start</code>、<code>end</code>、<code>left</code>、<code>right</code>、<code>center</code>、<code>justify</code>,默认为<code>start</code></td><td></td></tr> <tr><td><code>textTransform</code></td><td><code>none</code>、<code>lowercase</code>、<code>uppercase</code>、<code>capitalize</code>,默认为<code>none</code></td><td></td></tr> <tr><td><code>textOverflow</code></td><td><code>clip</code>、<code>ellipsis</code>,默认为<code>clip</code></td><td></td></tr> <tr><td><code>textDecoration</code></td><td>支持线型<code>underline</code>和<code>line-through</code>,以及样式<code>dotted</code>、<code>dashed</code>、<code>solid</code></td><td><a href="https://og-playground.vercel.app/?share=nVLLTsMwEPwVaxHqJYgUOCCr9EL5Ajj24mQ3icH1Ro5DW6L8O3ZeQpwKJ-_M7ox25O0gZySQsEH9ubdCNP5s6KnrYi1ERbqsvBSrdZper5KRPGr01S8OdVMbdQ5sYeg0s7HeaUe512xDL2fTHuzcrRWitqUU63RiMpV_lI5bi89s2AXFVVEUixtb_6q_SIr7u4kqVR3lEfT93m5jEZMsMYSnk99Rzk5NO1i2tArT21hsbsPwJaqwEjmjJ-mCLtbH4RtfhWxlNVj8JP6-hUD2nlA4wsFthP_aRqBqqmCVmXYMN-LZa34hAa6jvAHZwXACIB_TNIHxRkA-RICUtSXIQpmGEqADv-u3cx0PzB8HFHziP74cMkKQ3rXUJ-BVFiYqMoaP7AxC_w0">示例</a></td></tr> <tr><td><code>textShadow</code></td><td>支持</td><td></td></tr> <tr><td><code>lineHeight</code></td><td>支持</td><td></td></tr> <tr><td><code>letterSpacing</code></td><td>支持</td><td></td></tr> <tr><td><code>whiteSpace</code></td><td><code>normal</code>、<code>pre</code>、<code>pre-wrap</code>、<code>pre-line</code>、<code>nowrap</code>,默认为<code>normal</code></td><td></td></tr> <tr><td><code>wordBreak</code></td><td><code>normal</code>、<code>break-all</code>、<code>break-word</code>、<code>keep-all</code>,默认为<code>normal</code></td><td></td></tr> <tr><td><code>textWrap</code></td><td><code>wrap</code>、<code>balance</code>,默认为<code>wrap</code></td><td></td></tr> <tr><td rowspan="7">背景</td></tr> <tr><td><code>backgroundColor</code></td><td>支持,单一值</td><td></td></tr> <tr><td><code>backgroundImage</code></td><td><code>linear-gradient</code>、<code>radial-gradient</code>、<code>url</code>,单一值</td><td></td></tr> <tr><td><code>backgroundPosition</code></td><td>支持单一值</td><td></td></tr> <tr><td><code>backgroundSize</code></td><td>支持两个值的大小,如 `10px 20%`</td><td></td></tr> <tr><td><code>backgroundClip</code></td><td><code>border-box</code>、<code>text</code></td><td></td></tr> <tr><td><code>backgroundRepeat</code></td><td><code>repeat</code>、<code>repeat-x</code>、<code>repeat-y</code>、<code>no-repeat</code>,默认为<code>repeat</code></td><td></td></tr> <tr><td rowspan="5"><code>transform</code></td></tr> <tr><td>平移(<code>translate</code>、<code>translateX</code>、<code>translateY</code>)</td><td>支持</td><td></td></tr> <tr><td>旋转</td><td>支持</td><td></td></tr> <tr><td>缩放(<code>scale</code>、<code>scaleX</code>、<code>scaleY</code>)</td><td>支持</td><td></td></tr> <tr><td>倾斜(<code>skew</code>、<code>skewX</code>、<code>skewY</code>)</td><td>支持</td><td></td></tr> <tr> <td colspan="2"><code>transformOrigin</code></td> <td>支持一值和两值语法(相对和绝对值都支持)</td> <td></td> </tr> <tr> <td colspan="2"><code>objectFit</code></td> <td><code>contain</code>、<code>cover</code>、<code>none</code>,默认为<code>none</code></td> <td></td> </tr> <tr> <td colspan="2"><code>opacity</code></td> <td>支持</td> <td></td> </tr> <tr> <td colspan="2"><code>boxShadow</code></td> <td>支持</td> <td></td> </tr> <tr> <td colspan="2"><code>overflow</code></td> <td><code>visible</code>和<code>hidden</code>,默认为<code>visible</code></td> <td></td> </tr> <tr> <td colspan="2"><code>filter</code></td> <td>支持</td> <td></td> </tr> <tr> <td colspan="2"><code>clipPath</code></td> <td>支持</td> <td><a href="https://og-playground.vercel.app/?share=XVJNb9wgEP0rI6poW8lJnX6pstpe0h7aQ1UlrXLJBZvBZosZBDgbZ7X_PQMbZze5wPCGmXmPx1Z0pFA04osytzcOIKbZ4tftNscAA5p-SA2szuv6ZFXtwY1RaXiBKRO9lTOj2uLdgub4uwnYJUOOcx3ZaXRLVlrTu58Jx5hT6BKGJbWeYjJ6viAGXZ7_PN3K7n8faHLqgiwFzr_SWj9N5aorc48NvH93BF0_avlU1wXd7W7ctxws0l-KP8j_8FhypP4Y8lIp4_oGzg_YgSKzY6FDau2EC0WAzhr_R5Z39GTnntzrj_UJ1BU34Z3jKi_lVEGd4zerfXEmDlCoA_yLqKCdIdKIQBrSgLChYNUqgpWhx5igo9FLZzBW8Bvv0tk6AjrZWoww0wSJoAsoE4KerD2NianDNbYgvbemk9m8mGdwLbqstEyxXMHNL1F2CTTXTyFPkE6BYbP6wIV81dMGAzeGS_b0tJWZ7y95K6-6YHzi4WTzNU2hdNUylrbtZKyKZ8Wft2wQy112UQnyhZRotqL4IZrP7IfY-yWabI5Q2E69aLS0ESuBI63N39nnv5425cR98r_4MbaoRJPChLtKJNnyjQGtpfKMYvcA">示例</a></td> </tr> <tr> <td colspan="2"><code>lineClamp</code></td> <td>支持</td> <td><a href="https://og-playground.vercel.app/?share=5VPBbtQwEP2VkRFakNKSshxQBBwoXDhwaEFc9uLYk6xbx2PZk-6G1Up8DR_GlzDOkgr13FtPGb_xvPf8ojkoQxZVo95Zd7cJAJknj-8Ph1IDbNH1W25gdVHXz1fVCdw5y9sHmHU5ej0J2nncL2ipP7mEhh0F6Rny4xCWbtTWutA3cFH_Q1ptbvtEY7CX5CnJxLOu6-7ZKPC1-4kNrF_P0PG4CR9KsZh_aP9_X60nc7tQAXgX8NLrIQrbPTjo1LvwkZhpkJF1HferU69IAcxiAN8zWmgnyDQgUAe8RdhR8naVwQsFZgZDQ9TBYa7gK-75_CYDBt16zDDRCExgEmpG6EbvzzLLy-EHtqBj9M7oElguGjKLocQ0q3iZEPIr1Iahk_kxFQUdLLjA2CcZlKuRdpiEGK7GzGetLn6_6Dt9bZKLLOIkz-8l0DSzdjrPtO3ovM3nc6KvJNJHyHa1ho368-s3vDBihQb5fVayEa-BX27UE093-apKUZxNqeag5v1Szdu6rtRpAVXzphwstmOvmk77jJXCgW7ctymW7eXdfBKesiSfhxatajiNeKwU61ZubNF7mmNUx78">示例</a></td> </tr> <tr><td rowspan="5">遮罩</td></tr> <tr><td><code>maskImage</code></td><td><code>linear-gradient(...)</code>、<code>radial-gradient(...)</code>、<code>url(...)</code></td><td><a href="https://og-playground.vercel.app/?share=pZJfb9MwFMW_imVp2ZDS5s_I1kULSMAkhgRoYlJf-uLYN8ltHTvYDm2o-t2xuxXBXvcQXed3rONj37unXAugJb0V-GulCLFuklDt92FNSAfYdq4k51manp3HT3CLwnUvmEA7SDZ52kjYnWhYf0ID3KFWXuNajr06qUxiq-4d9DZIoByYk7QercNm-qg9VOH8_-XG8x_4G0pymf-Dls9pr9L0mdaMb1qjRyW8x2jkRefcYMskwZ61YOejCrFtN-e6T4ZOOz3LinyRL65v3ubZdTZrari8KkQmbhh_jzuJdWXqWTbP51n0s1oUUdNX66GNuNFD5TP6MkXbKsvTNOK2sqatI9yhqGD60vHPHxq2fMDv67v022NbNA9vTjfqmd3ch0w-p2ECmZy1oXrLC46GSyDMkSI9C19MajlCTJxhPj8zftNfoyXUG3RfX21HkuTYBf-whhhowGMOBBXpXC_DWYfDSr1bqdvET46vNKZ6CH22tNzT44zQMrxDTJ-miJahL1RAPba0bJi0EFPo9RofpyGMoNse_7xRaOZdX4OgpTMjHGLqWO13dCCl3mojBT38AQ">示例</a></td></tr> <tr><td><code>maskPosition</code></td><td>支持</td><td><a href="https://og-playground.vercel.app/?share=pVJda9swFP0rQlC3Ayf-6NKmpt5gW2Ed7KOskJe8yNK1fRNZ8iR5iRfy3yelCayFPfXBvtK5h3uP7j07yrUAWtBbgb-XihDrRgnlbhfOhLSATesKcp6l6dl5_ARuULj2BSbQ9pKNHq0lbE9oOH9CA9yhVj7HtRw6dcoyiY26d9DZkALlwJxSq8E6rMeP2oMq9H-erj3-E_9AQS7zf6DFUe1Vmh7RivF1Y_SghK8xGHnROtfbIkmwYw3Y6aCCbNtOue6SvtVOT7JZPs_n1zdv8-w6m9QVXF7NRCZuGH-PW4lVaapJNs2nWfSrnM-iuitXfRNxo_vSa_RhjDZllqdpxG1pTVNFuEVRwvil5Z8_1GzxgN9Xd-m3x2ZWP7w5vahjdn0fNHmdhglkctKE6EtecDRcAmGOzNKz8MWkkgPExBnm9TPjSc8K_dAWjxP3O-q35PA_MRZQrdF9fX1DkiSHRfnZG2KgBo9zIKhI6zr5stl_RAXafr9U75bqNvEe9JHGVPeBammxowe30SJMNKZPfqRF2DAVUA0NLWomLcQUOr3Cx7EPZnabw80XCra46yoQtHBmgH1MHas8owUp9UYbKej-Lw">示例</a></td></tr> <tr><td><code>maskSize</code></td><td>支持两个值的大小,如 `10px 20%`</td><td><a href="https://og-playground.vercel.app/?share=pVLfb9MwEP5XLEvLhpQ2P0a3LlpAAiYxJEATk_rSF8e-JNc6drAd2lD1f8duV8H6yoN19ved7j7ffTvKtQBa0HuBv5aKEOtGCeVuF-6EtIBN6wpymaXpxWV8BDcoXHuGCbS9ZKNHawnbExrun9AAd6iV57iWQ6dOLJPYqEcHnQ0UKAfmRK0G67AeP2oPqtD_NV17_Af-hoJc5_9Aixe1N2n6glaMrxujByV8jcHIq9a53hZJgh1rwE4HFWTbdsp1l_StdnqSzfJ5Pr-9e5tnt9mkruD6ZiYyccf4e9xKrEpTTbJpPs2in-V8FtVdueqbiBvdl16jD2O0KbM8TSNuS2uaKsItihLGLy3__KFmiyf8vnpIvz03s_rpzelHHbPrx6DJ6zRMIJOTJkRf8oqj4RIIc2SWXoQTk0oOEBNnmNfPjE96Veg4Gr-ffkvyvztaQLVG9_X_O5EkOWzID90QAzV4nANBRVrXyfNm52oCv98v1buluk-863ykMdV98IilxY4e_EWLMMOYHh1Ii7BTKqAaGlrUTFqIKXR6hc9jH-zrNoeXLxSM8NBVIGjhzAD7mDpW-YwWpNQbbaSg-z8">示例</a></td></tr> <tr><td><code>maskRepeat</code></td><td><code>repeat</code>、<code>repeat-x</code>、<code>repeat-y</code>、<code>no-repeat</code>,默认为 <code>repeat</code></td><td><a href="https://og-playground.vercel.app/?share=nVbpjqNIEn6VkqXVzMg1AhtjQ-3MStwGA-Ywl9U_hssJ5jSHAbf63TdxdfXUzh4_FhllHF8cGZkm4usirKJ48bb4LUrvX8qXl7ab8vj3r19n-uUliVOQdG8vP61Q9G8_vb4LhzTqkr_IorStc3-C0ksejx_SmWbTJg67tCqhLqzyvig_tH6eglLs4qKdVXHZxc2H6tq3XXqZmAoKyzn-v6ovUG6mj_jtBVt_Ejnfs92i6Hdp4IcZaKq-jKCPvsl_jvzOf0sLH8RIXYK_B34bbzevqU0fjQE9CKCi4KOaVsJZAFK0PvMaQ3lwYbPiSNqzgHJV00BFqmk34XaGiEbucHlxslDqMNtRAJpyJkUpM0NTFAcXzqco6ztPUSbggs-8BTgY_AMvwl9UU9Qz_lPvPP0-WaiEz6zinkKoPwLIs9_lkGcATGEO-o6jTUANn3iKeJJ2F-6CJ58PJp8_ICFzA7QeFZqSbqHwBOW1zSeow62UY6HeAxNPzgKZnk18E7jfU2LHzbFMulBY5ZHAgVhYtUGpbGMWTT3HuHuFtZ35wLFRzyRScQ-2EDNEQkuKeaJaDM0GmJSLrNcrzGYQr5uDyFBA20vZ-VqbBuf98BkWRqGZUhXtjeGYEvcIizC5DB9yQU7niRiPpwyXH9QkP8RJdqF9unrEDo56Luig_fXD9yf_3NlVr2GRw3zye5DS01nwtp4j3SNXJ8VU_IH_eD9ygfjifEVTf2-gIVvd5TUO8-CzYC3l8rNWJOo750J-cHBfRKqB6rMf4t2-1mDsPCiN5Bn_uhk15t3umJGT79h9JPCQJ_tP9oSM_YfcP-rGwFrAPViZIUAbiH2v97P-p81BsHcJDc-ZWvGSwfHWkRZUm-8UDuWsMsJM7ITXvl8YYxpVaWIcDFuQMp-lDYZXUyUzNVLX4KYTMBgGNxwFaEUoF84QWe6mXMYz13GVeU91ISF0sPF8oDNpbYtxHVWOmSxRzOXLyHCzEenHcHk5as7liJUdRl2SjhWUE3PZ2gdM43nDPrEUGwnJxHISvL6WuHksd8qjuK66bTDEQyKKHu5qIGNFxvAo5byyizvKZ1y7x28hf-CjZXAw2EGzWn_bP04b2lbtMx3Y0jpXaDNktVtXbPH7o8A3k8q5jhVNxsBWhe0F8jqqYqJnr17XAO9o1UZrAcDRo3tY7Zc5wGhikM4Wilz3YTH1akMOy1XMMGOVEZokexWWlo7HMrJ4mBzVqM7u8aSyN7SWb870cAKdUCqJ6c2z3xr6gV61QqrD22-O_pRosq3iHQHGzFRQ5Yisjo61Tseq0VByWxKmdVrHa9fRk122bBpiUHnDCTG_OR28OudwcW0E4qGozUaOdnHZRLesiUbXkbg1bku7lGdSrNTYBlHqgxtVdr9RjvZyd8xXd4BUYBvou7VvXLoxGkldoSrXdvmzRHnurQiLi9WfDPsgi_dJE5cB4pIZG6gaVm1qkrxQVSUqZU3d0bDMtxfdU3kSiVwJKVrPXy8HaWAJzNBDjq4entTprFOeWL32HNwX1u2dXVfSQJQeeyMecFNHn6ezUUmaO9md4uaKL3twybpTNuQ1QYGym8gitAjRu7DoFaQkWHI7miNzZ2UUsuEE2LlmjNrpp5XTh3mM-eXt_mi2O1kor9tBsfwbxgILhzkJ68PRPh25nlhRkxTTuWQq6dWVpp3BVPWq6ree34P7ivDPAljuwsQbB8fxjnTSn-lsx7sPMdwQe48zB3lI0rI02Vgz2kBmsColkI3M3QuwOSUEzZuCd99fNIykkP0YINFwL6LNUiQmKiAPoo5PqkVFGc1fEaQtxrW6psdO4C5IhRxC1916J3mrxeDerWKcRC_0etLjCiR7IexI2eG0w57VB4S0zd53hq0xZI7sNuqZ2ka4KhmHvBQke2sbO_gn013TtlADlAmPyZEcSqsdVrqFl8IbmAgqnY9pFukjifCFN1mcGPOEFPsIAi-V0rgqfdMZSlIkpEGa4ua3J44SQ4thMqQRr8ujjuxUKgCIq3Iaheg6fbOvF2qN895725IMC-eaTAIA_P77Lx_NvfDbTJw79NvLH3laxn7zK2j8KIUTwM9d9dLMPf71Jcj7-PWla_yyrf0G6n7545P9-3AwTyj1-LJaz8tn90Zcx_48VjRP4tcfSicOsrRTPmXwl6GhvYPlWOQfg4O2V9fnicZ8x0B92OyOLDWIKV2dnbz097B5XMGgMCKICnsK1_MHGk0VczNCzBp-2DG9IDeaKQ4iSwHlJEIsNSrXp49N4Ix9-PjUXGCjiyYcUyb8HhbhfcYpDPmIijDVruPguUYlCjBmho4KMzxUk6Yhpn2-zDDILNeqJ0g_LKDDWDI7v0_dKLMZpJWVyHM45NeqOazgikMfhgJt1KvVzuts66QiOBd5G8D9RuukjgQrFRliCZvOnMvyx0H8ezH_n-P808v_ONQ_Qf_laL99-1L-40v5GwLHXLguXhdVPQ-l7eLt6-I50C7eZpevi_eRd_E2D5CLKA56sHi7-Hkbvy7iorqmp6me5-VueHLQ0Tx5ckUQR4u3runjb6-Lzg8gIonzvBqqJo8W3_4J">示例</a></td></tr> 注意:
  1. 不支持三维变换。
  2. SVG 中不支持 z-index。文档中较后出现的元素将被绘制在上层。
  3. 所有元素的 box-sizing 都设置为 border-box
  4. 不支持 calc
  5. overflow: hiddentransform 不能同时使用。
  6. currentcolor 仅支持 color 属性。

语言和排版

目前不支持字距调整、连字等高级排版功能和其他 OpenType 特性。

同样不支持从右到左的语言。

字体

Satori 目前支持三种字体格式:TTF、OTF 和 WOFF。请注意,目前不支持 WOFF2。使用 Satori 渲染任何文本时必须指定字体,并将字体数据作为 ArrayBuffer(网页)或 Buffer(Node.js)传递:

await satori( <div style={{ fontFamily: 'Inter' }}>Hello</div>, { width: 600, height: 400, fonts: [ { name: 'Inter', data: inter, weight: 400, style: 'normal', }, { name: 'Inter', data: interBold, weight: 700, style: 'normal', }, ], } )

可以向 Satori 传递多种字体并在 fontFamily 中使用。

表情符号

要为特定字素渲染自定义图像,可以使用 graphemeImages 选项将字素映射到图像源:

await satori( <div>Next.js is 🤯!</div>, { ..., graphemeImages: { '🤯': 'https://cdnjs.cloudflare.com/ajax/libs/twemoji/14.0.2/svg/1f92f.svg', }, } )

图像将被调整为当前字体大小(宽度和高度)的正方形。

语言环境

Satori 支持在不同语言环境中渲染文本。您可以通过 lang 属性指定支持的语言环境:

await satori( <div lang="ja-JP"></div> )

相同的字符在不同的语言环境中可能会有不同的渲染方式,您可以在必要时指定语言环境,以强制使用特定字体和语言环境进行渲染。查看此示例了解更多信息。

支持的语言环境作为 Locale 枚举类型导出。

动态加载表情符号和字体

Satori 支持动态加载表情符号图像(字素图片)和字体。当渲染文本段但缺少图像或字体时,将调用 loadAdditionalAsset 函数:

await satori( <div>👋 你好</div>, { // `code` 将是检测到的语言代码,如果是表情符号则为 `emoji`,如果无法判断则为 `unknown`。 // `segment` 将是要渲染的内容。 loadAdditionalAsset: async (code: string, segment: string) => { if (code === 'emoji') { // 如果 segment 是表情符号 return `data:image/svg+xml;base64,...` } // 如果 segment 是普通文本 return loadFontFromSystem(code) } } )

运行时和 WASM

Satori 可以在浏览器、Node.js (>= 16) 和 Web Workers 中使用。

默认情况下,Satori 在浏览器运行时依赖于 asm.js,在 Node.js 中依赖于原生模块。但是,您可以选择通过导入 satori/wasm 来加载 WASM,并向 Satori 提供初始化的 Yoga WASM 模块实例:

import satori, { init } from 'satori/wasm' import initYoga from 'yoga-wasm-web' const yoga = initYoga(await fetch('/yoga.wasm').then(res => res.arrayBuffer())) init(yoga) await satori(...)

在浏览器或 Node.js 环境中运行时,需要托管 WASM 文件并在初始化之前获取。asm.js 可以与库一起打包。在这种情况下,WASM 应该更快。

在 Node.js 服务器上运行时,原生模块应该更快。但是,有些 Node.js 环境不支持原生模块(例如 StackBlitz 的 WebContainers),或者其他支持 WASM 的 JS 运行时(例如 Vercel 的 Edge Runtime、Cloudflare Workers 或 Deno)。

此外,asm.js、原生模块和 WASM 之间还有其他差异,如安全性和兼容性。

总的来说,每种选择都有许多权衡,最好选择最适合您的用例的方案。

字体嵌入

默认情况下,Satori 将文本渲染为 SVG 中的 <path>,而不是 <text>。这意味着它将字体路径数据作为内联信息嵌入,因此后续处理(例如在另一个平台上渲染 SVG)不需要再处理字体文件。

您可以通过将 embedFont 设置为 false 来关闭此行为,Satori 将使用 <text> 替代:

const svg = await satori( <div style={{ color: 'black' }}>hello, world</div>, { ..., embedFont: false, }, )

调试

要绘制用于调试的边界框,可以传递 debug: true 作为选项:

const svg = await satori( <div style={{ color: 'black' }}>hello, world</div>, { ..., debug: true, }, )
<br/>

贡献

您可以使用 Vercel OG Image Playground 来测试和报告 Satori 的错误。在开启拉取请求之前,请遵循我们的贡献指南

<br/>

作者


<a aria-label="Vercel logo" href="https://vercel.com"> <img src="https://badgen.net/badge/icon/Made%20by%20Vercel?icon=zeit&label&color=black&labelColor=black"> </a>

编辑推荐精选

Keevx

Keevx

AI数字人视频创作平台

Keevx 一款开箱即用的AI数字人视频创作平台,广泛适用于电商广告、企业培训与社媒宣传,让全球企业与个人创作者无需拍摄剪辑,就能快速生成多语言、高质量的专业视频。

即梦AI

即梦AI

一站式AI创作平台

提供 AI 驱动的图片、视频生成及数字人等功能,助力创意创作

扣子-AI办公

扣子-AI办公

AI办公助手,复杂任务高效处理

AI办公助手,复杂任务高效处理。办公效率低?扣子空间AI助手支持播客生成、PPT制作、网页开发及报告写作,覆盖科研、商业、舆情等领域的专家Agent 7x24小时响应,生活工作无缝切换,提升50%效率!

TRAE编程

TRAE编程

AI辅助编程,代码自动修复

Trae是一种自适应的集成开发环境(IDE),通过自动化和多元协作改变开发流程。利用Trae,团队能够更快速、精确地编写和部署代码,从而提高编程效率和项目交付速度。Trae具备上下文感知和代码自动完成功能,是提升开发效率的理想工具。

AI工具TraeAI IDE协作生产力转型热门
蛙蛙写作

蛙蛙写作

AI小说写作助手,一站式润色、改写、扩写

蛙蛙写作—国内先进的AI写作平台,涵盖小说、学术、社交媒体等多场景。提供续写、改写、润色等功能,助力创作者高效优化写作流程。界面简洁,功能全面,适合各类写作者提升内容品质和工作效率。

AI辅助写作AI工具蛙蛙写作AI写作工具学术助手办公助手营销助手AI助手
问小白

问小白

全能AI智能助手,随时解答生活与工作的多样问题

问小白,由元石科技研发的AI智能助手,快速准确地解答各种生活和工作问题,包括但不限于搜索、规划和社交互动,帮助用户在日常生活中提高效率,轻松管理个人事务。

热门AI助手AI对话AI工具聊天机器人
Transly

Transly

实时语音翻译/同声传译工具

Transly是一个多场景的AI大语言模型驱动的同声传译、专业翻译助手,它拥有超精准的音频识别翻译能力,几乎零延迟的使用体验和支持多国语言可以让你带它走遍全球,无论你是留学生、商务人士、韩剧美剧爱好者,还是出国游玩、多国会议、跨国追星等等,都可以满足你所有需要同传的场景需求,线上线下通用,扫除语言障碍,让全世界的语言交流不再有国界。

讯飞智文

讯飞智文

一键生成PPT和Word,让学习生活更轻松

讯飞智文是一个利用 AI 技术的项目,能够帮助用户生成 PPT 以及各类文档。无论是商业领域的市场分析报告、年度目标制定,还是学生群体的职业生涯规划、实习避坑指南,亦或是活动策划、旅游攻略等内容,它都能提供支持,帮助用户精准表达,轻松呈现各种信息。

AI办公办公工具AI工具讯飞智文AI在线生成PPTAI撰写助手多语种文档生成AI自动配图热门
讯飞星火

讯飞星火

深度推理能力全新升级,全面对标OpenAI o1

科大讯飞的星火大模型,支持语言理解、知识问答和文本创作等多功能,适用于多种文件和业务场景,提升办公和日常生活的效率。讯飞星火是一个提供丰富智能服务的平台,涵盖科技资讯、图像创作、写作辅助、编程解答、科研文献解读等功能,能为不同需求的用户提供便捷高效的帮助,助力用户轻松获取信息、解决问题,满足多样化使用场景。

热门AI开发模型训练AI工具讯飞星火大模型智能问答内容创作多语种支持智慧生活
Spark-TTS

Spark-TTS

一种基于大语言模型的高效单流解耦语音令牌文本到语音合成模型

Spark-TTS 是一个基于 PyTorch 的开源文本到语音合成项目,由多个知名机构联合参与。该项目提供了高效的 LLM(大语言模型)驱动的语音合成方案,支持语音克隆和语音创建功能,可通过命令行界面(CLI)和 Web UI 两种方式使用。用户可以根据需求调整语音的性别、音高、速度等参数,生成高质量的语音。该项目适用于多种场景,如有声读物制作、智能语音助手开发等。

下拉加载更多