PPTX数据格式的更换图片

2) 推荐且兼容的实现(最终代码

下面函数不依赖 ImagePart.from_blob,使用 Image.from_blob + ImagePart.new,并且包含完整断点输出 (你可以在这些处下断点或查看日志),以及安全删除旧关系 的逻辑(避免直接 ._rels.pop 导致 package 被污染)。

把它直接拷到你的项目里运行(记得把路径改成你本地的):

复制代码

import os from pptx.opc.constants import RELATIONSHIP_TYPE as RT from pptx.oxml.ns import qn # 这两个类来自 python-pptx from pptx.parts.image import Image as PPTXImage from pptx.parts.image import ImagePart def replace_image_robust(shape, slide_part, image_source, content_type_hint=None): """ Robust image replace: - image_source: 文件路径 (str) 或 bytes - 不依赖 ImagePart.from_blob;使用 Image.from_blob + ImagePart.new - 在关键点打印调试信息(可断点) - 安全地 relate_to(new ImagePart), 更新 blip, 并 drop_rel(old_rId) """ print("\n===== replace_image_robust 开始 =====") # 1) 读取 image blob / 构建 pptx Image 对象 if isinstance(image_source, str): if not os.path.exists(image_source): raise FileNotFoundError(image_source) with open(image_source, "rb") as f: blob = f.read() filename = os.path.basename(image_source) elif isinstance(image_source, (bytes, bytearray)): blob = bytes(image_source) filename = None else: raise TypeError("image_source must be path or bytes") # 创建 pptx.parts.image.Image(通用) img_obj = PPTXImage.from_blob(blob, filename) # DEBUG 断点 A: 检查 image meta print("DBG A: image filename:", getattr(img_obj, "filename", None)) print("DBG A: image content_type:", getattr(img_obj, "content_type", None)) # 2) 用 ImagePart.new(package, image) 构造合法 ImagePart package = slide_part.package image_part = ImagePart.new(package, img_obj) # DEBUG 断点 B: 检查 image_part print("DBG B: image_part type:", type(image_part)) print("DBG B: image_part.partname:", image_part.partname) print("DBG B: image_part.content_type:", getattr(image_part, "content_type", None)) # 3) 把 image_part 关联到 slide_part,得到 new rId new_rId = slide_part.relate_to(image_part, RT.IMAGE) print("DBG C: new_rId:", new_rId) # 4) 更新 shape 的 blip/embed 指向 new rId blips = shape.xpath(".//a:blip") if not blips: raise RuntimeError("can't find <a:blip> inside shape") blip = blips[0] old_rId = blip.get(qn("r:embed")) blip.set(qn("r:embed"), new_rId) print(f"DBG D: old_rId -> new_rId: {old_rId} -> {new_rId}") # 5) 在删除 old rId 前做一次安全检查(不要直接 pop 私有 dict) try: old_rel = slide_part.rels.get(old_rId) except Exception: old_rel = None if old_rel is not None and hasattr(old_rel, "target_part"): # 安全删除 slide_part.drop_rel(old_rId) print("DBG E: dropped old rId:", old_rId) else: print("DBG E: skip dropping old_rId (not found or invalid):", old_rId) # 6) 再打印 slide_part.rels._rels(安全遍历,标出非 str key / 非 _Relationship value) print("\nDBG F: slide_part.rels._rels snapshot:") for k, v in getattr(slide_part.rels, "_rels", {}).items(): k_repr = k if isinstance(k, str) else f"<non-str key {type(k)}>" v_type = type(v) target_part_type = type(getattr(v, "target_part", None)) if v is not None else None print(f" key={k_repr}, rel_type={v_type}, target_part={target_part_type}") print("===== replace_image_robust 结束 =====\n") return new_rId

相关推荐
你好潘先生3 小时前
别再记命令了,用 yeero do 说句人话就能跑脚本,而且不烧 token
服务器·python·命令行
orion5714 小时前
Missing Semester Class1:course overview and introduction of shell
linux
SkyWalking中文站19 小时前
认识 Horizon UI · 6/17:Trace 探索器
运维·监控·自动化运维
用户1204872216121 小时前
Linux驱动编译与加载
linux·嵌入式
程序员老赵1 天前
服务器文件不想 SFTP 上传?Docker 跑个 File Browser,浏览器就能管理
服务器·docker·开源
火车叼位1 天前
写给初级开发者:SSL、SSH、HTTPS 与证书体系全解析
运维
vivo互联网技术1 天前
从 10 分钟到 1 秒:ES 深度分页任意跳页的三轮优化实战
服务器·数据库·redis·elasticsearch·深度分页
用户805533698031 天前
Input 子系统架构:Core、Handler、Driver 三层是怎么协作的
linux·嵌入式
用户805533698031 天前
RK-Forge外设系列开篇 - 把板子从「能启动」变成「能用」:Ethernet/SPI/MMC 三个纯接线外设
linux·github·嵌入式