<div id="js_content">
<p style="text-align: center"><img src="https://beijingoptbbs.oss-cn-beijing.aliyuncs.com/cs/5606289-074e34cb930e0a329e577c25a542a124"></p>
<p>相信大家对<code>python-docx</code>这个常用的操作<code>docx</code>文档的库都不陌生,它支持以内联形状(Inline Shape)的形式插入图片,即图片和文本之间没有重叠,遵循流动版式(flow layout)。但是,截至最新的<code>0.8.10</code>版本,<code>python-docx</code>尚不支持插入浮动图片(floating picture)。这显然不能满足丰富多彩的文档样式的需要,因此本文探究基于<code>python-docx</code>插入浮动图片——剖析xml、追踪源码,最后得到完整代码。</p>
<h2>问题提出</h2>
<p>作者在尝试实现PDF文档转docx(pdf2docx:https://github.com/dothinking/pdf2docx,开发中)的过程中遇到一个需求:根据背景图片在PDF页面的具体位置(例如左上角坐标和图片区域的长宽),将其重现到docx页面的相应位置。考虑到背景图片与文本的重叠,这就需要实现精确定位的浮动图片,参考下图示例。</p>
<p style="text-align: center"><img src="https://beijingoptbbs.oss-cn-beijing.aliyuncs.com/cs/5606289-954fd7844bf504cf72284fbccf59d7d7"></p>
<h2>Word中的设置</h2>
<p>我们先尝试在Office Word中,手动解决上述问题。具备基础的Word使用经验即可知,通过设置<strong>图片版式</strong>来控制图片的浮动和具体位置。</p>
<p style="text-align: center"><img src="https://beijingoptbbs.oss-cn-beijing.aliyuncs.com/cs/5606289-871f9d7210c5dac5624bef8101bc4848"></p>
<p>上图版式设置中的文本环绕样式,大体可以分为三类:</p>
<p></p>
<table><thead><tr><th>分类</th><th>文本重叠</th><th>自由定位</th><th>样式名称</th></tr></thead><tbody><tr><td>嵌入型</td><td>否</td><td>否</td><td>In line with text</td></tr><tr><td>环绕型</td><td>否</td><td>是</td><td>Square, Tight, Through, Top and bottom</td></tr><tr><td>完全浮动</td><td>是</td><td>是</td><td>behind text, In front of text</td></tr></tbody></table>
<p></p>
<p>例如最常见的嵌入型图片,它占据了整行区域,我们既不能将其与文字重叠,也不能自由放置它的位置,而是由页面排版自动确定。对于环绕型图片,文本可以进入图片所在行,但是无法与之重叠;并且,我们可以用鼠标自由拖动其位置。完全浮动型图片则可以浮于文本上方或者衬于文本下方,同时支持随意放置其位置。</p>
<p>如果需要精确定位,则可在图片版式的位置(Position)选项卡进行设置。它提供了多种定位方式,例如<strong>绝对定位</strong>——根据图片左上角点距离水平和竖直参考的坐标值来定位。至于参考对象,可以是页面(Page)本身,这样<code>(0, 0)</code>就是页面左上角;也可以是边距(Margin),此时<code>(0, 0)</code>即为正文区域的左上角。</p>
<p>综上,我们需要实现<strong>精确定位</strong>的<strong>衬于文本下方</strong>的图片版式。</p>
<h2>docx背后的xml</h2>
<p>我们还知道,docx文档的背后是xml格式的数据,<code>python-docx</code>正是通过处理xml的方式来读写word文档。所以,接下来先手工创建word文档,然后查看图片部分的xml内容。</p>
<p>作为对比,首先分别创建一个普通嵌入型图片文件和一个衬于文本下方的浮动型图片文件。然后执行查看步骤:右键docx文件 | 7-zip打开压缩包 | word | document.xml,复制文件内容并格式化xml,得到如下的关于图片部分的片段。为了便于对比分析,删除了一些节点属性。</p>
<p>内联图片片段:</p>
<pre class="blockcode"><code class="language-go"><w:drawing>
<wp:inline>
<wp:extent cx="3297600" cy="2782800"/>
<wp:effectExtent l="0" t="0" r="0" b="0"/>
<wp:docPr id="1" name="Picture 1"/>
<wp:cNvGraphicFramePr>
<a:graphicFrameLocks/>
</wp:cNvGraphicFramePr>
<a:graphic>
<a:graphicData>
<pic:pic>
<!-- more pic content -->
</pic:pic>
</a:graphicData>
</a:graphic>
</wp:inline>
</w:drawing>
</code></pre>
<p>浮动图片片段:</p>
<pre class="blockcode"><code class="language-go"><w:drawing>
<wp:anchor behindDoc="1" locked="0" layoutInCell="1" allowOverlap="1">
<wp:simplePos x="0" y="0"/>
<wp:positionH relativeFrom="page">
<wp:posOffset>285750</wp:posOffset>
</wp:positionH>
<wp:positionV relativeFrom= |
|