Pillow TiffTags 模块
下面给你一个 Pillow(PIL Fork)中 TiffTags 模块 的完整入门指南,包含 TIFF 图像元数据读取、写入、解析、分辨率、方向、压缩、批量处理、ICC 配置文件、地理 TIFF 等高级应用。
(基于 Pillow ≥ 9.0,Python 3.8+)
1. 安装 Pillow(支持 TIFF)
pip install --upgrade pillow
注意:Pillow 默认支持 TIFF,但某些功能(如 LZW 压缩)需要系统库
libtiff。
2. 基本导入
from PIL import Image
from PIL.TiffTags import TAGS
3. TIFF 图像元数据(Tag)概述
TIFF 是一种多功能图像格式,支持:
| 特性 | 说明 |
|---|---|
| 多页(Multi-page) | 一文件多图 |
| 高位深 | 16/32 位 |
| 压缩 | LZW, ZIP, JPEG, PackBits |
| 元数据 | 分辨率、方向、相机信息、ICC |
| 地理信息 | GeoTIFF(坐标、投影) |
4. 读取所有 TIFF Tag
img = Image.open("image.tif")
for tag_id, value in img.tag.items():
tag_name = TAGS.get(tag_id, tag_id)
print(f"{tag_name} ({tag_id}): {value}")
常用 Tag ID:
256: ImageWidth257: ImageLength258: BitsPerSample259: Compression282: XResolution283: YResolution296: ResolutionUnit274: Orientation34665: ExifIFD(EXIF)34737: ICCProfile
5. 解析常用字段
def get_tiff_info(img_path):
img = Image.open(img_path)
tag = img.tag
info = {
"尺寸": img.size,
"模式": img.mode,
"页数": getattr(img, "n_frames", 1),
"分辨率": (
tag.get(282), # XResolution
tag.get(283), # YResolution
tag.get(296, 2) # ResolutionUnit (1=无单位, 2=英寸, 3=厘米)
),
"方向": tag.get(274, 1),
"压缩": tag.get(259, 1),
"ICC配置文件": bool(tag.get(34675))
}
return info
# 使用
info = get_tiff_info("scan.tif")
for k, v in info.items():
print(f"{k}: {v}")
6. 解析分辨率(DPI)
def get_dpi(img_path):
img = Image.open(img_path)
x_res = img.tag.get(282) # XResolution
y_res = img.tag.get(283) # YResolution
unit = img.tag.get(296, 2) # ResolutionUnit
if x_res and y_res and unit == 2: # 英寸
return (float(x_res[0][0])/x_res[0][1], float(y_res[0][0])/y_res[0][1])
return None
dpi = get_dpi("scan.tif")
if dpi:
print(f"DPI: {dpi[0]:.0f} x {dpi[1]:.0f}")
7. 读取多页 TIFF
def read_multipage_tiff(tiff_path):
img = Image.open(tiff_path)
pages = []
try:
i = 0
while True:
img.seek(i)
page = img.copy()
pages.append(page)
i += 1
except EOFError:
pass # 结束
return pages
pages = read_multipage_tiff("document.tif")
print(f"共 {len(pages)} 页")
for i, page in enumerate(pages):
page.save(f"page_{i+1}.png")
8. 写入 TIFF + 自定义 Tag
def save_tiff_with_tags(input_path, output_path, dpi=300, compression="tiff_lzw"):
img = Image.open(input_path).convert("RGB")
# 设置分辨率
img.info["dpi"] = (dpi, dpi)
# 自定义 Tag
img.tag[270] = "Pillow 生成的 TIFF" # ImageDescription
img.tag[306] = "2025:04:05 12:00:00" # DateTime
img.tag[274] = 1 # Orientation: TopLeft
img.save(output_path, compression=compression, tiffinfo=img.tag)
print(f"已保存: {output_path}")
save_tiff_with_tags("input.jpg", "output.tif")
9. 提取 ICC 配置文件
def extract_icc_profile(tiff_path, output_icc="profile.icc"):
img = Image.open(tiff_path)
icc = img.tag.get(34675) # ICCProfile
if icc:
with open(output_icc, "wb") as f:
f.write(icc[0])
print(f"ICC 配置文件已提取: {output_icc}")
else:
print("无 ICC 配置文件")
extract_icc_profile("color.tif")
10. 批量处理:转换 + 压缩 + 添加 DPI
import os
def batch_convert_to_tiff(input_dir, output_dir, dpi=300):
os.makedirs(output_dir, exist_ok=True)
for fname in os.listdir(input_dir):
if fname.lower().endswith(('.png', '.jpg', '.jpeg')):
in_path = os.path.join(input_dir, fname)
out_path = os.path.join(output_dir, os.path.splitext(fname)[0] + ".tif")
img = Image.open(in_path).convert("RGB")
img.info["dpi"] = (dpi, dpi)
img.save(out_path, compression="tiff_lzw", dpi=(dpi, dpi))
print(f"已转换: {out_path}")
batch_convert_to_tiff("images", "tiff_output")
11. GeoTIFF 支持(读取地理信息)
def get_geotiff_info(tiff_path):
img = Image.open(tiff_path)
tag = img.tag
# GeoTIFF 常用 Tag
geotags = {
33550: "PixelScale", # 像素尺寸 (x, y, z)
33922: "TiePoints", # 控制点
34735: "GeoKeyDirectory", # 投影信息
34737: "GeoAsciiParams"
}
geo_info = {}
for tag_id, name in geotags.items():
if tag_id in tag:
geo_info[name] = tag[tag_id]
return geo_info
# 使用
info = get_geotiff_info("map.tif")
for k, v in info.items():
print(f"{k}: {v}")
12. 高级技巧
12.1 自动按 DPI 缩放打印
def print_size_from_dpi(tiff_path):
dpi = get_dpi(tiff_path)
if not dpi:
return "未知 DPI"
img = Image.open(tiff_path)
width_inch = img.width / dpi[0]
height_inch = img.height / dpi[1]
return f"{width_inch:.2f} x {height_inch:.2f} 英寸"
print(print_size_from_dpi("scan.tif"))
12.2 合并多页为 PDF(借助 reportlab)
pip install reportlab
from reportlab.pdfgen import canvas
def tiff_to_pdf(tiff_path, pdf_path):
pages = read_multipage_tiff(tiff_path)
c = canvas.Canvas(pdf_path, pagesize=pages[0].size)
for page in pages:
temp = "temp_page.png"
page.save(temp)
c.drawImage(temp, 0, 0)
c.showPage()
c.save()
os.remove(temp)
tiff_to_pdf("doc.tif", "doc.pdf")
13. 常见问题 & 解决方案
| 问题 | 原因 | 解决 |
|---|---|---|
tag 为空 | 非 TIFF 格式 | 检查文件头 |
LZW 压缩失败 | 系统无 libtiff | 安装 libtiff 或用 tiff_deflate |
分辨率显示为 (1,1) | 未设置 DPI | 用 img.info["dpi"] = (300,300) |
| 多页 TIFF 只能读第一页 | 未用 seek() | 使用 while True: img.seek(i) |
| ICC 丢失 | save() 未传 icc_profile | img.save(..., icc_profile=img.info.get("icc_profile")) |
14. 官方文档
- https://pillow.readthedocs.io/en/stable/reference/TiffTags.html
- TIFF 规范:https://www.adobe.io/open/standards/TIFF.html
一键工具脚本:tiff_tool.py
#!/usr/bin/env python3
import argparse
from PIL import Image
from PIL.TiffTags import TAGS
def main():
parser = argparse.ArgumentParser(description="TIFF 信息工具")
parser.add_argument("tiff", help="TIFF 文件路径")
parser.add_argument("-d", "--dpi", action="store_true", help="显示 DPI")
parser.add_argument("-p", "--pages", action="store_true", help="显示页数")
parser.add_argument("-i", "--icc", help="提取 ICC 到文件")
args = parser.parse_args()
img = Image.open(args.tiff)
if args.icc:
icc = img.tag.get(34675)
if icc:
with open(args.icc, "wb") as f:
f.write(icc[0])
print(f"ICC 已提取: {args.icc}")
else:
print("无 ICC")
return
print(f"文件: {args.tiff}")
print(f"尺寸: {img.size}")
print(f"模式: {img.mode}")
if args.pages:
try:
pages = 0
while True:
img.seek(pages)
pages += 1
print(f"页数: {pages}")
except:
pass
if args.dpi:
dpi = get_dpi(args.tiff)
print(f"DPI: {dpi[0] if dpi else '未知'} x {dpi[1] if dpi else '未知'}")
print("\n主要 Tag:")
for tag_id in [256, 257, 258, 259, 282, 283, 296, 274]:
if tag_id in img.tag:
name = TAGS.get(tag_id, tag_id)
print(f" {name} ({tag_id}): {img.tag[tag_id]}")
if __name__ == "__main__":
main()
使用:
python tiff_tool.py scan.tif -d -p
python tiff_tool.py color.tif -i profile.icc
总结:TiffTags 核心用法
| 功能 | 代码 |
|---|---|
| 读取 Tag | img.tag[tag_id] |
| 解析名称 | TAGS.get(tag_id) |
| 设置 DPI | img.info["dpi"] = (300,300) |
| 多页 | img.seek(i) |
| 保存 | img.save(..., tiffinfo=img.tag) |
需要我帮你实现 扫描仪自动处理、GeoTIFF 地图叠加、医学影像 DICOM 转 TIFF、批量压缩归档 等完整项目吗?直接说需求,我给你完整可运行代码!