复制.docx并保存图像

时间:2018-08-04 15:49:45

标签: python docx

我正在尝试将一个文档的元素从一个doc文件复制到另一个。文字部分很简单,图像很棘手。 附上图片以解释文档的结构:仅提供一些文字和1张图片。

enter image description here

$ stitch-cli import --project-id=XXX

这使我获得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') 中文档的整个结构,但是图像仍然空白。下图:

enter image description here

好事是我在正确的位置放置了空白图像,因此我想从先前的图像中获取字节级数据并将其插入新文档中。这是我扩展上述代码的方式:

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') 中仍然显示为空白。我应该从这里做什么?

2 个答案:

答案 0 :(得分:1)

您可以尝试:

  1. 通过解压缩.docx文件(每个How can I search a word in a Word 2007 .docx file?)从第一个文档中提取图像
  2. 将这些图像保存到文件系统(例如,以Views的形式)
  3. 使用Python生成新的.docx文件,然后使用foo.png添加.png文件。

答案 1 :(得分:1)

几天前,我想出了一个解决方案。但是,文本会丢失使用这种方式的格式,但是图像放置正确。

这样的想法是,对于para文档中paras中的source,如果有文本,我将其写入dest文档中。并且,如果存在内嵌图像,我会在dest文档中的那个位置添加一个唯一标识符(请参考here来查看这些标识符的工作方式以及docxtpl中的上下文)。这些标识符和docxtpl在这里特别有用。然后使用这些唯一标识符创建一个“上下文”(如下所示),该上下文基本上是将唯一标识符映射到其特定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

还必须在for语句内添加一个if循环。由于我通常不需要图像,因此图像总是位于不同的段落中。只是对可能需要它的人的补充说明。.

干杯!