Docling DOCX 图片转换实战分组与未分组图片的解析、DoclingDocument 结构与 Ground Truth 验证【免费下载链接】doclingGet your documents ready for gen AI项目地址: https://gitcode.com/GitHub_Trending/do/docling本文以 Docling 仓库中的测试基准文件tests/data/docx/groundtruth/docx_grouped_images.docx.md为主体围绕“Word 文档中的图片含分组图片如何被转换为 Docling 结构”这一具体主题展开你将理解该基准 Markdown 中每一行!-- image --占位符的来历、对应DoclingDocumentJSON 中groups/pictures的父子引用关系以及 msword_backend.py 中_handle_pictures的父节点决策逻辑并学会用配套测试与源码复现、验证这一转换行为。1. 基准文档在仓库中的位置docx_grouped_images.docx.md不是用户文档而是 Docling DOCX 转换链路的ground truth预期输出文件。三件套文件构成一个完整的最小验证用例角色路径待转换的 Word 源文件docx_grouped_images.docx预期 Markdown 输出docx_grouped_images.docx.md预期 DoclingDocument JSONdocx_grouped_images.docx.json源文件刻意覆盖了两类典型排布同一位置的多张图片分组与分散在不同段落中的图片未分组其中部分图片使用 Word 的 “Top and bottom” 环绕方式部分为 “In line with text” 行内方式。这类排布是 DOCX 后端图片处理逻辑最容易产生歧义的场景因此非常适合作为回归基准。2. 基准 Markdown 的完整内容与含义基准 Markdown 文件全文如下这是转换docx_grouped_images.docx后export_to_markdown()的期望产物图片位置以 HTML 注释!-- image --占位## Grouped images !-- image -- !-- image -- There are 2 pictures grouped together !-- image -- !-- image -- There are 2 pictures ungrouped, each wrapped Top and bottom ## Ungrouped images There are 2 pictures ungrouped, each wrapped In line with text in different paragraphs !-- image -- !-- image --逐段解读## Grouped images/## Ungrouped imagesWord 中的两个标题段落被识别为section_header文本项第 12 个!-- image --两张在源文档中成组的图片紧接其说明文字 “There are 2 pictures grouped together”第 34 个!-- image --两张未分组、各自使用 “Top and bottom” 环绕的图片对应说明文字 “There are 2 pictures ungrouped, each wrapped Top and bottom”第 56 个!-- image --两张行内in line with text且位于不同段落的图片。!-- image --这一占位符并非猜测测试代码中对export_to_markdown()的输出明确统计了该标记的出现次数见 test_backend_msword.py 中assert with_picture.count(!-- image --) 1的同类断言。同时从 document.py 的结构看Docling 在反向解析 Markdown 类文本时会先用正则re.sub(r!--(.*?)--, , content_str, ...)剥离 HTML 注释document.py 有同样处理即该占位符主要服务于“可人读的中间表示”重新导入时会被安全忽略。3. 对应的 DoclingDocument JSON 结构基准 JSONdocx_grouped_images.docx.json声明schema_name: DoclingDocument版本1.10.0origin.mimetype为application/vnd.openxmlformats-officedocument.wordprocessingml.document。它的节点组织方式恰好解释了 Markdown 中每张图片的“归属”#/groups/0name: header-0、label: section是文档主体的唯一顶层分组其children引用#/texts/0“Grouped images”与#/texts/3“Ungrouped images”两个section_header文本项#/texts/0与#/texts/3label: section_header、level: 1即两个标题#/groups/1与#/groups/2name: group、label: picture_areaparent均指向#/texts/0——这是“分组图片”在树中的落点。groups/1收纳#/pictures/0、#/pictures/1前两张成组图片groups/2收纳#/pictures/2、#/pictures/3两张 “Top and bottom” 环绕图片#/pictures/4与#/pictures/5parent直接指向#/texts/3“Ungrouped images” 标题节点即两张行内图片没有经过picture_area分组直接挂在所在段落节点之下每个pictures项携带image.mimetype: image/png、dpi: 72、size111×111 或 102×102以及 base64 编码的uri: data:image/png;base64,...说明后端在导出 JSON 时会把原始位图内嵌进文档树tables、key_value_items、form_items、pages均为空因为源文档只有标题、正文与图片。这套self_ref/$ref的父子引用结构正是后文后端代码“先决定 parent再挂 picture”逻辑的直接产物。4. 源码解析_handle_pictures如何决定图片的父节点DOCX 后端的图片处理核心是 msword_backend.py 中的_handle_pictures。关键分支在 msword_backend.pylevel self._get_level() parent: NodeItem | None ( self.parents[level - 1] if len(drawing_blip) 1 else doc.add_group( labelGroupLabel.PICTURE_AREA, parentself.parents[level - 1], content_layerself.content_layer, ) )规则非常清晰且与第 3 节的 JSON 结构一一对应同一元素内只有一张图片len(drawing_blip) 1直接以当前遍历栈中的父节点self.parents[level - 1]作为图片 parent——这解释了#/pictures/4、#/pictures/5为什么直接挂在#/texts/3之下它们是行内单图段落同一元素内有多张图片调用doc.add_group(labelGroupLabel.PICTURE_AREA, ...)新建一个picture_area分组把多张图收进同一个 group——这解释了#/groups/1、#/groups/2两个label: picture_area节点的存在。入口在文档线性遍历_walk_linear的图片分支msword_backend.py当元素命中drawing_blipDrawingML 的a:blip关系时调用_handle_pictures若该段落内还有w:t文本则图片之后继续处理文字保证“图片 说明文字”的顺序不丢失。5. 图片加载与渲染兜底拿到 blip 元素后_handle_pictures对每张图片执行三步msword_backend.py关系取数_get_image_from_relationship(image, {…relationships}embed, image)按 Office 文档关系表取出原始字节Pillow 解码 PNG 归一化Image.open(BytesIO(...))后再save(test_bytes, formatPNG)重读一次——这是一次“可用性探测”对 PIL 无法渲染的 WMF/EMF 会在此抛UnidentifiedImageError或OSErrorLibreOffice 兜底渲染若直读失败则走_convert_elements_via_docx(image, [drawing, pict])msword_backend.py构造一个只含该图形的临时 DOCX经 LibreOffice 转 PDF 再渲染成 PNG。同类逻辑也用于 VML 遗留图片msword_backend.py 的_handle_vml_pictures并且在该路径的兜底失败时会提示 “Install LibreOffice for better VML/EMF/WMF support”。每张图片入库前还会经_is_invisible_spacer(pil_image)判定是否为不可见占位图spacer再由_add_picture_to_doc(doc, parent, pil_image, is_spacer...)生成RefItem。基准 JSON 中所有pictures项的captions、references、footnotes、annotations均为空数组对应源文档图片没有附加题注的事实。6. 测试验证test_handle_pictures的断言逻辑该用例的自动化验证位于 test_backend_msword.pydef test_handle_pictures(documents): Test the function _handle_pictures. name docx_grouped_images.docx doc next(item[1] for item in documents if item[0].name name) assert len(doc.pictures) 6 assert isinstance(doc.pictures[0].parent.resolve(doc), GroupItem) assert doc.pictures[0].parent doc.pictures[1].parent assert isinstance(doc.pictures[2].parent.resolve(doc), GroupItem) assert doc.pictures[2].parent doc.pictures[3].parent assert isinstance(doc.pictures[4].parent.resolve(doc), SectionHeaderItem) assert doc.pictures[4].parent doc.pictures[5].parent六条断言把第 4 节的实现规则完整固化了下来全图 6 张第 1、2 张与第 3、4 张的 parent 分别各自相同且解析后是GroupItem即picture_area分组第 5、6 张的 parent 相同且解析为SectionHeaderItem挂在所在段落的文本节点下无分组包装。如果你的改动例如调整GroupLabel.PICTURE_AREA的创建条件破坏了“多图成组、单图不分组”的约定这个测试会首先报错。7. 复现转换从 docx 到 Markdown / JSON结合基准文件与后端实现复现步骤如下以下均为运行方式说明不涉及修改仓库方式一Python API与测试同构from docling.document_converter import DocumentConverter from docling.datamodel.base_models import InputFormat converter DocumentConverter(allowed_formats[InputFormat.DOCX]) result converter.convert(tests/data/docx/sources/docx_grouped_images.docx) print(result.document.export_to_markdown()) # 期望与 groundtruth 中的 .md 内容一致 print(result.document.export_to_dict()) # DoclingDocument JSON 结构export_to_markdown()的输出应与 docx_grouped_images.docx.md 的 21 行内容一致6 处!-- image --、两段说明文字、两个##标题JSON 序列化后应能对上 docx_grouped_images.docx.json 中groups/pictures/texts的引用关系。方式二CLI仓库提供 cli/main.py 命令行入口docling可执行命令对 docx 输入默认产出 Markdown 与 JSON 两个工件可与 groundtruth 目录逐文件比对。注意事项若源 docx 含 EMF/WMF/VML 图片Pillow 直读会失败并回落到 LibreOffice 渲染链路环境缺少 LibreOffice 时此类图片可能缺失或告警见 msword_backend.py 的提示与 msword_backend.py 中对DOCLING_LIBREOFFICE_CMD的提示而基准用例使用的 PNG 位图不受影响若用docling的 Markdown 解析器反向读取该基准 .md!-- image --注释会被正则剥离document.py这是设计行为而非缺陷。8. 小结docx_grouped_images.docx.md这个 21 行的基准文件浓缩了 Docling DOCX 后端图片处理的三条核心约定单图直挂当前段落节点、多图经PICTURE_AREA分组归拢、位图内嵌进pictures节点并做 PNG 归一化。基准 Markdown可读产物、基准 JSON结构化产物与test_handle_pictures断言产物三者互相印证构成一条从 源文件 到 msword_backend.py 再到 测试 的完整可追溯证据链也是理解 Docling“布局树 引用型节点”文档模型的极佳入口。【免费下载链接】doclingGet your documents ready for gen AI项目地址: https://gitcode.com/GitHub_Trending/do/docling创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考