# @basenative/og-image 中文文档

规范地址：https://npmcn.com/package/%40basenative/og-image/

版本：3\.0\.0
npm 元数据更新时间：2026-10-31T13:47:05.265Z
中文译文更新时间：2026-10-31T16:27:04.612Z
软件包许可：Apache-2\.0

本文由上游 README 机器翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40basenative/og-image
原文对照：https://npmcn.com/package/%40basenative/og-image/?lang=original
项目主页：https://github.com/DuganLabs/BaseNative/tree/main/packages/og-image#readme
源码仓库：https://github.com/DuganLabs/BaseNative

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：103 kB，20 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- 运行依赖：1 个
- peer 依赖：satori ^0\.38\.2
- 首次发布：2026-10-18T05:29:32.969Z
- 最新版本发布：2026-10-31T13:47:04.952Z
- 已发布版本数：11（近 12 个月 11 个）

## 中文简介

运行时无关OG /社交分享PNG渲染器- SVG卡场景栅格化的resvg-wasm，与CDN+ kv缓存字体；运行在Cloudflare Workers、Node、Deno和Bun上

## 安装

```sh
npm install @basenative/og-image
```

也可以使用：`pnpm add @basenative/og-image`、`yarn add @basenative/og-image`、`bun add @basenative/og-image`

## README

# @ basenative/og-image

> 运行时不可知的OG /社会分享PNG渲染器- SVG卡场景栅格化 `resvg-wasm`，与CDN + kv缓存字体。运行在Cloudflare Workers， Node， Deno和Bun上。

部分 [BaseNative](https://github.com/DuganLabs/basenative) 生态系统——基于信号的web运行时，基于原生HTML。

在请求时间渲染1200x630 png `og:image`， `twitter:image`,以及任意共享卡端点。

## 如果您是从0.2.x升级，请先阅读本文

`renderPng` -顿悟的入口点- **已移动** 到一个单独的出口：

```js
-import { renderPng } from "@basenative/og-image";
+import { renderPng } from "@basenative/og-image/satori";
```

和 `satori` 现在是一个 **可选的对等依赖**: 如果你自己安装 使用那条路径。在Cloudflare Workers上，你不能；使用 `renderCard`/`renderSvg` 而是从主条目，这就是这个版本存在的目的。

### 为什么

此软件包的每个版本，包括0.2.2 **不能执行 Cloudflare所有工作人员**，尽管是为他们写的。 `satori` 导入 `harfbuzzjs` （它的文本塑造器），以及harfbuzz的刻字加载器 按顺序问两个环境问题，工人回答错误。已复制 反对真正的工人 (`wrangler dev`， `compatibility_date` 2026-04-23， `nodejs_compat`):

1.  `TypeError: Cannot read properties of undefined (reading 'href')` - - - 加载程序将 `WorkerGlobalScope`，结束“浏览器工作器”，并读取 `self.location.href`。workerd定义 `WorkerGlobalScope` 和 `self`, 定义了 **否 `location`**.
2.  垫片 `location` 在它之前，你会得到 `ReferenceError: __dirname is not defined` - - - - - - `nodejs_compat` 给工人一个 `process.versions.node`，所以 loader接着结束“Node”，然后开始寻找 `hb.wasm` 在文件系统上 那是不存在的。牧马人不捆绑该文件，其余的 分支从缓冲区编译WASM，嵌入器完全拒绝 （`Wasm code generation disallowed by embedder` ——也测量过)。

固定 (2) 需要 `harfbuzzjs` 接受铭文 `Module.instantiateWasm` 钩子是静态导入的 `.wasm` 可以上交。 `hb.js` 荣誉的钩子； `harfbuzzjs`输入呼叫 `hb()` 没有参数，所以没有下游包可以 供应。一个牧人 `[alias]` 不能站在两者之一中-别名 `harfbuzzjs` 重写它的子路径，所以替换不能再解析真实的 `hb.js`/`hb.wasm`.

所以修复是不需要一个文本整形器。 `@resvg/resvg-wasm` 它自己 整形，它是一个单一的静态 `.wasm` 工人们接受。卡现在是一个 SVG字符串，并且布局引擎是 `text.js` -算术超过测量的字形 进步，无处不在。

## 安装

```bash
npm install @basenative/og-image
# only if you use the satori entry point:
npm install satori
```

## 快速启动

```js
// src/worker.js — Cloudflare Worker
import { renderCard, pngHeaders } from "@basenative/og-image";

export default {
  async fetch(request, env) {
    const png = await renderCard(
      {
        title: "Northside Electrical",
        subtitle: "Electrical — Manchester, NH",
        badge: "Licensed electrician",
        brand: "northside.example.com",
      },
      env,
    );
    return new Response(png, { headers: pngHeaders() });
  },
};
```

测量于 `wrangler dev`： ~730ms的冷隔离（两个字体提取加上WASM） 加热26-45ms。

## 卡片

### `brandCard(opts) → string` (SVG)

通用实体卡：一个名称、一个限定行、一个可选的徽章和一个 品牌线钉在底部。

```js
import { brandCard, renderSvg } from "@basenative/og-image";

const svg = brandCard({
  title: "Northside Electrical",
  titleFallback: "northside",          // used if `title` has no letter or digit
  subtitle: "Electrical — Manchester, NH",
  badge: "Licensed electrician",
  brand: "northside.example.com",
  theme: { accent: "#4EAF7C" },
  width: 1200,
  height: 630,
});
const png = await renderSvg(svg, env);
```

**没有输入可以破坏布局。** 每次运行都符合宽度预算，并且 整个堆栈安装到顶部填充和品牌线之间的高度。 一个空标题，一个200字符的标题，一个没有空格的标题，RTL脚本， 标记、控制字符和单独的代理都由测试覆盖，并且 所有渲染到有效的1200x630 PNG。

值得了解的文本处理：

-   **收缩贴合，然后包裹**,最多三行，然后是省略号。
-   **柔软的优惠** 后 `-`， `/`， `_` 和 `.`,所以一个呆滞的名字在 `greenleaf-` / `landscaping` 而不是中间词。
-   **Grapheme-安全截断** -永远不会发出一个单独的代理，这将使 文档无效的XML。
-   **RTL** 集合 `direction="rtl"` 当内容主要是RTL脚本时。
-   **XML-非法字符被删除，不转义** -杂散控制 字符在数据库列中，否则会将一个坏行变成500 公共页面。

### 字体覆盖是一个真正的限制

光栅化器只绘制给定的字体缓冲区中存在的字形，和 默认是拉丁Inter。一个CJK， Devanagari或阿拉伯语标题措施和 正确布局，然后呈现为 `.notdef` 盒子。 `brandCard` 限制了 损害-它总是吸引 `brand` 行，所以牌仍然标识它的 主题-但如果你提供这些脚本，提供一个覆盖面:

```js
await renderCard(card, env, {
  fonts: { urls: { 600: "https://…/NotoSansArabic-SemiBold.ttf" } },
});
```

`titleFallback` 覆盖完全没有单词字符的名称的较窄大小写 (仅限表情符号的业务名称): 相反，将绘制回退。

### `OG_SIZE`

`{ width: 1200, height: 630 }` -高于Facebook的600x315最小值，正是 1.91:1的比例它的文件，和里面的2:1 .. 1:1窗口X需要为 `summary_large_image`.

## 字体

两个渲染路径需要两种格式，出错是无声的：

| 路径 | 格式 | 来源 | 为什么 |
| --- | --- | --- | --- |
| `renderSvg` / `renderCard` | `ttf` | `@expo-google-fonts/*` (上游Google TTFs在不可变的npm版本) | resvg的 `fontdb` 只解析原始数据。给它一个 `.woff` 和它加载 **零面不画任何东西** -一个正确大小的卡与文本丢失。 |
| `@basenative/og-image/satori` | `woff` | `@fontsource/*` | satori解压WOFF本身；文件要小5倍。 |

```js
import { defineFonts } from "@basenative/og-image";

defineFonts({
  family: "Inter",
  weights: [600, 800],
  format: "ttf",
  cdnVersion: "0.2.3",
  cacheBinding: "OG_CACHE", // KV binding name; `null` = deliberately none
  cacheKeyPrefix: "font:",
  urls: { 600: "https://…/Custom-SemiBold.ttf" }, // per-weight override
  buffers: { 600: bytes },                         // skip the network entirely
});
```

缓存键包括格式和CDN版本，因此由satori缓存的WOFF 路径永远不能服务于光栅化路径。

### 无KV缓存

字体是用 `cf: { cacheTtl: 86400, cacheEverything: true }`,所以 Cloudflare自己的边缘缓存即使在没有KV的情况下也能吸收冷隔离失误 名称空间。通过 `cacheBinding: null` 说这是故意和沉默 警告。KV:

```bash
wrangler kv namespace create OG_CACHE
```

```toml
[[kv_namespaces]]
binding = "OG_CACHE"
id = "<id>"
```

## 提供WASM模块

包解析resvg `.wasm` 本身：静态导入 牧马人/esbuild (提前编译-工人拒绝编译 从缓冲区中读取WASM)，以及在Node下读取的文件系统。如果两者都不适合你 运行时或打包器，把它交出来:

```js
import wasm from "@resvg/resvg-wasm/index_bg.wasm"; // your bundler
import { provideResvgWasm } from "@basenative/og-image";

provideResvgWasm(wasm); // WebAssembly.Module, bytes, a Response, or a promise
```

在第一次渲染之前，在模块作用域中调用它。你所提供的战胜了 内置的分辨率，然后从来没有咨询。

## 运行时检测

`detectRuntime()` 被导出，因为它的检查顺序是整个 此版本的主题:

```js
import { detectRuntime, isWorkerd, hasFilesystem } from "@basenative/og-image";

detectRuntime(); // "workerd" | "node" | "deno" | "bun" | "browser" | "unknown"
```

-   **在Node之前检查workerd**,因为 `nodejs_compat` 使it报告 `process.versions.node`.
-   **在浏览器之前检查workerd**,因为它定义了 `WorkerGlobalScope` 和 `self`。将它与真正的浏览器工作者区分开来的信号是 浏览器工作人员 _有_ 一个 `location`.

## 缓存图像本身

`pngHeaders()` 默认情况下，将响应标记为一年不可变，因为 预期的寻址方案是内容寻址的：放入卡自己的哈希值 因此，重命名主题会更改URL，并且不会留下爬虫 拿着一张陈旧的卡片。如果您的URL不是内容寻址的，请传递 `{ immutable: false }`.

## API

| 出口 | 目的 |
| --- | --- |
| `renderCard(card, env?, opts?)` | 创建一个品牌卡片并栅格化。 |
| `renderSvg(svg, env?, opts?)` | 栅格化任何SVG字符串。 |
| `brandCard(opts)` | 在不渲染的情况下构建卡片场景。 |
| `pngHeaders(opts?)` | `Content-Type` + `Cache-Control`. |
| `provideResvgWasm(source)` | 显式地提供WASM模块。 |
| `defineFonts`， `loadFontBuffers`， `loadFonts`， `fontUrl`， `fontCacheKey` | 字体。 |
| `detectRuntime`， `isWorkerd`， `hasFilesystem`， `canCompileWasmFromBytes` | 环境。 |
| `escapeXml`， `num`， `rect`， `textLine`， `textBlock`， `headline`， `clippedLine`， `svgDoc` | SVG原语，用于自定义场景。 |
| `graphemes`， `estimateWidth`， `isRtl`， `hasWordCharacter`， `truncateGraphemes`， `truncateToWidth`， `wrapToLines`， `fitText` | 文本布局。 |
| `OgImageError` | 用马槽扔 `code`. |
| `box`， `text`， `tile`， `tileGrid`， `parseGrid`， `theme`， `defaultTheme`， `el`， `defaultPreset`， `articlePreset`， `scoreCardPreset`， `presets` | satori场景DSL-仅限数据; 通过 `/satori` 条目。 |

`@basenative/og-image/satori` 另外出口 `renderPng(scene, env?, opts?)`.

## 主题

```js
brandCard({
  title: "Hello",
  theme: { bg: "#0a0a0a", fg: "#fafafa", accent: "#7c3aed", muted: "#71717a" },
});
```

令牌: `bg`， `fg`， `accent`， `muted`， `tile`， `letter`， `green`， `yellow`， `absent`， `empty`.

## 错误

`OgImageError` 带着马厩 `code`：

| 代码 | 意义 |
| --- | --- |
| `satori-unsupported-on-this-runtime` | 你打电话给工人的satori入口点。 |
| `wasm-source-unavailable` | 既不是导入映射也不是 `provideResvgWasm` 产生了一个模块。 |
| `wasm-source-invalid` | `provideResvgWasm` 被交给的东西不是一个模块，字节或 `Response`. |
| `font-fetch-failed` | CDN拒绝了，或者没有TTF知道这个家族/重量。 |
| `no-fonts` | 解析的权重列表是空的; 光栅化器什么也不画。 |

## 许可证

apache - 2.0

## 常见问题

### @basenative/og-image 是什么？

运行时无关OG /社交分享PNG渲染器- SVG卡场景栅格化的resvg-wasm，与CDN\+ kv缓存字体；运行在Cloudflare Workers、Node、Deno和Bun上

### 如何安装 @basenative/og-image？

在项目目录运行 npm install @basenative/og-image，或使用 pnpm add / yarn add / bun add。

### @basenative/og-image 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @basenative/og-image 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @basenative/og-image 可以商用吗？

@basenative/og-image 使用 Apache-2\.0 许可。宽松许可：允许商业使用、修改和再分发，并附带明确的专利授权；分发时需保留许可与 NOTICE 文件，修改过的文件要注明改动。以上为概括，不构成法律意见，请以许可原文为准。

### @basenative/og-image 还在维护吗？

最新版本 3\.0\.0 发布于 2026/10/31（2 天前）；至今共发布 11 个版本，其中过去 12 个月发布了 11 个；首次发布于 2026/10/18。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

