Project Icon

satori

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

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

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。


文档

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 功能:

注意:
  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,
  },
)

贡献

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


作者


属性属性扩展支持的值示例
displaynoneflex,默认为 flex
positionrelativeabsolute,默认为 relative
color支持
margin
marginTop支持
marginRight支持
marginBottom支持
marginLeft支持
位置
top支持
right支持
bottom支持
left支持
尺寸
width支持
height支持
最小和最大尺寸
minWidth支持,除了 min-contentmax-contentfit-content
minHeight支持,除了 min-contentmax-contentfit-content
maxWidth支持,除了 min-contentmax-contentfit-content
maxHeight支持,除了 min-contentmax-contentfit-content
border
宽度 (borderWidth, borderTopWidth, ...)支持
样式 (borderStyle, borderTopStyle, ...)soliddashed,默认为 solid
颜色 (borderColor, borderTopColor, ...)支持
简写 (border, borderTop, ...)支持,如 1px solid gray
borderRadius
borderTopLeftRadius支持
borderTopRightRadius支持
borderBottomLeftRadius支持
borderBottomRightRadius支持
简写支持,如 5px50% / 5px
弹性布局
flexDirectioncolumnrowrow-reversecolumn-reverse,默认为row
flexWrapwrapnowrapwrap-reverse,默认为wrap
flexGrow支持
flexShrink支持
flexBasis支持,除了auto
alignItemsstretchcenterflex-startflex-endbaselinenormal,默认为stretch
alignContent支持
alignSelf支持
justifyContent支持
gap支持
字体
fontFamily支持
fontSize支持
fontWeight支持
fontStyle支持
文本
tabSize支持
textAlignstartendleftrightcenterjustify,默认为start
textTransformnonelowercaseuppercasecapitalize,默认为none
textOverflowclipellipsis,默认为clip
textDecoration支持线型underlineline-through,以及样式dotteddashedsolid示例
textShadow支持
lineHeight支持
letterSpacing支持
whiteSpacenormalprepre-wrappre-linenowrap,默认为normal
wordBreaknormalbreak-allbreak-wordkeep-all,默认为normal
textWrapwrapbalance,默认为wrap
背景
backgroundColor支持,单一值
backgroundImagelinear-gradientradial-gradienturl,单一值
backgroundPosition支持单一值
backgroundSize支持两个值的大小,如 `10px 20%`
backgroundClipborder-boxtext
backgroundRepeatrepeatrepeat-xrepeat-yno-repeat,默认为repeat
transform
平移(translatetranslateXtranslateY支持
旋转支持
缩放(scalescaleXscaleY支持
倾斜(skewskewXskewY支持
transformOrigin支持一值和两值语法(相对和绝对值都支持)
objectFitcontaincovernone,默认为none
opacity支持
boxShadow支持
overflowvisiblehidden,默认为visible
filter支持
clipPath支持示例
lineClamp支持示例
遮罩
maskImagelinear-gradient(...)radial-gradient(...)url(...)示例
maskPosition支持示例
maskSize支持两个值的大小,如 `10px 20%`示例
maskRepeatrepeatrepeat-xrepeat-yno-repeat,默认为 repeat示例
项目侧边栏1项目侧边栏2
推荐项目
Project Cover

豆包MarsCode

豆包 MarsCode 是一款革命性的编程助手,通过AI技术提供代码补全、单测生成、代码解释和智能问答等功能,支持100+编程语言,与主流编辑器无缝集成,显著提升开发效率和代码质量。

Project Cover

AI写歌

Suno AI是一个革命性的AI音乐创作平台,能在短短30秒内帮助用户创作出一首完整的歌曲。无论是寻找创作灵感还是需要快速制作音乐,Suno AI都是音乐爱好者和专业人士的理想选择。

Project Cover

白日梦AI

白日梦AI提供专注于AI视频生成的多样化功能,包括文生视频、动态画面和形象生成等,帮助用户快速上手,创造专业级内容。

Project Cover

有言AI

有言平台提供一站式AIGC视频创作解决方案,通过智能技术简化视频制作流程。无论是企业宣传还是个人分享,有言都能帮助用户快速、轻松地制作出专业级别的视频内容。

Project Cover

Kimi

Kimi AI助手提供多语言对话支持,能够阅读和理解用户上传的文件内容,解析网页信息,并结合搜索结果为用户提供详尽的答案。无论是日常咨询还是专业问题,Kimi都能以友好、专业的方式提供帮助。

Project Cover

讯飞绘镜

讯飞绘镜是一个支持从创意到完整视频创作的智能平台,用户可以快速生成视频素材并创作独特的音乐视频和故事。平台提供多样化的主题和精选作品,帮助用户探索创意灵感。

Project Cover

讯飞文书

讯飞文书依托讯飞星火大模型,为文书写作者提供从素材筹备到稿件撰写及审稿的全程支持。通过录音智记和以稿写稿等功能,满足事务性工作的高频需求,帮助撰稿人节省精力,提高效率,优化工作与生活。

Project Cover

阿里绘蛙

绘蛙是阿里巴巴集团推出的革命性AI电商营销平台。利用尖端人工智能技术,为商家提供一键生成商品图和营销文案的服务,显著提升内容创作效率和营销效果。适用于淘宝、天猫等电商平台,让商品第一时间被种草。

Project Cover

AIWritePaper论文写作

AIWritePaper论文写作是一站式AI论文写作辅助工具,简化了选题、文献检索至论文撰写的整个过程。通过简单设定,平台可快速生成高质量论文大纲和全文,配合图表、参考文献等一应俱全,同时提供开题报告和答辩PPT等增值服务,保障数据安全,有效提升写作效率和论文质量。

投诉举报邮箱: service@vectorlightyear.com
@2024 懂AI·鲁ICP备2024100362号-6·鲁公网安备37021002001498号