DOCX Embedded Image Handling#
MinerU extracts images embedded in DOCX files, serializes them to base64 data URIs, and passes them through the Office block pipeline — without applying any OCR to image content. The pipeline is entirely separate from the PDF/image pipeline and runs through three main stages: extraction, serialization, and storage.
Entry Point#
Processing begins in office_docx_analyze(), which calls convert_binary() to invoke the DocxConverter, then passes the resulting page-block lists to result_to_middle_json().
Stage 1: Image Detection and Extraction (DocxConverter)#
DocxConverter uses an XPath expression registered at init time to locate image references in the DOCX XML :
self.picture_xpath_expr = etree.XPath(
".//a:blip | .//v:imagedata", namespaces=...
)
This covers both modern DrawingML (a:blip) and legacy VML (v:imagedata) formats. During _walk_linear(), each top-level body element is checked for picture refs. When found, _handle_pictures() is called.
Inside _handle_pictures() :
- Each picture ref's relationship ID (
r:embedorr:id) is resolved againstself.docx_obj.part.relsto get the image part. - Duplicate relationship IDs within the same element are skipped via a
seen_rel_idsset. - The image part's raw bytes (
.blob) are passed toserialize_office_image(). - The resulting base64 string is stored as
{"type": BlockType.IMAGE, "content": img_base64}and appended toself.cur_page.
For anchored (floating) images inside a paragraph, the text of that paragraph is processed first, then the image — preserving document order .
Images embedded in table cells are handled differently: mammoth pre-parses all top-level tables against the full DOCX package context, converting embedded images to inline data: URI <img src="..."> tags within the table HTML . Those <img> src attributes are preserved through the clean_table_html() step .
Stage 2: Serialization (serialize_office_image)#
serialize_office_image() in mineru/backend/utils/office_image.py handles the full serialization path:
- Vector images (WMF/EMF): Detected by part name extension or content-type . On non-Windows systems, these are replaced with a standard 320×180 gray placeholder reading "WMF/EMF placeholder / Use Windows to parse / the original image" . On Windows, Pillow attempts to render them as PNG .
- Raster images: Loaded via Pillow. If loading fails,
Noneis returned and the block is skipped . - Format normalization:
- RGB images → JPEG
- RGBA/LA images or palette images with transparency → PNG
- All other modes → converted to RGB then JPEG
The output is a standard data URI string via image_to_b64str() (from mineru/utils/pdf_reader.py):
data:image/jpeg;base64,<base64-encoded bytes>
Stage 3: Block Restructuring and Storage#
In MagicModel, raw {"type": "image", "content": <base64>} blocks from the converter are restructured :
span = {
"type": ContentType.IMAGE,
"image_base64": block_content,
}
If an image_writer is provided to blocks_to_page_info(), each image span is written to persistent storage by save_span_image_if_needed() (from html_image_utils.py), which decodes the base64, writes the file, and replaces image_base64 with a local image_path. Without an image_writer, images remain as inline base64 data URIs in the output.
No OCR on Embedded Images#
There is no OCR step for images extracted from DOCX files. Unlike PDF images (which go through the ML model pipeline), DOCX images are passed through purely as pixel data — extracted, format-normalized, serialized to base64, and stored. Any text content within an embedded image is not extracted.
This is a known limitation. A related user report shows that WMF images inside DOCX produce a warning Skipping WMF image part before Pillow load and result in placeholder output rather than any recognized content.
Key Files#
| File | Role |
|---|---|
mineru/model/docx/docx_converter.py | Image detection (_handle_pictures), XPath extraction, block creation |
mineru/backend/utils/office_image.py | serialize_office_image() — Pillow load, format normalization, base64 output |
mineru/backend/office/docx_analyze.py | Pipeline entry point |
mineru/backend/office/model_output_to_middle_json.py | blocks_to_page_info() — image_writer dispatch |
mineru/backend/office/office_magic_model.py | Block restructuring, image_base64 field assignment |