Python-docx处理图片的3个隐藏技巧与1个常见大坑(附提取图片完整代码)

张开发
2026/4/19 16:44:18 15 分钟阅读

分享文章

Python-docx处理图片的3个隐藏技巧与1个常见大坑(附提取图片完整代码)
Python-docx图片处理实战3个高阶技巧与1个深度解决方案在自动化办公和文档处理领域Python-docx库已经成为处理Word文档的事实标准。但当你真正深入项目实战时会发现这个看似简单的库藏着不少技术暗礁——尤其是图片处理部分。很多开发者都能完成基础的图片插入和大小调整但当遇到需要精确控制图片位置、批量提取文档图片或处理特殊类型的内嵌对象时往往陷入反复试错的泥潭。1. 类型判定精准识别文档中的图片对象处理Word文档时最令人头疼的问题之一就是区分真正的图片和其他视觉元素。官方文档轻描淡写提到的InlineShape对象实际上隐藏着关键的类型判定逻辑。from docx import Document doc Document(complex_report.docx) for shape in doc.inline_shapes: if shape.type 3: # 标准图片类型 print(f发现图片宽度{shape.width.cm}cm) elif shape.type 12: # 图表类型 print(警告检测到图表对象) elif shape.type 4: # 链接图片 print(注意文档包含外部链接图片)类型判定对照表类型常量数值说明PICTURE3标准嵌入图片LINKED_PICTURE4外部链接图片CHART12Excel图表对象SMART_ART15SmartArt图形NOT_IMPLEMENTED-6未支持的对象类型实际项目中我发现一个关键细节当文档包含从Excel复制的图表时type12的对象可能同时包含图片和图表数据。这时需要结合shape._inline.graphic.graphicData中的URI属性进一步判断if chart in shape._inline.graphic.graphicData.uri: # 确认是图表而非图片2. 动态缩放保持图片比例的黄金算法很多教程教你直接设置width和height属性但这往往导致图片变形。经过多次项目实践我总结出一个保持比例的可靠方法def add_scaled_picture(doc, image_path, target_width): 智能缩放图片保持原始比例 from PIL import Image import io # 先用PIL获取原始尺寸 with Image.open(image_path) as img: orig_width, orig_height img.size ratio orig_height / orig_width # 插入图片并设置目标宽度 run doc.add_paragraph().add_run() picture run.add_picture(image_path, widthtarget_width) # 计算并设置精确高度 picture.height int(target_width * ratio) return picture注意在Linux服务器环境可能缺少PIL库可以用python-docx自带的尺寸计算替代picture run.add_picture(image_path) orig_width picture.width picture.width target_width picture.height int(picture.height * (target_width / orig_width))3. 精确定位通过段落样式控制图片布局图片位置控制是另一个容易踩坑的点。不同于文字可以直接设置对齐方式图片的位置受多重因素影响段落对齐基础但有效的方法from docx.enum.text import WD_PARAGRAPH_ALIGNMENT para doc.add_paragraph() para.add_run().add_picture(demo.png) para.alignment WD_PARAGRAPH_ALIGNMENT.CENTER制表位技巧实现复杂布局# 设置右对齐制表位 section doc.sections[0] tab_stops section.footer.paragraphs[0].paragraph_format.tab_stops tab_stops.add_tab_stop(Inches(6), WD_TAB_ALIGNMENT.RIGHT) # 在制表位插入图片 para doc.add_paragraph() para.add_run(\t) # 插入制表符 para.add_run().add_picture(logo.png)表格布局法最稳定的定位方案table doc.add_table(rows1, cols2) # 左侧单元格放文字 table.cell(0, 0).text 产品示意图 # 右侧单元格放图片 para table.cell(0, 1).paragraphs[0] para.add_run().add_picture(product.png)4. 图片提取逆向工程解构Word文件这才是真正的技术深水区——python-docx官方并未提供图片提取API。经过对多个失败案例的分析我开发出一个健壮的解决方案import os import zipfile from xml.etree import ElementTree as ET from docx import Document def extract_images(docx_path, output_dir): 从Word文档提取所有图片到指定目录 os.makedirs(output_dir, exist_okTrue) # 临时解压docx文件 with zipfile.ZipFile(docx_path) as z: # 解析document.xml获取图片引用 with z.open(word/document.xml) as f: tree ET.parse(f) ns { a: http://schemas.openxmlformats.org/drawingml/2006/main, r: http://schemas.openxmlformats.org/officeDocument/2006/relationships } img_refs { el.get({ ns[r] }embed): el for el in tree.findall(.//a:blip, ns) } # 提取图片二进制数据 for rel_id in img_refs: img_path fword/media/{rel_id}.jpeg # 大部分情况是jpeg try: with z.open(img_path) as img_file: with open(os.path.join(output_dir, f{rel_id}.jpeg), wb) as f: f.write(img_file.read()) except KeyError: # 尝试png格式 img_path fword/media/{rel_id}.png with z.open(img_path) as img_file: with open(os.path.join(output_dir, f{rel_id}.png), wb) as f: f.write(img_file.read())这个方案的优势在于不依赖python-docx内部实现直接解析docx的ZIP结构自动处理JPEG和PNG格式的图片保留原始图片质量避免二次编码损失性能优化版处理大型文档时可以添加图片去重和并行处理from concurrent.futures import ThreadPoolExecutor def extract_images_optimized(docx_path, output_dir): # ...前面的解压和解析代码相同 # 使用线程池并行提取 with ThreadPoolExecutor(max_workers4) as executor: futures [] for rel_id in set(img_refs.keys()): # 去重 futures.append(executor.submit(save_image, z, rel_id, output_dir)) for future in futures: future.result() # 等待所有任务完成 def save_image(zip_file, rel_id, output_dir): # 实际的图片保存逻辑 # ...同上实战中的经验教训在金融报告自动化项目中我遇到过一个棘手案例客户上传的Word文档中包含从不同系统导出的图片有些是EMF矢量图有些是屏幕截图的PNG。这时标准的图片处理方法会失效必须结合文件类型检测def detect_image_type(blob): 通过文件头判断图片类型 if blob.startswith(b\x89PNG): return png elif blob.startswith(b\xff\xd8): return jpg elif blob.startswith(bBM): return bmp elif blob.startswith(b\x01\x00\x00\x00): # EMF头 return emf else: return unknown处理这类混合格式文档时建议先将所有媒体文件提取到临时目录再根据实际类型分别处理。对于EMF等矢量图可能需要使用专门的转换工具转为位图后再继续处理。

更多文章