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

相关推荐
xuhe21 分钟前
[重磅更新] 支持最新 Overleaf 6.x!我的私有化部署方案 xuhe2/sharelatex-ce 迎来大升级
linux·docker·github·科研·overleaf
zhuzewennamoamtf4 分钟前
Linux驱动实现DMA支持
linux·spring boot·spring
一个平凡而乐于分享的小比特7 分钟前
硬链接(ln) vs 复制(cp)的详细区别
linux·复制·硬链接·cp·ln
可口码农7 分钟前
Kwrt软路由从“路由模式”改为“交换机模式”,再改为旁路由模式接管 DHCP 的透明网关模式。
运维·服务器
奶油话梅糖9 分钟前
解决Windows SSH无法连接老旧网络设备(路由器交换机)
运维·windows·ssh
源代码•宸10 分钟前
goframe框架签到系统项目开发(用户认证、基于 JWT 实现认证、携带access token获取用户信息)
服务器·开发语言·网络·分布式·后端·golang·jwt
郝学胜-神的一滴12 分钟前
Linux 多线程编程:深入理解 `pthread_join` 函数
linux·开发语言·jvm·数据结构·c++·程序人生·算法
广州服务器托管13 分钟前
[2025.12.25] Win10.LTSC2021极速响应养老版19045.3208轻精简全功能【可更新】PIIS出品 老电脑福利 老旧电脑流畅运行
运维·人工智能·计算机网络·云计算·电脑·可信计算技术
半壶清水19 分钟前
ubuntu中PHP升级详细方法
linux·ubuntu·php
刺客xs19 分钟前
TCP服务器并发编程
服务器·网络协议·tcp/ip