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

相关推荐
wacsii1 小时前
【Linux进程(一)】Linux 进程初探:操作系统如何管理进程?fork() 为什么返回两次?
linux·运维·服务器
共享家95271 小时前
408 操作系统第一章
服务器·数据库·windows
AI+程序员在路上1 小时前
RV1126B 上支持的模型及全流程应用--从CNN及语音到 LLMVLM 与跨平台选型
linux·c语言·人工智能
默|笙1 小时前
【Linux网络】传输层协议TCP(1)---TCP报文介绍
linux·网络·tcp/ip
相思难忘成疾1 小时前
从零搭建 Kubernetes 1.30 集群:kubeadm 部署一主多从实战(RHEL 9.3 + Docker + flannel)
linux·运维·kubernetes
PellyKoo1 小时前
【docker】cifs卷改smb密码后容器起不来的解决方法
运维·docker·容器
用户4107192013251 小时前
用 systemd 从零做一个系统健康巡检服务:脚本、沙箱与磁盘满排查实战
linux·ubuntu
云飞云共享云桌面1 小时前
1台SolidWorks服务器如何承载10个设计并发?
运维·服务器·网络·3d·制造
未来之窗软件服务2 小时前
WAF负载均衡+蜜罐混淆安全体系-东方仙盟
运维·安全·负载均衡·仙盟创梦ide·东方仙盟·阿雪技术观·网关开发