request-free-img

Photoshop 1.0 开源-源代码探秘:从 Pascal 到改变世界的工具

2013 年 2 月 13 日 Adobe 开源了 Photoshop 1.0 的源代码,源代码包含了大约 179 个文件,共约 12.8 万行代码。

回看这份代码,整个 Photoshop 1.0 的代码 88% 使用了 Pascal 语言编写,其余 12%则采用汇编语言。

有朋友要问了,

为什么是 Pascal 而不是用 C 或 C++进行开发呢?要知 C 在 1987 年已经很流行了,莫非是因为 PHOTOSHO 的作者 Thomas 不会 C 语言 吗?

UNIT UVMemory;
INTERFACE
USES
    {$LOAD MacIntf.LOAD}
    MemTypes, QuickDraw, OSIntf, ToolIntf, PackIntf,
    ...

1984-1985:Object Pascal 的诞生

1984 年,Apple 的 Larry Tesler 与 Pascal 语言发明人Niklaus Wirth合作,将 Clascal 发展成Object Pascal

第二年,Apple 发布了Object Pascal 编译器

紧接着,苹果发布使用 Object Pascal 开发的苹果应用开发框架 MacApp 1.0,它提供了文档/视图架构、事件处理、菜单管理,让开发者不需要从零开始写 Mac 应用。

之后 Object Pascal 成为 Macintosh 开发的事实标准

苹果的画图程序MacPaint,(文字处理程序)MacWrite,(绘图程序)MacDraw, (终端程序)MacTerminal全都采用 Object pascal 编写。

而 Thomas 的 Photoshop 正是为 Mac 系统开发的,理所当然,也使用了 苹果的 MacApp 框架进行开发。

从源代码中可以看到 MacApp 的依赖:

USES
    {$LOAD UMacApp.LOAD}
    UObject, UList, UMacApp,

所以,Thomas 没有其它选择,他必须用 Pascal 来开发 Photoshop。

插一句哈,苹果 在1991 年 改用 C++全部重写 MacApp 3.0 版本。

1994 年 9 月,Photoshop 3.0 也完全用 C++重写, 代码库彻底重构。

“By version 3, they HAD rewritten the application entirely – in a completely different language.”

代码的艺术

虽然 Photoshop 1.0 距今已经过去了 30 多年,但是回过头来看 Thomas 当年写的代码,你仍然会发很多值得一说的东西。

但是因为代码量比较大,photoshop 1.0 超过 12 万行代码,对于 1990 年的软件来说,这已经是非常大的规模。

所以我们不可能一一去说它,在此我们挑三个最值得一看的功能点。

虚拟内存分页系统 – 最具创新性

文件位置: UVMemory.inc1.p 第 211-451 行

第一个就是虚拟内存分页系统,这是一个极其精妙的磁盘分页虚拟内存系统,它让 Photoshop 能在只有 1-8MB 内存的 Mac 上处理超大图像。

它的核心技术特征:

  • 30KB 页面大小 (第 22 行:kVMPageSize = 30720)
  • LRU (最近最少使用) 缓存淘汰,使用双向链表管理页面 (第 342-389 行)
  • (第 1307, 1325-1330 行),允许安全的嵌套访问虚拟内存数据
  • 批量刷新脏页 (第 463 行:kBatchSize = 20),优化磁盘 I/O

代码示例 (第 1277-1289 行):

fData := NewLargeHandle (ORD4 (hiPage - loPage + 1) * kVMPageSize);
FOR j := loPage TO hiPage DO
BEGIN
BlockMove (gVMPageInfo^^ [fPageList^^[j]] .fData^,
dstPtr,
kVMPageSize);
dstPtr := Ptr (ORD4 (dstPtr) + kVMPageSize)
END

当需要多个页面时,智能地将它们合并成单个连续缓冲区——这是应对内存碎片的巧妙方案。

双三次插值汇编优化

文件位置: URotate.a 第 63-163 行

采用高度优化的 68k 汇编实现的三次插值算法,用于图像缩放和旋转, 这是一个极致优化的算法。

技术手法 (第 63-163 行):

; 使用分数部分计算加权斜率
SUB.W D2,D0 ; 斜率计算
MULS.W D7,D0 ; 用分数加权
ASR.W #1,D0 ; 快速除以 2
; 对分数进行平方以实现三次插值
MULU.W D6,D6 ; (1-fraction)²
MULU.W D7,D7 ; fraction²
; 计算最终插值值
MULS.W D1,D6 ; 加权斜率 1
MULS.W D2,D7 ; 加权斜率 2
ADD.L D6,D7 ; 合并

精妙之处:

  • 使用 8 位精度的定点数学 (第 76 行:LSR.W #3,D7)
  • 它有首巧妙的累加器管理,最小化内存访问

这个算法模式至今仍用于 GPU 纹理采样!

CMYK 专业分色算法(含 UCR/GCR 处理)

文件位置: USeparation.inc1.p 第 147-394 行

专业印刷色彩分离极其复杂,而 Photoshop 1.0.1 实现了非常先进的分色算法。

(1) 底色去除 (UCR) 算法 (第 147-178 行):

PROCEDURE SolveUCR (VAR gcrTable: TLookUpTable;
VAR ucrTable: TLookUpTable);
VAR
s: EXTENDED; { 使用浮点数!}
w: EXTENDED;
BEGIN
s := 1.0;
FOR j := 255 DOWNTO 0 DO
BEGIN
k := ORD (gcrTable [j]);
IF k > 0 THEN
BEGIN
w := SQR (k / 255); { 二次加权混合 }
s := (j / k) _ w + s _ (1 - w);
IF s > 1 THEN s := 1
END;
ucrTable [j] := CHR (...)
END
END;

使用二次加权的非线性插值——对于一个绘画程序来说异常精密!

(2) 定点数反正切计算 (第 215-233 行):

FUNCTION FindHue (r, g, b: INTEGER): INTEGER;
FUNCTION Angle (x, y: INTEGER): INTEGER;
BEGIN
IF y < 0 THEN Angle := -Angle (x, -y)
ELSE IF x < 0 THEN Angle := 2048 - Angle (-x, y)
ELSE IF y > x THEN Angle := 1024 - Angle (y, x)
ELSE IF x = 0 THEN Angle := 0
ELSE Angle := BSL (y, 9) DIV x { 定点数 arctangent }
END;

避免昂贵的三角函数,用定点数近似计算反正切!

3D 种子矩阵插值 (第 400+ 行):

在 CMYK 色彩空间构建 6×6×6 查找表,使用矩阵求逆实现平滑的颜色变换梯度。

从以上这些代码我们可以看出, Photoshop 从第一天起就是为专业印刷工作设计的,不是简单的图像编辑器。色彩科学真是是货真价实的专业级。

即使以现代标准来看,这些实现仍然令人印象深刻,揭示了 Photoshop 1.0.1 从一开始就是专业级工具,而非业余项目。

1989 年的远程协作

在互联网高达发达的今天,远程协作工作已经变得非常容易,不是什么新鲜事了,但是你有没想象过在 1989 年,如果要进行远程协作,要怎么办吗?

在整个 1989 年:

  • Thomas 在密歇根的家里编码
  • John 在加州的 ILM 工作

那他们是如何进行远程协作的呢?

  • 首先当然是电话:他们每周会进行多次长途电话讨论功能
  • 然后 Thomas 把讨论的功能开发出新版本后,写入到软盘中,再邮寄给 John 进行测试
  • 如有必要,John 则会飞到密歇根,或者是 Thomas 飞到加州进行见面沟通

没有互联网。也没有 Git。只有热情和决心。

2013 年 2 月 13 日,公开源代码

2013 年 2 月 13 日 计算机历史博物馆宣布:在 Adobe 的许可下,公开发布 Photoshop 1.0.1 的源代码。

Adobe 在声明中说道(通过博物馆发布):

With the permission of Adobe Systems Inc., the Computer History Museum is pleased to make available, for non-commercial use, the source code to the 1990 version 1.0.1 of Photoshop.

计算机历史博物馆相关人士说(Grady Booch):

“Software source code is the literature of computer scientists, and it deserves to be studied and appreciated.”

发布内容包括

  • 179 个源文件
  • 约 128,000 行代码
  • 很可惜的是:由于 Apple 的授权限制,发布的代码缺少 MacApp 库,无法进行编译

计算机历史博物馆董事,也是 IBM 软件架构师 Grady Booch

“这是我们都能学习的代码。它如此清晰易读,注释反而可能妨碍理解。这就是软件工艺(software craftsmanship)的典范。

现如今,Photoshop 的源码早就超过千万行。

这一切都源自 Thomas Knoll 在 1989 年打下的坚石基础,支撑了 Photoshop 35 年的发展。

杜比剧院的舞台

2019 年 2 月 24 日,Thomas 和 John Knoll,两位白发的兄弟,站上奥斯卡舞台上,领取了属于他们的科学技术奖。

Photoshop 1.0 源代码探秘:从 Pascal 到改变世界的工具

颁奖词

“表彰 Thomas 和 John Knoll 对 Adobe Photoshop 的原始架构、设计和开发。Photoshop 在电影制作中的作用是巨大的,使艺术家能够以前所未有的方式创作和操作图像。”

台下的电影人起立鼓掌。

从工业光魔到好莱坞

这个奖项特别适合 John Knoll。

他从未离开 ILM。从 1986 年的夜班摄像机操作员,到首席创意官

John 参与的电影(部分):

  • 《星球大战》前传三部曲
  • 《星球大战》续集三部曲
  • 《侏罗纪公园》
  • 《加勒比海盗》系列
  • 《阿凡达》
  • 《侠盗一号》

而这一切作品,都用到了 Photoshop。

Thomas 的持续贡献

Thomas 也从未停止。

在 Adobe 工作多年后,他开发了Camera Raw,一款数码摄影界的关键工具。

Camera Raw 让专业摄影师能够处理 RAW 格式的数码照片,保留最大的图像质量和调整空间。

这是 他 1987 年 Display 程序的延续:让不可能变为可能。

最后淡入,淡出:

这不只是技术史,而是关于梦想、执着、完美主义,以及两兄弟如何用代码改变世界的人类故事

_”I really disliked writing papers, so I wrote code instead.”_

— Thomas Knoll, 1987

_”We had no idea we were adding a word to the dictionary.”_

— John Knoll, reflecting on Photoshop’s name

这是 Photoshop 的故事。

这是代码改变世界的故事。

这是你也能创造历史的证明。

致敬所有程序员

主要来源

  1. Computer History Museum – Adobe Photoshop Source Code
  2. Thomas & John Knoll Create Adobe Photoshop – History of Information
  3. University of Michigan – Power to the Pixel: Photoshop is Born
  4. ILM Interview – John and Thomas Knoll Share the Origin Story
  5. University of Michigan Record – “I really disliked writing papers”

其他来源

  1. DPreview – Computer History Museum shares original Photoshop code
  2. PetaPixel – Source Code Released
  3. FilterGrade – History of Photoshop Through the Years

更多问题探讨,请关注公众号:程序员角