前言
"把 PDF 转成 TIFF""把扫描的 TIFF 转成 PDF"是很常见的需求,常用于归档、传真、票据存档等场景。但多数教程只丢一段代码就完事,从不解释一个关键前提:PDF 和 TIFF 根本不是同一类东西。PDF 是矢量文档格式,里面的文字可能带着字体、字形和文本层;TIFF 是多页位图格式,只存像素。搞不清这一点,转出来的结果会和你预期差很远。
这篇讲的是原理和流程,不是可直接粘贴的成品。涉及的库——处理 PDF 的 PyMuPDF(导入名fitz)与 pypdf、处理图像的 Pillow——都是第三方库,需要单独安装;本机没有它们,因此下面的代码是示意性的,用来讲清步骤,每个库的具体函数签名、参数与行为一律以各库官方文档为准,不要凭本文去断言某个参数的效果。
一、本质:一个是矢量,一个是位图
| 维度 | TIFF |
|---|
| 内容形态 | 矢量 + 文本层(也可能是扫描位图) | 光栅位图(像素) |
| 多页 | 支持 | 支持(多页 TIFF) |
| 文字可选中 | 通常是 | 否(除非另附 OCR 文本层) |
| 缩放 | 矢量内容放大不糊 | 放大就糊(受限于分辨率) |
| 典型用途 | 电子文档、排版输出 | 扫描归档、传真、印刷 |
正因为一个是矢量、一个是像素,所谓"互转"在本质上只有一条路:把页面渲染成像素位图再重新打包(PDF→TIFF),或者把一张张位图打包成 PDF 的页面(TIFF→PDF)。没有"把矢量无损变成位图又不丢信息"这种事——一旦渲染成像素,文本层就没了,字变成了一堆点,不能再被搜索、复制或提取。这是本文最需要你记住的一句话。
二、PDF 转 TIFF 的流程
思路是逐页渲染、逐页收集、最后一次性打包。
# 适用于 Python 3 的示意代码(第三方库 PyMuPDF 与 Pillow,本机未安装);API 以各库官方文档为准
import fitz # PyMuPDF 的导入名
from PIL import Image
doc = fitz.open("input.pdf") # 打开 PDF
pages = []
for page in doc: # 逐页处理
# 用指定分辨率把这一页渲染成位图(dpi 越高越清晰,体积也越大)
pix = page.get_pixmap(dpi=200)
img = Image.frombytes("RGB", (pix.width, pix.height), pix.samples)
pages.append(img)
# 多页 TIFF:Pillow 用 save_all 加 append_images 保存多帧
pages[0].save("output.tif", save_all=True, append_images=pages[1:])
doc.close()三个环节各自的关键参数:
- 打开文档:拿到文档对象后可以读页数、逐页访问。
- 渲染:这一步的分辨率(dpi/缩放)决定成品清晰度和文件大小,是 PDF→TIFF 最重要的旋钮。dpi 太低文字发虚,太高文件巨大。
- 打包:把多张图存成一个多页 TIFF,需要显式开启"保存全部帧"并把它余下的帧按顺序附上。
如果只是单页转换,pages[0].save("output.tif")就够了;多页必须走多帧保存的路径,否则只会存下第一页——这是新手最常踩的坑。
还有一个容易被忽略的取舍:TIFF 的体积。位图 TIFF 若不做压缩,几十页就可能涨到几百 MB。常见做法是给 TIFF 选择无损或有损压缩、或降低位深(彩色转灰度、灰度转黑白),但每一次降级都在损失信息。归档场景里要在"能看清"和"存得下"之间明确一条线——先定用途(是给人看还是给机器识别),再定分辨率、色彩模式与压缩方式,而不是转完再抱怨文件太大。
三、TIFF 转 PDF 的流程
反方向更简单:它本质是给每张图包一层 PDF 页面。Pillow 可以直接把图像存成 PDF;多页 TIFF 要先拆帧。
# 适用于 Python 3 的示意代码(第三方库 Pillow,本机未安装);API 以各库官方文档为准
from PIL import Image
img = Image.open("input.tif") # 可能是多页
frames = []
try:
while True:
frames.append(img.convert("RGB")) # 拆出当前帧
img.seek(img.tell() + 1) # 移到下一帧
except EOFError:
pass # 没有更多帧了
if frames:
frames[0].save("output.pdf", save_all=True, append_images=frames[1:])要点:这一步只产生像素页,PDF 里没有可选中、可搜索的文字。想让结果"能搜",就必须在之前或之后加一道 OCR(光学字符识别)把文字识别出来,再作为文本层叠加——那是另一条技术路线,不是"格式转换"本身能解决的。
四、转换中真正会丢的信息
把常见的损失列出来,比记 API 有用得多:
- 文本层:渲染成像素即丢失,文字不再可选择、可搜索、可复制。
- 矢量清晰度:放大后会看到锯齿或模糊,只能靠提高渲染分辨率缓解,无法恢复。
- 超链接、书签、表单域:PDF 的这些交互信息在纯位图里不存在。
- 颜色与色彩空间:位图的色彩空间与 PDF 的可能不同,转的时候要留意是否做色彩管理。
- 压缩与体积:TIFF 常见无压缩或无损压缩,体积可能远大于原件;选择压缩方式要在体积和画质间权衡。
理解了这些,"转换质量不好"就不再是玄学——先问清楚:我要的是"看着像"还是"能搜索"?要能搜索就必须保留文本层或补 OCR。
五、库怎么选
| 库 | 擅长 | 说明 |
|---|
PyMuPDF(fitz) | 打开 PDF、按页渲染成位图 | 渲染速度与成像质量口碑好 |
| pypdf | 读写 PDF 结构、合并拆分、页级操作 | 偏"文档结构"而非"渲染" |
| Pillow | 读写 TIFF/PNG/JPEG 等图像、多帧保存 | 图像侧的主力 |
| OCR 库(如 Tesseract 的封装) | 从位图里识别文字 | 想保住可搜索性时才需要 |
选择原则:PDF 侧用 PyMuPDF 或 pypdf 负责打开与页面操作,图像侧用 Pillow 负责保存与打包,两边各司其职。具体某个库能不能做某件事、参数怎么写,以该库官方文档为准。
常见坑点
坑 1:以为转成 TIFF 后文字还能被搜索。
❌ 把带文字的 PDF 转成 TIFF,期待在 TIFF 里搜索关键词 —— 位图里没有文本层。
✅ 明确"位图不可搜";需要可搜索就保留 PDF 原文件,或对图像加 OCR 生成文本层。
坑 2:多页只存下第一页。
❌img.save("out.tif")处理多页时只写了第一帧。
✅ 用多帧保存:开启保存全部帧并把其余帧按顺序附上。
坑 3:渲染分辨率拍脑袋定。
❌ 随手用很低的 dpi,文字发虚;或直接用极高 dpi,文件大到无法归档。
✅ 先按用途定目标:屏幕预览可低些,印刷/归档要高些;转完检查清晰度与体积。
坑 4:彩色图像转成黑白或调色板模式。
❌ 转换时不做颜色处理,存成 1 位或调色板模式,彩色内容变色。
✅ 明确目标色彩空间,必要时先convert到 RGB。
坑 5:忽略页面尺寸与旋转。
❌ PDF 有旋转标记或非标准页尺寸,直接转后方向歪了、比例变了。
✅ 转换时统一按目标页尺寸处理,并留意原始页的旋转属性。
坑 6:把"格式转换"当成"格式转换 + OCR"。
❌ 拿一张扫描 TIFF 转成 PDF,以为就得到了可搜索文档。
✅ 扫描件要可搜,必须在流程里显式加入 OCR 步骤。
坑 7:没关文件句柄就处理下一个。
❌ 批量转换时不关闭打开的文档或图像对象,文件被占用、内存上涨。
✅ 用with或显式close();批量任务里逐个释放。
总结
| 方向 | 本质操作 | 会丢什么 |
|---|
| PDF → TIFF | 按 dpi 逐页渲染成像素,再多帧打包 | 文本层、矢量清晰度、链接与书签 |
| TIFF → PDF | 拆帧后把每张图包成一页 | 无(本就是位图),但也不会凭空产生文本 |
| 想保住文字 | 保留 PDF 或补 OCR | —— |
一句话总结:PDF 转 TIFF 是"渲染成像素再打包",TIFF 转 PDF 是"给位图包上 PDF 外壳",两条路的共同点是都在像素层面工作,都会丢文本层。选好渲染分辨率、处理好多页打包,就能得到符合预期的结果;要可搜索就得另走 OCR 路线。所有具体 API以各库官方文档为准。