摘要

  • Alan R. Katz 在 1981 年写成的 Rapicom 450 解码程序,能把已存储的传真数据还原成单色位图。文件先到了,能看的页面还没有。
  • 数据字节、部分块头字段和游程长度各有不同的比特反转规则;块头帮助程序在丢块后重新定位。RFC 797 则提出十字节位图头,让后续程序面对像素,而非传真机的私有编码。

传真机把文件交出来,电脑却看不出纸上画了什么。比特被取反、在字节里倒序,有些字段还要单独倒序;两条扫描行又被捆成黑白组合。谁要是把这个文件直接扔给显示器,得到的大概是一幅抽象画。Alan R. Katz 于 1981 年 9 月写的 RFC 798,讲的就是怎样把 Rapicom 450 的私有比特流拆开,重组为普通位图。与之配套的 RFC 797,给重组后的图片安排了一个清爽的家。

Katz 的程序用 L10 写成,运行在 TOPS20 上的 NLS 环境中。传真机通过名为 FAXIE 的微处理器接口接到电脑终端线。机器串行送来数据,FAXIE 每八位凑成一个字节。Rapicom 对 MARK 和 SPACE 的逻辑含义恰好与 RS232 相反,因此接口先对各位取反。写入文件时,数据字节还按既定约定倒转位序并取反。解码时必须把这些动作倒回去。文件记录开头的长度字节和命令字节不参加这套变换;把它们也翻一遍,连盒子的盖子都认不出来。

盒子里面确实有规矩。设备每块送出 585 位,尾部补七个零,就成了 74 个数据字节。文件中的普通记录另加长度和命令字节,共 76 字节。命令区分设置块、数据块和结束块。这样的包装让数据能保存、能传递,却没有替使用者画出图像。真正的页面藏在设备的编码法里。

Katz 描述的普通信纸图像约有 2100 行,每行 1726 个黑白像素。精细模式写下每一行;质量模式写每隔一行;快速模式写每隔两行。显示时,缺席的行靠重复前一行补上。传真机一次编码上下两行,每一列因此有白白、白黑、黑白、黑黑四种状态。状态之间的跳转用长短不一的比特串表达;连续的全白或全黑列则用游程计数,计数字段可能从两位长到七位。这里不是“一位就是一个像素”的轻松游戏。

最容易让人手滑的是“反过来”竟有好几层意思。整个数据字节的位序和取反是一层。设备块头里的有效数据位数、横向位置、黑白游程字段,其字段内部位序又要反着读;序号和当前状态却不用。图像数据里的游程长度也按字段倒序发送。Katz 特别提醒:反转一个 n 位字段,不等于把整字节翻面再取反。写一个万能“反转”按钮很省事,直到屏幕拒绝把人脸画在应有的位置。

数据块还自带重新找路的线索。585 位里有同步码、37 位块头、512 位数据区和校验和。块头的有效位数说明 512 位中有多少是真的;值为零时整块丢弃。块头中的横向位置若比上一块终点靠后,空隙填白;若退回,重叠部分用新块数据覆盖。序号在 0、1、2、3 之间循环,跳号就说明有块失踪。每次开始新块,程序应相信这一块自己报告的状态、游程字段长度和横向位置,即使与上一块的结尾不一致。这能让解码从失块后继续,丢掉的笔画却不会凭空回来。

像素终于排好队后,RFC 797 给出了朴素的位图文件格式:头四字节写宽度,接着四字节写高度,再用两个字节写横向和纵向增量。第十一个字节起才是图像数据,从左到右、从上到下,每行末尾补零凑齐整字节。纵向增量一、二、三可对应 Rapicom 的精细、质量、快速模式,显示时按数值重复扫描行。接手的程序只需读像素和几项尺寸信息,不必继承传真机的一整套脾气。

这不是纸上游戏。Katz 报告,一份普通精细模式文件在 DEC KL10/TOPS20 上解码约用两分钟 CPU 时间;得到的约 1726×2100 像素位图占用约 204 个磁盘页。HP 图形终端只能显示页面的一部分,再靠缩放查看细节。一张传真真正“送到”屏幕,代价是有人把每一层倒着走的比特都转了回来。