2009 年度总结

* 年度电影:[Up](http://www.imdb.com/title/tt1049413/)
* 年度游戏:[Uncharted 2: Among Thieves](http://en.wikipedia.org/wiki/Uncharted_2)
* 年度小说:[大江东去](http://www.douban.com/subject/3432304/)
* 年度电子产品:[PlayStation 3](http://en.wikipedia.org/wiki/PlayStation_3)
* 年度网络应用:[twitter](http://twitter.com)

下面是我自己参与的:

* 年度软件项目:[Textus](http://www.jjgod.org/projects/textus)
* 年度翻译作品:[Objectified](http://www.objectifiedfilm.com/) [中文字幕](http://jjgod-documentation-project.googlecode.com/svn/trunk/Objectified.chs.srt)

homebrew — Mac OS X 下新的软件包管理工具

虽然 Mac OS X 自带了不少 Unix 下的开源软件,比如 vim, ruby, python, perl 等等,也自带了许多常用的库,包括 iconv, zlib 等等,但我们仍然有时会需要自己动手安装一些这样的软件或者库,要自动化这样的安装,现有最常见的选择是 [MacPorts][macports] 和 [Fink][fink],其中 MacPorts 是基于源代码的包管理,并不在自己的库里储存软件的实际内容,只有一个定义如何编译代码的 [Portfile][portfile] 和一些专门针对这个平台的 patch;而 Fink 则是 [Apt][apt] 包管理系统在 Mac OS X 下的一个克隆,采用二进制分发,用户直接从 Fink 的仓库中下载安装软件。

[macports]: http://www.macports.org
[fink]: http://www.finkproject.org
[portfile]: http://guide.macports.org/chunked/development.html
[apt]: http://en.wikipedia.org/wiki/Advanced_Packaging_Tool

这两种方式各自有各自的优点和缺陷:

MacPorts 基于源代码的管理优点是非常灵活,更新很快 (很多时候更新只需要修改一下 Portfile 里的版本号和压缩包校验码就可以),用户要订制安装也可以简单的通过修改 Portfile 实现,而且很多开源软件的安装配置会有多种模式 (典型的大都通过 `configure` 步骤配置),在 MacPorts 中可以方便地通过 `variants` 参数指定,而不必像二进制分发那样,在远程服务器上编译的时候就定死了。而 MacPorts 的问题是,它希望自己安装的每套软件,所有的依赖都在它自己这个系统内 (一般就是你的 `/opt/local`) 解决,就算 Mac OS X 系统原生自带了满足依赖的库,它也坚决不用,这样就给你的系统增加了许多冗余,也客观增加了管理上的难度,典型的情况是:你的系统里装了两套 Python,该怎么管理外部安装的 Python 模块?比如通过 `easy_install` 或 `setup.py` 安装的,往往很难记住到底装到哪里了。

而 Fink 虽然不会这么自作主张地添加依赖,最大的问题是更新不够及时,这也是缺乏维护人手导致的。二进制安装的缺点在上面也提到了:不便定制。

所以 [Homebrew](http://github.com/mxcl/homebrew) 的出现,也许不是很及时,但在现在仍然是很必要的,它有这么一些优点:

1. 尽可能的利用你的系统里自带的库,包括 zlib, OpenSSL, Python 等等,只要 Mac OS X 自带了,它就不会另装一份。

2. 定制简单,通过用 Ruby 写的 Homebrew formula 来定制,甚至可以灵活的跟踪直接来自版本管理库的最新软件

3. 用 Git 管理和同步自身

4. 直接装在 `/usr/local` 下,这样可以少定义很多各种 `PATH` 环境变量

其中第一点尤为重要。好的,下面简单介绍一下 Homebrew 的安装,以及它是如何工作的。

#### 安装

首先,Homebrew 的原则是“No sudo”,也就是说,既然 Mac OS X (client 版本) 绝大部分情况下都是归你这个有管理员权限的用户,为什么在自己的 `/usr/local` 下安装程序还需要 `sudo` 呢?所以,首先:

sudo chown -R `whoami` /usr/local

然后可以正式开始安装,我推荐的安装方式是先用 [git-osx-installer](http://code.google.com/p/git-osx-installer/) 装上 git,然后用 git 安装:

cd /usr/local
git init
git remote add origin git://github.com/mxcl/homebrew.git
git pull origin master

这么做的实际作用是把你的 `/usr/local` 目录变成了一个本地 git 仓库,只不过这个仓库只跟踪跟 Homebrew 相关的更新,并不影响任何其他软件的安装。

这样安装会在 `/usr/local` 下创建 `Library` 这个目录,然后在 `/usr/local/bin` 中加入 `brew` 这个 ruby 脚本。

#### 使用

安装完毕,下面就可以试试了:

brew search

这个命令用来搜索所有可以通过 homebrew 安装的软件,不带任何参数的时候就是列出所有的。可以看到数量已经不少了。

下面就是选择安装,比如我想安装 unrar:

$ brew search rar
gnu-scientific-library unrar

$ brew install unrar
Warning: It appears you have Macports or Fink installed
Although, unlikely, this can break builds or cause obscure runtime issues.
If you experience problems try uninstalling these tools.
/usr/local/Library/Formula/unrar.rb:3: warning: already initialized constant ALL_CPP
==> Downloading http://www.rarlab.com/rar/unrarsrc-3.9.4.tar.gz
######################################################################## 100.0%
==> g++ -O4 -march=core2 -mmmx -msse3 -w -pipe -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE all.cpp -o unrar
/usr/local/Cellar/unrar/3.9.4: 3 files, 320K, built in 13 seconds

可以看到,unrar 被安装到了 `/usr/local/Cellar/unrar/3.9.4` 这个目录下,但这样我们访问起来显然很不方便,所以 Homebrew 会在 `/usr/local/bin` 下面创建到 `unrar` 程序的符号链接,如果安装的是库之类的,也会对应在 `/usr/local/lib` 这样的目录下创建符号链接。所以这是一套类似 [GoboLinux](http://www.gobolinux.org/) 的软件管理方式。

安装后就可以用 `list` 命令列出:

$ brew list
pkg-config unrar

#### 更新

如果用了一段时间,需要更新同步上游的 Formula,可以简单地:

$ brew update
From git://github.com/mxcl/homebrew
* branch master -> FETCH_HEAD
Updated Homebrew from 60600885 to 60600885.
No formulae were updated.

Homebrew 会通过 git 完成同步。

总结起来,Homebrew 是一套很有新意的软件包管理工具,虽然它的更新及时程度还有待考验,但至少在目前还是比较令我满意的解决方案。

TeX Live 2009 的 LaTeX 中文支持

最近刚发布的 [TeX Live 2009](http://www.tug.org/texlive/) 是对中文支持有较大改进的一个版本,这里简单介绍一下。

首先,一如 2007, 2008 版本,TeX Live 2009 有中文版本的[安装使用指南](http://www.tug.org/texlive/doc/texlive-zh-cn/texlive-zh-cn.pdf),强烈建议在提问前把相关章节好好看看,这份指南主要叙述的是和中文无关的一些通用的问题。

然后 TeX Live 2009 的中文支持主要分为两部分,基于 XeTeX 的,和基于传统 CJK 宏包的。(我这里只讨论 LaTeX 的,如果你希望尝试 ConTeXt 和 luatex,可以参考 Li Yanrui 的 [blog](http://liyanrui.is-programmer.com/),他有很详细的介绍。)

#### 基于 XeTeX 的方案

这是我们推荐的方案,又可分为高层与低层两种,分别适用于不同需求的用户。

首先,安装所需的宏包:

sudo tlmgr install xecjk ctex

高层的方案是使用 ctex 宏包自带的文档类,例如原来用 article 文档类的就改用 ctexart 文档类,原来用 book 文档类的就改用 ctexbook 文档类,这样绝大部分你会遇到的中文问题,比如字体设置、hyperref 的调用、章节标题的设置等等,都自动为你解决了。详情可以看 ctex 宏包的[文档](http://tug.ctan.org/tex-archive/language/chinese/ctex/doc/ctex.pdf)。下面是一个小例子:

\documentclass{ctexart}
\begin{document}
你好,TeX Live 2009!
\end{document}

默认情况 (winfonts) 下,你需要宋体 (SimSun)、仿宋 (simfang)、黑体 (simhei)、楷体 (simkai)、隶书 (LiSu)、幼圆 (YouYuan) 这六套 Windows 字体,如果你的字体不全,可以编辑 `ctex-xecjk-winfonts.def` 文件 (用 `kpsewhich` 来找) 来修改设置,也可以选择 Adobe Reader 等软件所带的 Adobe Song Std, Adobe Heiti Std, Adobe Kaiti Std, Adobe Fangsong Std 四款字体,这时需要给 ctexart 加上 `[adobefonts]` 选项。又或者,你可以不用这些预置的字体,使用 `[nofonts]` 选项,然后参考 `ctex-xecjk-winfonts.def` 文件,自己定义对应各个 CJK 字体族的字体。

低层的方案则是用原来你自己的宏包,结合 xeCJK 宏包来配置字体,下面是一个小例子:

\documentclass{article}
\usepackage{xeCJK}
\setCJKmainfont{SimSun}
\begin{document}
你好,TeX Live 2009!
\end{document}

当然,你得有 SimSun 这个字体。

不管选用高层的还是低层的,都可以直接用 `xelatex` 命令直接编译你的文档。

#### 传统 CJK 方案

传统 CJK 方案主要是为了方便使用以前的文档存在的。也分为两种,高层方案也是使用 ctex 宏包,低层方案和原来的文档一样,直接用 CJK 宏包。

使用 ctex 宏包的例子和前面用 ctexart 的那个完全一样:

\documentclass{ctexart}
\begin{document}
你好,TeX Live 2009!
\end{document}

不过需要注意的是,你还得安装 `zhmetrics` 宏包。另外,如果文档保存的编码是 GBK,必须添加 `[GBK]` 选项,否则用 UTF-8 编码的也建议用 `[UTF8]` 选项。

可以看出,用高层方案最大的好处是文档代码可以最大限度地不修改就能换用不同的 TeX 引擎。

低层方案与原来的做法的区别是,需要载入 zhwinfonts,使用 zhwinfonts 定义的字体,而不是原来自己去生成字体的映射文件,这样要简便很多:

\documentclass{article}
\usepackage{CJK}
\input zhwinfonts
\begin{document}
\begin{CJK}{GBK}{zhsong}
你好,TeX Live 2009!
\end{CJK}
\end{document}

注意,这里用了 `zhsong` 这个字体族而不是 `song`,为了避免和 CJK 宏包原来定义的冲突,我们定义的所有字体族都带 `zh` 前缀。

对于上述这两种情况,你都可以使用 `latex` 编译,用 `dvipdfmx` 生成 pdf。

除了上述的 `zhmetrics`, `ctex`, `xeCJK` 宏包以外,我们还在 CTAN/TeX Live 中提交了 `zhspacing`, `CJKpunct`, `zh-luatex` 等宏包,`ctex-faq`, lshort 中文翻译等文档,以上工作都需要感谢参与维护 [ctex-kit](http://code.google.com/p/ctex-kit) 的全体开发者,为 [ctex-doc](http://code.google.com/p/ctex-doc) 贡献内容的全体作者,也欢迎你参加到我们的工作中来,帮助进一步改进 TeX 的中文支持。

闲聊文本渲染技术的近期发展

在今年 7 月的 [GUADEC](http://www.grancanariadesktopsummit.org/) 上 Behdad Esfahbod 做了一个题为 [State of Text Rendering](http://behdad.org/text/) 的讲座,系统地综述了当前文本渲染技术的现状,顺带强调主要由他开发的 [harfbuzz-ng](http://www.freedesktop.org/wiki/Software/HarfBuzz) 是未来发展的方向,4 个月过去了,最近文本渲染技术有了什么发展呢?这里谈谈我的一些印象和见解。

首先,harfbuzz-ng 到底想做成什么样子?我们知道底层的字体格式支持,开放的有 [FreeType](http://www.freetype.org) 一枝独秀,各平台私有的有 Win32 的 GDI font, Mac OS X 有 ATS 和 [CGFont](http://developer.apple.com/mac/library/documentation/GraphicsImaging/Reference/CGFont/Reference/reference.html),上层的文本布局排版引擎,现在各家自有一套到两套:Windows 的 [DirectWrite](http://en.wikipedia.org/wiki/DirectWrite) 和 Uniscribe;Mac OS X 有 Core Text 和 ATSUI,有 [NSLayoutManager](http://developer.apple.com/mac/library/DOCUMENTATION/Cocoa/Reference/ApplicationKit/Classes/NSLayoutManager_Class/Reference/Reference.html);GTK+ 有 [pango](http://www.pango.org/),都是比较成熟的接口了,那 harfbuzz-ng 是要取代他们吗?

不是,也完全说不通,毕竟 pango 就是 Behdad Esfahbod 自己维护的,没理由拆自己的台。但是开放的 pango 等平台一直缺失的部分是 OpenType 复杂排版特性的支持,这一点 FreeType 没来得及解决,也因为和排版引擎关系太紧密,所以没法完全靠 FreeType 这种“字体格式解析库”来解决。harfbuzz-ng 要做的,正是在原来的 FreeType OpenType 排版代码的基础上,构建一个类似 [ICU LayoutEngine](http://userguide.icu-project.org/layoutengine) 的、有简洁的 C API 的、支持 OpenType 特性的,而且还要比 pango 底层一些的库。

那不是和 ICU 重合了吗?ICU 一来是 C++ 的 API 用着比较累,而来确实也比较笨重,移植的时候够受的。ICU 虽然在近期版本里也开始提供 C 的排版引擎 API,但也只是试验性的。

所以总的看起来,Linux 下的文本渲染层次还真是够多的:GTK+ → pango/[cairo](http://cairographics.org) → harfbuzz-ng → FreeType,同时 harfbuzz-ng 还可能用到 ICU, [Graphite](http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&cat_id=RenderingGraphite),在 Mac OS X 上还要用到 Core Text 和 Core Graphics。

细分层带来的好处就是不同的需求可以选择合适的 API 来实现:比如你要在图形界面上显示一段文字,就用 GTK+ 的 label;要绘制小段的文本,就用 cairo 和 pango;要高效率的、轻量地绘制大量的文本,就用 harfbuzz-ng 来自己攒一个排版引擎 — 大部分浏览器都是这样,只不过在没有 harfbuzz-ng 的情况下,或者要直接用 FreeType,不得不多写很多代码,或者就用 pango 这种重量级的,性能又得不到保证。

在 8 月份,harfbuzz-ng 的 [API 提议](http://lists.freedesktop.org/archives/harfbuzz/2009-August/000359.html)已经出现,并在不断讨论中完善 (要我说,本来这个星球上有经验参与讨论的也最多不超过 20 个人,不如大家到一个屋子里开个会搞定得了)。

[XeTeX](http://www.tug.org/xetex/) 的作者 Jonathan Kew 虽然仍然在开发 [TeXworks](http://www.tug.org/texworks/),但工作的重心已经放到了 Mozilla Firefox 3.6 的 [WOFF](http://hacks.mozilla.org/2009/10/woff/) 格式和 OpenType 复杂排版支持上,最近的一个视频里 Jonathan 提供了一个[很棒的概览](http://hacks.mozilla.org/2009/10/font-control-for-designers/),有这样的一些特性之后,在浏览器里做一些**认真的**文本排版才可能成为现实 — 可惜浏览器仍然缺乏好的断行算法实现。这部分工作其实就是基于 harfbuzz-ng 的。而 WebKit-GTK 版本也开始了基于 harfbuzz-ng 的实现。

当然了,畅想了一番美好未来之后还是要回到现实,目前我想做的一个项目,是开发一套能跨 iPhone OS 和 Mac OS X 的、轻量级的排版引擎,专门给[文本阅读器](http://www.jjgod.org/projects/textus)用。这个工作的出发点是:

1. iPhone 上缺少 (按我的标准) 足够好的文本阅读器,而既然我已经开始写 Textus 了,不如把它移植到 iPhone 上;
2. iPhone 上没有 Core Text 这个层次的框架,要渲染文本要么用 `NSAttributedString`,要么用 `WebView`,他们的额外开销都太多,太重量级了;
3. 轻量的方法有神秘的 private API [`CGFontGetGlyphsForUnichars`](http://www.google.com/search?q=CGFontGetGlyphsForUnichars),如果不愿意用 private API 呢,就只好像 [cocos2d-iphone](http://code.google.com/p/cocos2d-iphone/) 那样自己去实现 [cmap 载入的代码](http://code.google.com/p/cocos2d-iphone/source/browse/trunk/external/FontLabel/FontLabelStringDrawing.m),非常痛苦;
4. 即使这样,也不支持复杂的 OpenType 排版特性,甚至简单一点的连字 (ligature) 都不支持,对于一个文本阅读器这是不能忍受的。

所以觉得写个这样的引擎会比较有用:

* 做到后端独立,比如可以选用 ICU (iPhone OS 上), Core Text (Mac OS X 上), harfbuzz-ng
* 能够支持 OpenType 复杂排版特性
* 至少支持好大部分西方字符和 CJK 字符
* API 尽可能的简单

最近刚刚开始做一些试验,比如用 Core Graphics 完成了一个简单的 [CGFontInstance](http://github.com/jjgod/texo/tree/master/icu/) 给 ICU 用,这在目前还没看到类似的工作。

Mac OS X 视频解码技术之现状

最近,Adobe 在 Flash Player 10.1 的 [release notes](http://labs.adobe.com/technologies/flashplayer10/releasenotes.pdf) 中这样写到:

In Flash Player 10.1, H.264 hardware acceleration is not supported under Linux
and Mac OS. Linux currently lacks a developed standard API that supports H.264
hardware video decoding, and Mac OS X does not expose access to the required
APIs. We will continue to evaluate adding the feature to Linux and Mac OS in
future releases.

然而实际上 Linux 下已经有了比较完善的 [VDPAU](http://en.wikipedia.org/wiki/VDPAU) API 用于视频硬件解码 — ffmpeg 和 [mplayer](http://www.mplayerhq.hu/design7/news.html#accelerationtips) 都对它有很好的支持。Mac OS X 呢?让我们罗列一下事实:

* 这里说的解码 — 主要是指视频,尤其是 [H.264](http://en.wikipedia.org/wiki/H.264/MPEG-4_AVC) 视频的解码,因为音频解码功能需要的资源较少,最耗资源的就是 H.264 解码。
* 对于有 [nVIDIA 9400M](http://www.nvidia.com/object/product_geforce_9400m_g_us.html) 显卡的机器,Snow Leopard 的 [QuickTime X](http://www.apple.com/macosx/what-is-macosx/quicktime.html) 支持使用*未公开*的接口来硬件解码特定 profile (low, standard) 的 H.264 视频,这个兼容性虽然没有人详细测试过,但可以认为是比较有限的。QuickTime X 最大的限制是限死了对封装 (container) 格式的支持,在它支持的封装格式中,能使用 H.264 视频编码也就是 mp4 和 mov 两种,而在电脑上观看的高清视频大部分是 [mkv](http://en.wikipedia.org/wiki/Matroska) 封装的。
* 传统的 QuickTime 7 (在 Snow Leopard 中仍然可用) 虽然可以通过 [Perian](http://perian.org) 支持更多的格式,没有见到具体的报告讨论 QuickTime 7 能否使用 Apple 的 H.264 硬解码模块 ([AppleVAH264HW.component](http://arstechnica.com/apple/news/2008/10/digging-into-new-macbooks-support-of-gpu-accelerated-h-264.ars)),[Perian 社区](http://groups.google.com/group/perian-discuss)的讨论也没提到能否利用这个模块来解码 H.264,同时用 ffmpeg 来解析 mkv 封装格式。
* 因为 Mac OS X 下**所有**显卡的驱动都是通过 Apple 分发的 — 显卡厂商自己没有发布过这些驱动,也没有权力提供用户空间的库来调用自己显卡中的硬件解码 API (实际上这显然还是得内核支持的),如果 Apple 不公开视频硬解码 API,造成的结果就是没有一个第三方的应用程序能利用 Mac 上完全充足的硬件 (9400M, 9600M 等等) 来解码 H.264 视频。
* 除了硬件解码之外的方案还有纯软件解码和基于 GPGPU 的方案,前者,Mac OS X 下可用的是 ffmpeg 的 H.264 解码功能,mplayer, Perian, Movist 等播放器用的都是它,还有一种是 [CoreAVC](http://coreavc.com/) 开发者的 CorePlayer Pro,这是一个封闭的播放器,在 Mac 上不提供单独的解码器;至于 GPGPU 方案,市场上现有的只有 CoreAVC 基于 CUDA 的解码技术,他们确实有计划开发基于 OpenCL 的解码,但看起来仍然是一个很漫长的周期,而其他开发者因为缺乏足够的经验,很难涉足这个领域 — 没错,视频编解码的水很深。

以上这些事实造成的恶果是,Mac 用户空守着性能充足的显卡,在 OS X 上播放起 1080p 视频时往往 CPU 占用率在 100% 以上,播放高码率的 720p 视频也能到 70% ~ 80%。如果用了硬件解码,CPU 占用率会在 5% 以下,而基于 CUDA 的方案占用率也只有 10% 左右。

那我们能做什么呢?不管出于减少能耗还是减少机器发热的角度,都很有必要向 Apple [提交 bug 报告](http://bugreport.apple.com),要求提供公开的 H.264 硬解码 API。