# 文风字体存储库

文风公开文件（网页字体包、许可原文、原件）的地址和布局，许可数据仓库的字段说明，以及收录和勘误。

# 文风字体存储库是什么

> 适合谁看：想直接读取文风公开文件（网页字体包、许可原文、字体原件）或许可数据的开发者、研究者和作者。

文风把每款字相关的公开文件放在固定地址，任何人都可以读取；许可的结构化数据另外放在一个公开的代码仓库里。这本书说明它们放在哪、怎么读。

## 两个部分

| 部分 | 在哪 | 放什么 |
|---|---|---|
| 公开文件 | `https://cn.windfonts.com/fonts-packages/{目录名}/…` | 网页字体包（CSS + woff2）、许可原文、可再分发字体的原件 |
| 许可数据仓库 | [github.com/Windfonts/font-licenses](https://github.com/Windfonts/font-licenses) | 每款字一份结构化许可信息（`license-info.json`），有原文的附许可原文 |

## 和别的网站的关系

- [app.windfonts.com](https://app.windfonts.com/fonts) 是字体库：看样张、筛选、复制网页代码，读的就是这里的文件。
- [wenfeng.org](https://wenfeng.org/) 是许可档案：许可原文、下载状态、授权证明，也以这里的文件为依据。
- 各网址的分工见[《文风的几个网址各管什么》](https://docs.cocobook.com/link/642)。

## 不是每款字都有全部文件

- 网页字体包：上架的字都有，但不是每个子集都有。
- 许可原文：有些字还没有归档原文，比如厂商只给了一个网页说明的。
- 原件：只有许可允许再分发、并且由文风托管的字才有。

所以程序里每个地址都要处理 404。

## 这本书的其他页

- [《字体的几个标识：目录名、字体名和 ID》](https://docs.cocobook.com/link/656)
- [《许可数据字段说明》](https://docs.cocobook.com/link/657)
- [《文件布局：网页字体包、许可原文和原件》](https://docs.cocobook.com/link/658)
- [《怎么查一款字有没有某个字》](https://docs.cocobook.com/link/659)
- [《收录、勘误和提交新字体》](https://docs.cocobook.com/link/660)

# 字体的几个标识：目录名、字体名和 ID

> 适合谁看：要在程序里关联同一款字的不同数据（网页、许可、接口）的开发者。

同一款字在不同地方有几种叫法。弄混了，地址就会 404、字体名就会写错。

## 目录名

目录名是一款字的短代号，例如霞鹜文楷是 `xwwk`，思源黑体是 `syhtsc`。

| 用在哪里 | 写法 |
|---|---|
| 字体页网址 `app.windfonts.com/fonts/{目录名}` | 小写 |
| 公开文件地址 `cn.windfonts.com/fonts-packages/{目录名}/…` | **小写** |
| wenfeng.org 网址 `/source/{目录名}/`、`/license/{目录名}/` | 小写 |
| 许可数据仓库的文件夹 `licenses/{目录名}/` | 首字母大写，例如 `Xwwk` |
| `license-info.json` 里的 `normalizedName` | 和仓库文件夹一致，首字母大写 |

比较目录名时请统一转成小写再比。拼文件地址时一律用小写。

## 字重名

公开文件地址里的字重目录，例如 `Regular`、`Bold`、`ExtraLight`，**大小写要和字体页一致**。个别字有自己的字重名（如 `Normal`、`Text`、`Oblique`）。

字重名和 CSS 里的 `font-weight` 数值没有固定对应关系，以 CSS 里实际写的为准。见[《在 CSS 里使用：字体名、备用字体和多字重》](https://docs.cocobook.com/link/649)。

## CSS 里的字体名

网页字体包 CSS 里声明的 `font-family` 名字格式不统一（有 `WF-`、`windfonts-`、`wenfeng-` 等开头）。不要从目录名推算，要从 CSS 里读取。

## 字体 ID

元数据接口里每款字还有一个 ID（一长串字母数字）。按单款查询时，路径里写 ID 或目录名都可以，见[《字体元数据 REST API（维护中）》](https://docs.cocobook.com/link/135)。

# 许可数据字段说明

> 适合谁看：要读取 font-licenses 仓库里结构化许可信息的开发者和研究者。

## 文件在哪

[font-licenses](https://github.com/Windfonts/font-licenses) 仓库里，每款字一个文件夹：

```
licenses/{目录名}/license-info.json   结构化许可信息
licenses/{目录名}/LICENSE             许可原文（有才放）
schemas/license-info.schema.json      字段的 JSON Schema
```

文件夹名的大小写见[《字体的几个标识：目录名、字体名和 ID》](https://docs.cocobook.com/link/656)。

## 字段

字段定义见仓库里的 `schemas/license-info.schema.json`。几乎每个条目都有 `normalizedName`、`type`、`commercial`、`verified`，其余字段视情况而定。

| 字段 | 类型 | 说明 |
|---|---|---|
| `normalizedName` | 字符串 | 目录名 |
| `type` | 字符串 | 许可档位，如「开源商用」「免费商用」，见[《许可档位与标签》](https://docs.cocobook.com/link/591) |
| `spdx` | 字符串 | SPDX 标识，如 `OFL-1.1`、`Apache-2.0`；不是标准协议的可能为空 |
| `licenseUrl` | 字符串 | 许可原文或上游发布处的网址 |
| `licenseFile` | 字符串 | 仓库里许可原文文件的路径 |
| `commercial` | 布尔 | 能否商用 |
| `modification` | 布尔 / null | 能否修改 |
| `distribution` | 布尔 / null | 能否再分发字体文件 |
| `embedding` | 布尔 / null | 能否嵌入文档或软件 |
| `webUse` | 布尔 / null | 能否用作网页字体 |
| `attribution` | 布尔 / null | 是否要求署名 |
| `shareAlike` | 布尔 / null | 衍生作品是否要用同样的许可 |
| `purchaseUrl` | 字符串 | 付费字体的购买链接 |
| `price` | 数字 | 付费字体的价格（人民币） |
| `notes` | 字符串 | 补充说明 |
| `verified` | 布尔 | 是否已人工核对 |
| `verifiedAt` | 字符串 | 核对日期 |
| `verifiedBy` | 字符串 | 依据什么核对 |
| `source` | 字符串 | 原文出处 |

## 部分条目还有的字段

| 字段 | 说明 |
|---|---|
| `licenseName` | 协议名称，如「某某体授权协议」 |
| `textState` | 原文归档状态：`full` 已归档全文，`pointer` 只记了出处链接，`missing` 还没找到原文 |
| `textSha256` | 归档原文的 SHA-256 |
| `rfn` | 保留字体名（衍生字体不能沿用的名字） |
| `mustOfficial` | 是否必须到作者或厂商官方渠道下载 |
| `uses` | 几种具体用途是否允许：`logo`、`trademark`、`video`、`doujin`（同人）、`print`、`appEmbed`（嵌入 App） |

## 读的时候注意

- **`null` 表示原文没写明或还没核对，不等于允许。** 按不允许处理，或去读原文。
- **`verified` 为 false 的条目，许可还没核对完。** 不要据此判断能否商用。
- 个别条目的 `type`、`commercial` 也可能为空，同样按「还没核对完」处理。
- 字段是对原文的归纳，有出入时**以许可原文为准**。
- 这些数据是操作参考，不构成法律意见。

## 示例

```json
{
  "normalizedName": "Xwwk",
  "type": "开源商用",
  "spdx": "OFL-1.1",
  "commercial": true,
  "modification": true,
  "distribution": true,
  "embedding": true,
  "webUse": true,
  "attribution": false,
  "shareAlike": false,
  "verified": true
}
```

（节选，省略了部分字段。）

## 接下来读什么

- [《文件布局：网页字体包、许可原文和原件》](https://docs.cocobook.com/link/658)
- 人工判断一款字能不能商用：[《这款字能不能商用：五步自查》](https://docs.cocobook.com/link/644)

# 文件布局：网页字体包、许可原文和原件

> 适合谁看：要用程序读取文风公开文件的开发者。

所有公开文件都在 `https://cn.windfonts.com/fonts-packages/{目录名}/` 下面，目录名一律小写。

## 一款字的目录

```
{目录名}/
├── {字重}/
│   ├── full/result.css        完整子集（每款字都有）
│   ├── zh/result.css          中文子集（有的字没有）
│   ├── zh-common/result.css   常用中文子集（有的字没有）
│   └── en/result.css          西文子集（有的字没有）
├── license/
│   ├── index.json             许可原文清单
│   └── original.txt           许可原文（有才放）
└── source/
    ├── index.json             原件清单
    └── …                      字体原件（许可允许再分发、并由文风托管的才有）
```

目录本身不能列出文件，请按清单里的文件名去取。

## 网页字体包

`result.css` 里是一组 `@font-face`，每条用 `unicode-range` 指向同目录下的一个 woff2 分片。用法见[《网页字体地址规则》](https://docs.cocobook.com/link/648)。

## license/index.json

```json
{
  "norm": "Xwwk",
  "kind": "license",
  "updated": "2026-10-04T21:07:15+08:00",
  "items": [
    {
      "role": "original",
      "primary": true,
      "file": "original.txt",
      "media": "text/plain; charset=utf-8",
      "bytes": 5171,
      "sha256": "…",
      "sourceUrl": "https://raw.githubusercontent.com/lxgw/LxgwWenKai/main/OFL.txt",
      "sourceName": "OFL.txt"
    }
  ]
}
```

| 字段 | 说明 |
|---|---|
| `items[].file` | 文件名，拼在 `license/` 后面就是地址 |
| `items[].primary` | 是否主文件 |
| `items[].sha256` | 文件的 SHA-256 |
| `items[].sourceUrl` | 这份原文从哪里取的 |

## source/index.json

```json
{
  "norm": "xwwk",
  "kind": "source",
  "items": [
    {
      "file": "LXGWWenKai-Regular.ttf",
      "url": "https://cn.windfonts.com/fonts-packages/xwwk/source/LXGWWenKai-Regular.ttf",
      "bytes": 25575676,
      "sha256": "…",
      "status": "本站下载"
    }
  ]
}
```

`status` 的用词和 wenfeng.org 的下载状态一致，见[《下载原件和切片：什么能下、怎么用》](https://docs.cocobook.com/link/645)。

## 注意

- 清单里的 `norm` 大小写可能和网址不一样，拼地址时一律用小写目录名。
- 任何一个文件都可能 404（没有这个子集、还没归档原文、不允许再分发），程序要处理。
- 下载原件后用 `sha256` 核对，见[《下载字体怎么避开山寨包和钓鱼站》](https://docs.cocobook.com/link/621)。
- 批量下载前请先确认许可允许再分发；只想用网页字体就不用下原件。

# 怎么查一款字有没有某个字

> 适合谁看：要确认一段文字（人名、地名、繁体、生僻字）能不能用某款字完整显示的用户和开发者。

## 不写代码：字体页查字

打开字体页，在「字符表 · 查字」里输入你要用的文字。字体里没有的字会用虚线框标出来。

## 写代码：读 CSS 的 unicode-range

网页字体包 CSS 里每条 `@font-face` 都有 `unicode-range`，列出这一片包含哪些字的编码。**把一份 `result.css` 里所有 `unicode-range` 合在一起，就是这一子集能显示的全部字符。** 不在里面的字，浏览器会用备用字体显示。

下面是一个 Python 示例，检查一段文字在某款字的 `full` 子集里缺哪些字：

```python
import re, urllib.request

def covered(css_url):
    req = urllib.request.Request(css_url, headers={"User-Agent": "Mozilla/5.0 (coverage-check)"})
    css = urllib.request.urlopen(req, timeout=30).read().decode("utf-8")
    cps = set()
    for rng in re.findall(r"unicode-range:([^;}]+)", css):
        for part in rng.split(","):
            part = part.strip().upper().removeprefix("U+")
            if "-" in part:
                a, b = part.split("-")
                cps.update(range(int(a, 16), int(b, 16) + 1))
            elif part:
                cps.add(int(part, 16))
    return cps

url = "https://cn.windfonts.com/fonts-packages/xwwk/Regular/full/result.css"
text = "你要检查的文字"
have = covered(url)
print("缺字：", "".join(ch for ch in set(text) if ord(ch) not in have and not ch.isspace()))
```

要点：

- 请求时带上常见的 `User-Agent`，不带可能被拒绝（返回 403）。

- 查 `full` 子集，结果就是整款字的覆盖；查 `zh-common` 等子集，结果只代表那个子集。
- 不同字重的覆盖可能不同，用到哪个字重就查哪个。
- 地址规则见[《网页字体地址规则》](https://docs.cocobook.com/link/648)。

## 缺字怎么办

- 换一款覆盖更全的字，或在 CSS 里写好备用字体。见[《繁体、日文、生僻字显示成方框怎么办》](https://docs.cocobook.com/link/626)。
- 字体缺字是字体本身的情况，文风不会替作者补字。

# 收录、勘误和提交新字体

> 适合谁看：想推荐文风收录某款字的用户，想上架自己作品的字体作者，以及发现许可信息有误的人。

## 文风收哪些字

wenfeng.org 写明了三道门槛，有一项过不去就不收录：

1. **能取得完整许可原文。** 发布包里的许可文件、官网许可页、官方仓库的 LICENSE，至少其一。
2. **能对应到著作权人或发布厂商。** 不收出处不明的转载包。
3. **字体文件来自作者或厂商公布的渠道。** 不收来路不明的打包文件。

许可还在核对的，目录里标「待核实」，核对完成前不提供文件、也不出证明。详见 [我们怎么核验](https://wenfeng.org/how)，以及[《一款字体怎么收录上线》](https://docs.cocobook.com/link/593)。

## 推荐一款字

写信到 license@wenfeng.org，写上：

- 字体名（中英文）
- 作者或厂商
- 官方发布地址（作者仓库、官网下载页）
- 许可原文的地址

WordPress 用户也可以看[《提交新的中文字体》](https://docs.cocobook.com/link/52)。

## 字体作者想上架自己的字

同样写信到 license@wenfeng.org，附上：

- 官方发布地址和许可原文
- 能证明你是作者或权利人的材料（例如发布仓库、官网）

用开源协议（如 OFL）发布的字更容易收录：许可原文完整，网页字体和再分发的范围也清楚。

## 许可、作者、出处写错了

写信到 license@wenfeng.org，写清字体页或许可页的网址、哪里写错了、正确的依据（最好是许可原文链接）。你是权利人并对某个条目有异议的，请附上权利证明。

核实期间该条目会标为「待核实」，暂停出证、也不提供文件；确认有误就更正或下架。

## 文档写错了

写信到 docs@windfonts.com，写清页面标题和错误的地方。

## 接下来读什么

- [《缺字、报错和勘误怎么反馈》](https://docs.cocobook.com/link/646)
- [《许可数据字段说明》](https://docs.cocobook.com/link/657)