章 1 · 为什么选择Postext
书刊排版, 为Web计算
印刷排版用了五个世纪学会怎样排一页,浏览器学会的是怎样布局一个界面。Postext把前者带给后者。
CSS提供响应式布局:flexbox、grid、多栏。但它不能让各栏齐底,不能让标题和它的段落排在一起,不能避免段首孤行和段末孤行,也不能把图浮动到下一栏的栏首。这些是编辑层面的决定,经过几个世纪的印刷实践才打磨成型。
Postext填补了这个空缺。给它语义化的Markdown和一个配置对象,它借助@chenglou/pretext测量文字,速度比DOM快300–600倍;然后计算出完整的页面几何——每一行、每个浮动体和每条题注——再通过HTML、Canvas或可直接付印的PDF后端渲染出来。
输入Markdown
:::part{number="I" title="基础"
palette="band=#2b4acb"}
:::
# 为什么需要Postext {lead="印刷排版
用了五个世纪……"}
Postext是一个**开源排版引擎**,
把印刷排版的手艺带到网页上,
如:ref{id="fig-flow"}所示。
:::callout{type="try"}
改一个词,页面就会重新排版。
:::输出页面
数字一览
- 文字测量比DOM快这么多倍,所以整本书随着输入实时重排
- 300–600×文字测量比DOM快这么多倍,所以整本书随着输入实时重排
- 个渲染器共用一个版面:HTML、Canvas和可直接付印的PDF
- 3个渲染器共用一个版面:HTML、Canvas和可直接付印的PDF
- 带标签的无障碍PDF输出,含书签和CMYK颜色
- PDF/UA带标签的无障碍PDF输出,含书签和CMYK颜色
- 台服务器:引擎完全在浏览器中运行,采用MIT许可证
- 0台服务器:引擎完全在浏览器中运行,采用MIT许可证
章 2 · 功能
印刷排版师早就懂得的事
页面需要、而CSS从未打算替你决定的六件事,由引擎计算,每次结果都一样。
- 2.1
Knuth-Plass两端对齐
与TeX相同的最优断行算法,配合TeX模式断词和孤行控制——排出疏密均匀的文字块,没有空白“河流”,这是CSS无法表达的。
在文档中阅读 - 2.2
资源与交叉引用
图、SVG图示和表按印刷浮动体的方式浮动到栏或页面的顶部或底部,带按类型编号和始终保持同步的:ref交叉引用。
在文档中阅读 - 2.3
表与题注
表的表体和表头可以分别设置排版样式,可以跨页拆分并重复表头;题注遵循你的配置,编号并放在所描述的资源旁边。
在文档中阅读 - 2.4
单色图示
按明度把SVG图示重新着色为同一种油墨的不同色调,让每幅插图都与你的设计一致,可直接用于专色印刷。
在文档中阅读 - 2.5
LaTeX数学公式
用LaTeX写行内公式和独立公式,由引擎测量并排版,与正文一起落在基线网格上。
在文档中阅读 - 2.6
Web与可直接付印的PDF
一个排版引擎,三个渲染器。同一组计算好的页面可以渲染为HTML、Canvas或可直接付印的PDF,支持书签、CMYK颜色,以及带标签的无障碍PDF/UA输出。
在文档中阅读
Postext指南的每一页——封面、目录、篇章分隔页,全部都算上——都在你阅读时由Postext在你的浏览器中排出。
作品展示
真正的书,在你的浏览器中排版
一本教材、一本杂志、一部文学作品、一本展览图录、一部120回的中文古典小说。任选一本在沙盒中打开,改一条规则,看每一页随之重排。
章 3 · 工作流程
三步得到出版级版面
内容写在Markdown里,设计写在配置对象里,调用一个函数就得到页面。
- 3.1
编写语义化Markdown
用增强Markdown撰写内容:标题、列表、表格、数学公式、标注框,以及指向图的:ref交叉引用。不用操心版面,只管内容。
- 3.2
配置排版规则
在PostextConfig对象中定义页面尺寸、分栏、字体排印、标题设计、书眉和浮动体位置——也可以在沙盒中可视化地设计。
- 3.3
渲染为HTML、Canvas或PDF
调用buildDocument,得到完整的版面几何,再用HTML、Canvas或可直接付印的PDF后端渲染。
API
一个函数,完全掌控
用你的内容和一个配置对象调用buildDocument,得到完整的页面几何:用renderPage把任意一页绘制成图片,或用renderToPdf把整本书排成可直接付印的PDF。
import { buildDocument, renderPage } from "postext";
import { renderToPdf } from "postext-pdf";
const doc = buildDocument(
{ markdown },
{
page: { sizePreset: "21x28" },
layout: { layoutType: "double" },
bodyText: {
fontSize: { value: 12, unit: "pt" },
textAlign: "justify",
hyphenation: { enabled: true, locale: "en-us" },
},
}
);
// 每一页都绘制成图片…
const cover = renderPage(doc.pages[0], doc);
cover.toBlob((png) => save(png, "cover.png"));
// …或把整本书输出为可直接付印的PDF
// fontProvider:按字族和字重提供TTF字节(参见文档)
const pdf = await renderToPdf(doc, { fontProvider });章 4 · 开放格式
一个文件,整本书
.postext文件包含了文档在任何机器上重新排版所需的一切:一种开放、可编辑、任何人都能采用的格式。
多数出版格式会把一个项目拆得七零八落。LaTeX的构建依赖某一台机器上安装的字体和宏包,主流排版软件的原生文件链接着存放在文件之外的图片和字体。项目一挪地方,就会缺东西。我们自己用LaTeX时就碰到过这些限制。
.postext就是一个普通的ZIP压缩包,任何人都能打开、阅读和编辑:一个JSON清单、每章一个Markdown文件,以及字体文件和图片本身。沙盒可以导出它,postext-port代理技能可以写出它,postext/bundle可以在任何程序中打开它,重新排出同样的页面。这种格式有完整的文档,采用MIT许可证,任何工具都可以读写。
- 4.1
preset.json配置. 页面、网格、字体、标题和段落样式、颜色和书眉,都是可读的JSON。
- 4.2
chapters/<lang>/*.md章. 每章一个Markdown文件:这里有12章,共2种语言。
- 4.3
fonts/*.woff2字体. 字体文件本身,而不只是字体名称:Lora、Fraunces、Geist和Bricolage Grotesque的18个文件。
- 4.4
preset.json › resources资源. 正文引用的22个图和表的题注、编号、位置和表格内容。
- 4.5
resources/*.svg图片. 图稿本身,SVG或位图,包括每种语言的版本:32个文件。
试试看
打开指南,得到它的页面
沙盒的第一个示例,即Postext指南,就是一个.postext文件。在浏览器中打开它,把每一页都变成图片:它的字体、图和表都来自这个文件本身。
下载指南postext-guide.postext · 496 KBimport { openBundle, loadBundleFonts, registerBundleImages,
buildBundle, renderPageToCanvas } from "postext";
// 沙盒中的指南:配置、各章、字体和图片
const file = await fetch("postext-guide.postext").then((r) => r.blob());
const book = await openBundle(file, { locale: "en" });
await loadBundleFonts(book); // 它自带的字体
await registerBundleImages(book); // 它自带的图
// 每一章的每一页,都绘制成图片
for (const doc of buildBundle(book))
for (const page of doc.pages) {
const canvas = document.createElement("canvas");
renderPageToCanvas(page, doc, canvas, { scale: 0.5 });
document.body.append(canvas);
}// 快速开始
import { buildDocument, renderPage } from "postext";
import { renderToPdf } from "postext-pdf";
const doc = buildDocument({
markdown: "# Hello World\n\nYour content here.",
});
// 第一页,绘制在Canvas上
document.body.append(renderPage(doc.pages[0], doc));
// 整个文档输出为PDF
const pdf = await renderToPdf(doc, { fontProvider });