本文是系列文章的第 2 篇。上一篇我们讲清了“为什么要在 PDF 中原样保留 CMYK”。这一篇, 我们把一张“PDF 里的图像”彻底拆开,看清它由哪些对象构成,并说明我们的技术选型。
本项目完整源码:https://github.com/AmyLin2013/pdf-cmyk-image
本篇你将学到
- 一张 PDF 图像(Image XObject)到底由哪些键值组成;
- /ColorSpace [/ICCBased …] 是什么,它如何承载 CMYK + ICC;
- 为什么我们选择“底层对象 API”,而刻意绕开高层图片接口;
- 整体技术选型:libtiff 解码 + zlib 压缩 + 福昕 PDF Object API 组装。
一张“PDF 里的图像”长什么样
在 PDF 里,一张位图图像是一个 Image XObject——本质是一个带字典的流对象。 它的关键键值大致如下:
<< /Type /XObject
/Subtype /Image
/Width <像素宽>
/Height <像素高>
/ColorSpace <色彩空间>
/BitsPerComponent 8
/Filter /FlateDecode % 图像数据用什么方式压缩
/Length <压缩后字节数>
>>
stream
…(压缩后的图像采样数据)…
endstream
其中最关键的就是 /ColorSpace。它决定了“流里那一串字节,应该被当作什么颜色来解释”。
- 如果是 /DeviceRGB,每像素 3 通道,按 RGB 解释;
- 如果是 /DeviceCMYK,每像素 4 通道,按 CMYK 解释;
- 如果是 [/ICCBased …],则按内嵌的 ICC 特性文件来精确解释颜色。
要“无损保留 CMYK”,我们要做的就是:让 /ColorSpace 保持 CMYK(且带上原始 ICC), 同时让流里的字节就是源图的 CMYK 采样值。

/ColorSpace [/ICCBased …]:把 ICC 装进 PDF
ICCBased 色彩空间是一个数组,第二个元素指向一个ICC 流对象:
/ColorSpace [ /ICCBased 10 0 R ] % 10 0 R 指向下面这个 ICC 流
而那个 ICC 流对象长这样:
<< /N 4 % 4 个颜色分量 => CMYK
/Alternate /DeviceCMYK % 无法用 ICC 时的回退色彩空间
/Filter /FlateDecode
/Length <压缩后字节数>
>>
stream
…(压缩后的原始 ICC Profile 字节)…
endstream
- /N 4 表示 4 分量,正好对应 CMYK;
- /Alternate /DeviceCMYK 是回退方案;
- 流内容就是源 TIFF 里那份 ICC Profile 的原始字节——我们要做到逐字节保留。

📌 这就是“无损”的两个技术支点:ICCBased 的 ICC 流字节 = 源 ICC, Image 流字节 = 源 CMYK 采样。后续第 6 篇会用 SHA-256 来证明这两点。
为什么刻意不用“高层图片接口”
很多 SDK(包括福昕)都提供“往页面上加一张图”的高层便捷接口。它们很好用,但为了 通用性,内部常常会把图像归一化成 RGB/RGBA 位图再处理。这恰恰是色彩损失的根源。
所以我们的选择是:只用底层 PDF Object API,自己动手构造 ICC 流、ICCBased 色彩空间、 Image XObject,并把它们挂接到页面。这样每一个字节都在我们的掌控之中,不给隐式转换 任何机会。 
这也是本系列想传达的一个观点:当你需要确定性时,底层对象 API 提供的“精确控制” 比“便捷但黑盒”的高层接口更可靠。福昕 PDF SDK 的底层对象接口,正好提供了这种控制力。
技术选型全景
于是整套方案就清晰了,三块拼图各司其职:
| 解码 CMYK TIFF | libtiff(仅 scanline API) | 取出原始 CMYK 采样与内嵌 ICC,绝不走 RGB 路径 |
| 压缩流数据 | zlib(Flate) | 把 ICC 与图像数据压成 PDF 的FlateDecode 流 |
| 组装 PDF 对象 | 福昕 PDF Object API | 构造 ICC 流、ICCBased、Image XObject 并挂接页面 |
用一张图表示对象之间的关系:
ICC 流 ◄──[/ICCBased …]── ColorSpace 数组
▲ ▲
│ │
└───────────── Image XObject ───┘
▲
│ /XObject /ImCMYKn
页面 /Resources
▲
│ q cm /ImCMYKn Do Q
页面 /Contents(内容流)
小结
- PDF 图像是一个带 /ColorSpace 的流对象,色彩空间决定字节如何被解释;
- [/ICCBased …] 让我们把 CMYK 与原始 ICC 一并、精确地写入 PDF;
- 为避免隐式 RGB 转换,我们只用底层对象 API 手工组装;
- 选型:libtiff 解码 + zlib 压缩 + 福昕对象 API 组装。
下一篇预告
第 3 篇《上手实践:工程结构、依赖集成与一键构建运行》,我们会把工程 clone 下来, 装好 libtiff/zlib 和福昕 SDK,一条命令构建并跑出满屏的 PASS。
关于本系列
- 💻 完整源码:https://github.com/AmyLin2013/pdf-cmyk-image
- 🧩 关于福昕 PDF SDK:开发者站点 支持 Windows/Linux/Mac,多语言绑定,可以免费申请试用,感兴趣的自己去薅~







