如何用Python从PDF提取带页码、页面坐标信息的无失真图片
Python实现带坐标元信息的PDF图片无损提取方案
核心思路
直接提取PDF内嵌的原始图片对象,不做整页渲染截图,正确处理图片的透明蒙版、色彩空间转换逻辑,对齐Java PDFBox的提取效果,同时保留页码、页面坐标元数据,完全匹配指定命名规则,规避现有开源库常见的黑底、画质损失、文字覆盖问题。
前置依赖安装
执行以下命令安装需要的依赖包:
pip install pdfplumber pillow
可直接运行的实现代码
import pdfplumber from PIL import Image import io import os def extract_pdf_images(pdf_path: str, output_dir: str): # 输出目录不存在则创建 os.makedirs(output_dir, exist_ok=True) with pdfplumber.open(pdf_path) as pdf: # 遍历所有页面,页码从1开始计数 for page_num, page in enumerate(pdf.pages, start=1): page_img_serial = 1 # 遍历当前页所有内嵌图片对象 for img_meta in page.images: try: # 读取图片原始流数据 raw_stream = img_meta["stream"].get_data() img = Image.open(io.BytesIO(raw_stream)) # 处理SMask透明蒙版,解决透明区域变黑的问题 if "SMask" in img_meta: mask_stream = img_meta["SMask"].get_data() alpha_mask = Image.open(io.BytesIO(mask_stream)).convert("L") if img.mode != "RGBA": img = img.convert("RGBA") img.putalpha(alpha_mask) # 处理CMYK色彩空间转RGB,避免色偏、黑底异常 if img.mode == "CMYK": img = img.convert("RGB") # 按指定规则生成文件名,坐标保留2位小数避免文件名过长 # 注:如果需要PDF原生左下角原点的Y坐标,替换为img_meta["y0"]、img_meta["y1"]即可 x1 = round(img_meta["x0"], 2) x2 = round(img_meta["x1"], 2) y1 = round(img_meta["top"], 2) y2 = round(img_meta["bottom"], 2) file_name = f"image_{page_num}_{page_img_serial}_{x1}_{x2}__{y1}_{y2}.png" # 保存为PNG格式 img.save(os.path.join(output_dir, file_name), format="PNG") page_img_serial += 1 except Exception: # 跳过损坏、无法解析的图片流,对齐PDFBox的容错逻辑 page_img_serial += 1 continue # 调用示例 if __name__ == "__main__": extract_pdf_images("target.pdf", "./extracted_images")
关键问题说明
- 拒绝渲染截图方案:整页渲染后裁剪的方式本质是对页面做二次栅格化,不仅会压缩原图分辨率导致画质下降,还会将同坐标位置的文字、矢量线条一并截取,必然出现文字覆盖图片的问题,本方案直接提取PDF内嵌的原始图片资源,不存在该问题。
- 解决黑底、文字遮挡异常:之前测试pdfminer.six、PyMuPDF出现的黑底问题,核心原因是这类库默认没有正确处理图片附带的SMask透明通道,也没有做CMYK到RGB的正确色彩转换,透明区域被默认填充为黑色;本方案专门补全了这部分处理逻辑,提取效果和Java版PDFBox一致,不会出现这类异常。
- 坐标适配:代码默认使用左上角为原点的页面坐标(和多数PDF预览工具的坐标体系对齐),如果需要使用PDF标准的左下角原点坐标,只需将文件名生成部分的y1、y2替换为
img_meta["y0"]、img_meta["y1"]即可。
内容的提问来源于stack exchange,提问作者peter.murray.rust
相关产品推荐
相关产品推荐

