广告 《大道至简,给所有人看的编程课》 🔥

《技术图书排版》

杜金房

3 我在 Mac 上的写作工具链

杜金房/2015.08.13/来自 FreeSWITCH-CN 公众号

有读者问我在写书时是如何画插图又如何生成 PDF 的,今天,就跟大家分享一下。

先讲个故事。

大约 09 年底 10 年初的时候,我就想写点关于 FreeSWITCH 的东西,也希望最后能汇集成书。因此,我从最开始就研究怎么排版。

最开始,是从第二章写起的。当时直接使用 Textmate 写,使用 Latex 语法,用 PdfLatex 转成 PDF。事实证明,写的很痛苦。因为,跟那些写小说的人不同,我的书中有好多代码。大段的代码还好说,直接嵌入段落中的代码就比较麻烦,必须用一堆$$括起来,而且,如果代码中有$就得用\$转义。不幸的是,我最开始写的那一章中有很多的$

后来,发现写书是很遥远的事,就开始把内容放到我的博客上。博客是自己建的,使用简单的 Markdown 格式。Markdown 写起来很方便,而且兼容 HTML,一切都好。

但我一直忘不了寻求如何生成 PDF 的方案。也尝试过 RestructuredText 等方案,但都不完美。

再后来,一个自称是 Tim Yang 的网友鼓励我把书印出来。排版的事就又提上了日程。由于我时间不多,一个老朋友答应帮忙。后来,还真让她整理出了一个 Word 版。但是,问题是 Word 版里有很多地方需要改,而修改 Word 版,不仅是很累的活,而且,无法同步回 Markdown,并且我也不怎么喜欢(极其讨厌)Word。所以,我只好把那么精心打造的 Word 版给废了。再次寻找从 Markdown 生成 PDF 的方案。很幸运,我找到了 Pandoc。

Pandoc 是用 Haskell 编写的软件,能从各种文件格式中互转。比较典型的就是从 Markdown 转成 PDF、HTML 和 Word。

当然,它还是先将 Markdown 转成 Latex,再从 Latex 转成 PDF。通过精心调校以及一些 Shell 脚本的帮助(用于调整 Latex),终于能生成比较美观的 PDF 了。书也印了出来,名为《FreeSWITCH:VoIP 实战》。在第一届 FreeSWITCH 沙龙上卖出去几本,后来又间或有人来买,书也一直在更新。

但,PDF 比较美观,跟完美还差一个数量级。所以,我也一直在改进。当然,在过去的几年里,Pandoc 也一直在升级。

后来,我从 PdfLatex 转成了 XeLatex,效果要好很多(具体差别细节不记得了)。我的书中有很多脚注,写起来非常方便。而且,在使用中,我也慢慢学会了如何通过在 Markdown 中适当地嵌入一些 Latex 标记来做交叉链接。现在,除了还有下列两个问题外,已经几近完美了。

1)我还没有搞定字体(我希望某些引用使用楷体,不知道为什么使用楷体后有些副作用),好在我可以通过改变字号变相的区别。

2)图文混排控制力较弱。如果不在 Markdown 中增加 Latex 标记(我不想增加),就只能实现简单的图文混排,即图片永远占一行,而无法使用文字环绕。这种情况的一个最大问题就是一个竖版的图片,往往会占一整页。如果不想让它占一整页,只好修改图片,用白色或无色背景加宽。好在我会点 PS。

同样的 Markdown 也可以生成 ePub 格式,从 ePub 可以继续生成 Kindle 格式。这两种格式与 PDF 格式比起来,还不是很完美(因为 PDF 有 Latex 帮助,而 ePub 版不能利用 Latex 标签,如果需要更好的 ePub,需要一些相关的插件才行),但是,一般来说也够用了,在移动设备上有比较好的阅读体验。

不过,即使你的 Latex 和 PDF 再精美,出版社也不会用的。后来,出书的时机成熟后我发现,我的出版社只接受 Word 格式的稿子。他们说中国的环境不足以养一个会 Latex 的编辑。另外,Word 的修改和批注功能确实没有什么很好的替代品。我虽然跟他们说『我们可以使用 Git 啊』,但他们只是笑笑。其实我自己也知道,Git 是基于行的,不适合 diff 大段的文本(更别提中文单词和标点之间没有空格了)。

所以,我只好将我的 Markdown 通过 Pandoc 转成 Word 格式。再跟编辑们一遍遍地校对和修改。当然,这些修改就只存在于 Word 版了。除非手工同步修改 Markdown,不可能再从 Word 版转回原来的 Markdown。好在,书出版以后,我不需要再继续打印了。因此,也没有必要再保持 Markdown 跟最终的版本同步。而且,出版社给出了一个 Word 模版,通过使用一些快捷键,可以很方便地格式化一级标题二级标题以及代码块等,手工按这些快捷键处理一章也基本上就是几分钟的事(Pandoc 似乎也支持模板,但我没有试过,因为反正在编辑的时候还是要再次阅读和修改的)。

书于去年 6 月出版,出版时的名字叫《FreeSWITCH 权威指南》。

后来,在读了《Producter》一书(电子书)后,我也深受启发,在 SelfStore 上发了几本我的电子书《FreeSWITCH 互联互通》、《FreeSWITCH 实例解析》等。

当然,如果我今天只讲故事,没有干货的话,你可能觉得我是在做广告了。所以,接下来干货。

在写书时,要有很多的插图。据说 Mac 上最好的画图工具是 OmniGraffle,然而,我始终没有冲动试用它。而是尝试了很多不同的软件:Skitch、Dia、yEd、XMind、Keynote 等。这些软件的问题是画得不好看,而且风格不统一。所以,最后,我又回到了程序员神器——Graphviz。

通过 Graphviz,可以使用很简单的 dot 语言画出很复杂的图,比如今天的题图,对应的 dot 源文件如下(虽然长,但很直观):

graph G {
    ranksep = 3;
    ratio = auto;

    A [label = ""];
    B [label = ""];
    C [label = ""];
    D [label = ""];
    E [label = ""];
    F [label = ""];
    G [label = ""];
    H [label = ""];
    I [label = ""];
    J [label = ""];

    A -- B;
    A -- C;
    A -- D;
    A -- E;
    A -- F;
    A -- G;
    A -- H;
    A -- I;
    A -- J;
    B -- C;
    B -- D;
    B -- E;
    B -- F;
    B -- G;
    B -- H;
    B -- I;
    B -- J;
    C -- D;
    C -- E;
    C -- F;
    C -- G;
    C -- H;
    C -- I;
    C -- J;
    D -- E;
    D -- F;
    D -- G;
    D -- H;
    D -- I;
    D -- J;
    E -- F;
    E -- G;
    E -- H;
    E -- I;
    E -- J;
    F -- G;
    F -- H;
    F -- I;
    F -- J;
    G -- H;
    G -- I;
    G -- J;
    H -- I;
    H -- J;
    I -- J;
}

又比如下图:

源文件加上空行也只有 22 行(为了在手机上减少换行,取消了缩进):

digraph G {
splines = false;

S [label="源代码" shape = "box"];
SCAN [label = "configure.scan" shape = "box"];
IN [label = "configure.ac" shape = "box"];
ACLOCAL [label = "aclocal.m4" shape = "box"];
configure [shape = "box"];
MakefileAm [label = "Makefile.am" shape = "box"];
MakefileIn [label = "Makefile.in" shape = "box"];

S->SCAN [label = "autoscan"];
SCAN -> IN [label = "改名,编辑"];
IN -> ACLOCAL [ label = "aclocal"];
ACLOCAL -> configure [ label = "autoconf"];
IN -> configure [ label = "autoconf"];
MakefileAm -> MakefileIn;
IN -> MakefileIn [ label = "automake"];

MakefileIn -> Makefile;
configure -> Makefile [label = "./configure"];
}

而所有的 dot 文件,只是靠一个简单的 Makefile 和一个make命令就会部都转成 PNG 图片了。同时,dot 文件还可以存在 Git 仓库里。

谁能告诉我,像下面这样的图(如图)用 OmniGraffle 或 Windows 上的 Visio 画累不累呢?

FreeSWITCH模块结构
图4-1: FreeSWITCH模块结构

当然,并不是所有插图都适合用 Graphviz。所以,除此之外,我还使用 Keynote。Keynote 比较适合画这样的图(是的,Internet 也是我用弧线画出来的,如图):

用Keynote画的NAT示意图
图4-2: 用Keynote画的NAT示意图

还有一个问题。那就是,以上工具都不适合画时序图。因此,我不得不又搜遍互联网,找到一个类似 Graphviz 的工具——mscgen。是的,跟我期望的一样,它可以使用类似 dot 的语法画时序图,大概就是下面这个样子,如图:

SIP信令时序图
图4-3: SIP信令时序图

搞过通信的人应该对上面那种图都非常熟悉。当然 mscgen 在 Mac 上生成图时对中文的处理有点问题。我只好首先用 mscgen 生成 svg,然后又用 Inksape 将 svg 转换成 PNG。

你还在用 Word 写 API 文档和产品说明文档吗?反正我们已经全部是 Markdown 了。虽然 Word 也可以进行『文件比较』,但怎么也不如git diff来得顺手吧?

好了。这基本上就是全部的秘密了。如果大家感兴趣,我以后也可以跟大家分享一些相关的脚本和源文件。程序员万岁。



版权所有 © 杜金房 2014-2023,仅供在线阅读,谢绝一切形式转载。 | 回首页 |