我正在使用 python-docx 库(https://python-docx.readthedocs.io/)来编写 Word 文档。
我可以使用 python-docx 库的 API 添加嵌入文档中的图片。例如:
from docx import Document
doc = Document()
par = doc.add_paragraph( 'Embed picture:' )
run = par.add_run()
run.add_picture( 'puppy.png' )
doc.save( 'test.docx' )
图片成为存储在文档内的 ImagePart:
word/
media/
image1.png
指向该图像部分的关系是:
<Relationships ...>
...
<Relationship Id="rId4" Type=".../image" Target="media/image1.png"/>
我更愿意添加链接到外部图像文件的图片。您可以在 Microsoft Word 中执行此操作。 python-docx 库没有为此提供方便的 API。然而,一些底层代码似乎支持链接到外部文件
因此,我开始了自己的实用功能,将图片链接到外部文件。例如:
from docx import Document
doc = Document()
par = doc.add_paragraph( 'Link picture:' )
run = par.add_run()
Util.Run_add_picture( run, 'puppy.png', is_external = True )
doc.save( 'test.docx' )
这会导致图片的关系如下所示:
<Relationships ...>
...
<Relationship Id="rId4" Type=".../image" Target="file:///C:\work\puppy.png" TargetMode="External"/>
令我感到鼓舞的是,一些底层代码似乎支持链接到外部文件。例如,
docx.opc.part.Part.relate_to()
有一个 is_external
参数,默认为 false。为 Run.add_picture()
发明我自己的实用程序包装器以及调用的函数似乎是合理的,这样我就可以传递值为 true 的 is_external
参数。
再例如,
docx.oxml.shape.CT_Blip
具有 embed
和 link
属性,如果将关系 ID 分配给后者而不是前者,那么它应该渗透到其他位置并在文档中生成所需的标记。为 docx.oxml.shape.CT_Picture.new()
发明一个实用程序包装器以及调用它的函数似乎是合理的,这样我就可以传递值为 true 的 is_external
参数,然后执行如下操作:
@staticmethod
def CT_Picture_new( pic_id, filename, relationship_id, cx, cy, is_external ):
pic = parse_xml( CT_Picture._pic_xml() )
pic.nvPicPr.cNvPr.id = pic_id
pic.nvPicPr.cNvPr.name = filename
# The important change that pays attention to given is_external parameter.
if is_external:
pic.blipFill.blip.link = relationship_id
else:
pic.blipFill.blip.embed = relationship_id
pic.spPr.cx = cx
pic.spPr.cy = cy
return pic
到目前为止,我有实用函数来代替,并提供了一种指定
is_external
参数的方法,用于:
docx.text.run.Run.add_picture()
docx.parts.story.BaseStoryPart.new_pic_inline()
docx.parts.story.BaseStoryPart.get_or_add_image()
docx.oxml.shape.CT_Inline.new_pic_inline()
docx.oxml.shape.CT_Picture.new()
唉,我保存文档时还是出现异常。
类型错误:参数必须是字节或 unicode,得到“ImagePart”
我认为我必须改变的下一件事是如何填充
Relationship
对象; target_ref
属性只需分配一个外部图像文件的路径,而不是 ImagePart
对象。
我必须暂时放弃。是否有计划支持将图片链接到外部图像文件?或者,更简单的解决方法?
我也有同样的问题。这就是我用里面的评论解决它的方法
from docx.opc.constants import RELATIONSHIP_TYPE
from docx.oxml import CT_Inline, parse_xml, CT_Picture
from docx.shape import InlineShape
from docx.shared import Length
from docx.text.run import Run
# noinspection PyProtectedMember
def add_linked_pic(r: Run, image_path: str, width: Length, height: Length) -> InlineShape:
"""
Image will be inserted as character without embedding, just as link.
:param r: run
:param image_path:
Seems like it has to be absolute path.as_uri() like "file:///full/path/file.jpg".
It seems that it also works with relative path like "./folder/image.jpg"
:param width: size of image in document
:param height: size of image in document
:return:
"""
# create RELATION.
relations = r.part.rels
rel_id = relations._next_rId
relations.add_relationship(reltype=RELATIONSHIP_TYPE.IMAGE, target=image_path, rId=rel_id, is_external=True)
# Comment about pic_id from python-docx creators:
# -- Word doesn't seem to use this, but does not omit it
pic_id = 0
# Next code taken from this method:
# def new(cls, pic_id, filename, rId, cx, cy):
# Just one line changed in order to replace `r:embed` with `r:link`.
# The following fout lines created to make variable names same as in python-docx method.
filename = image_path # Filename - something useless. will make it equal to image_path
cx = width
cy = height
# Expand that code as CT_Picture.new(pic_id, filename, rId, cx, cy):
pic = parse_xml(CT_Picture._pic_xml())
pic.nvPicPr.cNvPr.id = pic_id
pic.nvPicPr.cNvPr.name = filename
# pic.blipFill.blip.embed = rId # This line is replaced with next one
pic.blipFill.blip.link = rel_id
pic.spPr.cx = cx
pic.spPr.cy = cy
shape_id = r.part.next_id
# Now from here: inline = cls.new(cx, cy, shape_id, pic)
inline = CT_Inline.new(cx, cy, shape_id, pic)
inline = r._r.add_drawing(inline)
return InlineShape(inline)