复制 .docx 并保留图像
Copying .docx and preserving images
我正在尝试将一个文档的元素从一个文档文件复制到另一个文档文件。文字部分很简单,图像是它变得棘手的地方。
附上一张图片来解释文档的结构:只有一些文字和一张图片。
from docx import Document
import io
doc = Document('/Users/neha/Desktop/testing.docx')
new_doc = Document()
for elem in doc.element.body:
new_doc.element.body.append(elem)
new_doc.save('/Users/neha/Desktop/out.docx')
这让我了解了 new_doc
中文档的整个结构,但图像仍然是空白的。下图:
幸好我的空白图像在正确的位置,所以我想从以前的图像中获取字节级数据并将其插入到新文档中。下面是我如何扩展上面的代码:
from docx import Document
import io
doc = Document('/Users/neha/Desktop/testing.docx')
new_doc = Document()
for elem in doc.element.body:
new_doc.element.body.append(elem)
im = doc.inline_shapes[0]
blip = im._inline.graphic.graphicData.pic.blipFill.blip
rId = blip.embed
doc_part = doc.part
image_part = doc_part.related_parts[rId]
bytes = image_part._blob #Here I get the byte level data for the image
im2 = new_doc.inline_shapes[0]
blip2 = im2._inline.graphic.graphicData.pic.blipFill.blip
rId2 = blip2.embed
document_part2 = new_doc.part
document_part2.related_parts[rId2]._blob = bytes
new_doc.save('/Users/neha/Desktop/out.docx')
但图像在new_doc
中仍然显示为空。我应该从这里做什么?
你可以试试:
- 通过解压缩 .docx 文件从第一个文档中提取图像(根据 How can I search a word in a Word 2007 .docx file?)
- 将这些图像保存到文件系统(例如
foo.png
)
- 使用 Python 生成新的 .docx 文件并使用
document.add_picture('foo.png')
添加 .png 文件。
几天前我想出了一个解决方案。然而,文本使用这种方式丢失了格式,但图像放置正确。
所以想法是,对于 paras
中的 para
对于 source
文档,如果有文本,我将其写入 dest
文档。如果存在内联图像,我会在 dest
文档中的那个位置添加一个唯一标识符(请参阅 here 以了解这些标识符的工作原理,以及 docxtpl
中的上下文)。这些标识符和 docxtpl
被证明在这里特别有用。然后使用这些唯一标识符我创建了一个 'context'(如下所示),它基本上是一个将唯一标识符映射到其特定 InlineImage
的映射,最后我 render
这个上下文..
下面是我的代码(为不必要的缩进道歉,我直接从我的文本编辑器复制它,shift+tab
在这里不起作用:P)
from docxtpl import DocxTemplate, InlineImage
import Document
import io
import xml.etree.ElementTree as ET
dest = DocxTemplate()
source = Document(source_path)
context = {}
ims = [im for im in source.inline_shapes]
im_addresses = []
im_streams = []
count = 0
for im in ims:
blip = im._inline.graphic.graphicData.pic.blipFill.blip
rId = blip.embed
doc_part = source.part
image_part = doc_part.related_parts[rId]
byte_data = image_part._blob
image_stream = io.BytesIO(byte_data)
im_streams.append(image_stream)
image_name = self.img_path+"img_"+"_"+str(count)+".jpeg"
with open(image_name, "wb") as fh:
fh.write(byte_data)
fh.close()
im_addresses.append(image_name)
count += 1
paras = source.paragraphs
im_idx = 0
for para in paras:
p = dest.add_paragraph()
r = p.add_run()
if(para.text):
r.add_text(para.text)
root = ET.fromstring(para._p.xml)
namespace = {'wp':"http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"}
inlines = root.findall('.//wp:inline',namespace)
if(len(inlines) > 0):
uid = "img_"+str(im_idx)
r.add_text("{{ " + uid + " }}")
context[uid] = InlineImage(dest,im_addresses[im_idx])
im_idx += 1
try:
dest.render(context)
except Exception as e:
print(e)
dest.save(dest_path)
PS:如果一个段落有两个图像,这个代码将被证明是次优的。必须在下面做一些改变:
if(len(inlines) > 0):
uid = "img_"+str(im_idx)
r.add_text("{{ " + uid + " }}")
context[uid] = InlineImage(dest,im_addresses[im_idx])
im_idx += 1
还必须在 if
语句中添加一个 for
循环。因为我不需要像往常一样我的图像足够大,所以它们总是出现在不同的段落中。只是给可能需要它的人的旁注..
干杯!
我正在尝试将一个文档的元素从一个文档文件复制到另一个文档文件。文字部分很简单,图像是它变得棘手的地方。 附上一张图片来解释文档的结构:只有一些文字和一张图片。
from docx import Document
import io
doc = Document('/Users/neha/Desktop/testing.docx')
new_doc = Document()
for elem in doc.element.body:
new_doc.element.body.append(elem)
new_doc.save('/Users/neha/Desktop/out.docx')
这让我了解了 new_doc
中文档的整个结构,但图像仍然是空白的。下图:
幸好我的空白图像在正确的位置,所以我想从以前的图像中获取字节级数据并将其插入到新文档中。下面是我如何扩展上面的代码:
from docx import Document
import io
doc = Document('/Users/neha/Desktop/testing.docx')
new_doc = Document()
for elem in doc.element.body:
new_doc.element.body.append(elem)
im = doc.inline_shapes[0]
blip = im._inline.graphic.graphicData.pic.blipFill.blip
rId = blip.embed
doc_part = doc.part
image_part = doc_part.related_parts[rId]
bytes = image_part._blob #Here I get the byte level data for the image
im2 = new_doc.inline_shapes[0]
blip2 = im2._inline.graphic.graphicData.pic.blipFill.blip
rId2 = blip2.embed
document_part2 = new_doc.part
document_part2.related_parts[rId2]._blob = bytes
new_doc.save('/Users/neha/Desktop/out.docx')
但图像在new_doc
中仍然显示为空。我应该从这里做什么?
你可以试试:
- 通过解压缩 .docx 文件从第一个文档中提取图像(根据 How can I search a word in a Word 2007 .docx file?)
- 将这些图像保存到文件系统(例如
foo.png
) - 使用 Python 生成新的 .docx 文件并使用
document.add_picture('foo.png')
添加 .png 文件。
几天前我想出了一个解决方案。然而,文本使用这种方式丢失了格式,但图像放置正确。
所以想法是,对于 paras
中的 para
对于 source
文档,如果有文本,我将其写入 dest
文档。如果存在内联图像,我会在 dest
文档中的那个位置添加一个唯一标识符(请参阅 here 以了解这些标识符的工作原理,以及 docxtpl
中的上下文)。这些标识符和 docxtpl
被证明在这里特别有用。然后使用这些唯一标识符我创建了一个 'context'(如下所示),它基本上是一个将唯一标识符映射到其特定 InlineImage
的映射,最后我 render
这个上下文..
下面是我的代码(为不必要的缩进道歉,我直接从我的文本编辑器复制它,shift+tab
在这里不起作用:P)
from docxtpl import DocxTemplate, InlineImage
import Document
import io
import xml.etree.ElementTree as ET
dest = DocxTemplate()
source = Document(source_path)
context = {}
ims = [im for im in source.inline_shapes]
im_addresses = []
im_streams = []
count = 0
for im in ims:
blip = im._inline.graphic.graphicData.pic.blipFill.blip
rId = blip.embed
doc_part = source.part
image_part = doc_part.related_parts[rId]
byte_data = image_part._blob
image_stream = io.BytesIO(byte_data)
im_streams.append(image_stream)
image_name = self.img_path+"img_"+"_"+str(count)+".jpeg"
with open(image_name, "wb") as fh:
fh.write(byte_data)
fh.close()
im_addresses.append(image_name)
count += 1
paras = source.paragraphs
im_idx = 0
for para in paras:
p = dest.add_paragraph()
r = p.add_run()
if(para.text):
r.add_text(para.text)
root = ET.fromstring(para._p.xml)
namespace = {'wp':"http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"}
inlines = root.findall('.//wp:inline',namespace)
if(len(inlines) > 0):
uid = "img_"+str(im_idx)
r.add_text("{{ " + uid + " }}")
context[uid] = InlineImage(dest,im_addresses[im_idx])
im_idx += 1
try:
dest.render(context)
except Exception as e:
print(e)
dest.save(dest_path)
PS:如果一个段落有两个图像,这个代码将被证明是次优的。必须在下面做一些改变:
if(len(inlines) > 0):
uid = "img_"+str(im_idx)
r.add_text("{{ " + uid + " }}")
context[uid] = InlineImage(dest,im_addresses[im_idx])
im_idx += 1
还必须在 if
语句中添加一个 for
循环。因为我不需要像往常一样我的图像足够大,所以它们总是出现在不同的段落中。只是给可能需要它的人的旁注..
干杯!