You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用pikepdf从PDF的Image XObject创建PIL.Image对象

解决PDF Image XObject转PIL.Image的问题

问题根源

PDF中的Image XObject不是标准图像格式(如PNG/JPG),它仅包含原始像素数据,并附带PDF特有的编码滤镜、颜色空间定义,直接用Image.open()读取会因为缺少文件头、不识别PDF颜色空间而报错。

解决方案步骤

  1. 解码PDF图像流:先处理FlateDecode等压缩滤镜,得到原始像素数据
  2. 解析图像参数:提取宽度、高度、位深、颜色空间等信息
  3. 适配颜色空间:将PDF的Indexed/ICCBased等颜色空间转换为PIL支持的RGB/灰度模式
  4. 构建PIL图像:用Image.frombytes()从原始像素数据创建图像

完整代码实现

import pikepdf
from PIL import Image

with pikepdf.open("./doc.pdf") as pdf:
    for page in pdf.pages:
        for image_key, image_data in page.images.items():
            # 解码PDF图像流,自动处理FlateDecode等滤镜
            decoded_pixel_data = image_data.decode()
            img_metadata = image_data.as_dict()
            
            # 提取核心图像参数
            width = img_metadata["/Width"]
            height = img_metadata["/Height"]
            bits_per_component = img_metadata["/BitsPerComponent"]
            
            # 处理Indexed颜色空间(你的示例中是这种情况)
            color_space = img_metadata["/ColorSpace"]
            if color_space[0] == "/Indexed":
                # 获取索引查找表的解码数据(每个索引对应3字节RGB)
                lookup_stream = color_space[3]
                lookup_table = lookup_stream.decode()
                
                # 4位深度:每个字节包含两个像素索引,转换为RGB像素
                rgb_pixels = []
                for byte in decoded_pixel_data:
                    # 拆分高4位和低4位的索引
                    idx_high = (byte >> 4) & 0x0F
                    idx_low = byte & 0x0F
                    # 从查找表中取出对应RGB值
                    rgb_pixels.extend(lookup_table[idx_high*3 : (idx_high+1)*3])
                    rgb_pixels.extend(lookup_table[idx_low*3 : (idx_low+1)*3])
                
                # 创建RGB模式的PIL图像
                img = Image.frombytes("RGB", (width, height), bytes(rgb_pixels))
            else:
                # 适配其他常见颜色空间(如DeviceRGB/DeviceGray)
                pil_mode = "RGB" if bits_per_component == 8 else "L"
                img = Image.frombytes(pil_mode, (width, height), decoded_pixel_data)
            
            # 无损PNG压缩保存(compress_level=0为无损)
            img.save(f"{image_key}_extracted.png", "PNG", optimize=True, compress_level=0)

关键说明

  • 解码流:必须用image_data.decode()替代get_raw_stream_buffer(),后者返回的是未解压的原始PDF流,无法被PIL识别。
  • 颜色空间处理:PDF的Indexed颜色空间需要手动将索引映射为RGB值,PIL不原生支持这种PDF特有的颜色模式。
  • 图像创建:用Image.frombytes()而非Image.open(),因为前者直接处理原始像素数据,不需要标准图像文件头。

内容的提问来源于stack exchange,提问作者eigenVector5

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 11:52:35