docx/image-inline

An inline image (1x1 PNG) anchored inside a paragraph via <w:drawing><wp:inline>.

Library verdicts: python-docx: — docxjs: pass

Metadata

Feature iddocx/image-inline
Formatdocx
Categoryblock-content
Spececma-376-5-part-1 § 17.3.3.9 w:drawing

XPath assertions

ID / partPredicateXPathpython-docxdocxjs
drawing-element-present
word/document.xml
exist
At least one <w:drawing> element must be present in the body.
//w:drawing
wp-inline-present
word/document.xml
exist
The drawing must use the inline layout variant (wp:inline), not wp:anchor.
//w:drawing//wp:inline

Render assertions

IDPredicateSelectorpython-docxdocxjs
img-element-presentcss_selector/ exist
An <img> element must appear in the rendered DOM.
.docx-wrapper imgpass
img-src-is-embeddedcss_selector/ exist
The rendered <img> must carry an embedded source — either a data:image/ URL (base64-inlined) or a blob: URL (Object URL). Both are valid DOM representations of an image extracted from the docx package; the choice is a renderer-level memory/runtime tradeoff.
.docx-wrapper img[src^='data:image/'], .docx-wrapper img[src^='blob:']pass
img-has-a11y-hookcss_selector/ exist
Accessibility hook: the rendered image must carry some screen-reader-visible signal — an alt attribute (even alt=''), aria-hidden='true' to explicitly mark decorative, aria-label/aria-labelledby to supply a name, a <figure> wrapper, or an explicit role='img'. Accepts any of these conventions; the assertion fails only when NONE are present (the typical renderer-with-zero-a11y case).
.docx-wrapper img[alt], .docx-wrapper img[aria-hidden='true'], .docx-wrapper img[aria-label], .docx-wrapper img[aria-labelledby], .docx-wrapper figure img, .docx-wrapper [role='img']

Generator source

scripts/gen_image_inline.py

#!/usr/bin/env python3
"""Generate ``fixtures/docx/image-inline.docx``.

A minimal document exercising the ``w:drawing`` inline-picture element.
A one-run paragraph embeds a 1x1 white PNG via ``run.add_picture``,
which yields a <w:drawing><wp:inline>... tree. Satisfies the
assertions in ``features/docx/image-inline.json``.

The PNG is written to a tempfile so python-docx's image header parser
(which reads from disk) accepts it. The hex bytes encode a valid
69-byte 1x1 RGB PNG with a deflate-compressed white pixel IDAT chunk.
"""

from __future__ import annotations

import tempfile
from pathlib import Path

from docx import Document
from docx.shared import Inches

_REPO_ROOT = Path(__file__).resolve().parent.parent
_OUT = _REPO_ROOT / "fixtures" / "docx" / "image-inline.docx"

# Valid 1x1 RGB PNG, 69 bytes. Hand-built with zlib-compressed IDAT.
# Byte layout: PNG signature | IHDR (1x1, 8-bit RGB) | IDAT (deflate of
# filter-byte + white RGB triplet) | IEND.
_TINY_PNG_HEX = (
    "89504e470d0a1a0a"
    "0000000d49484452000000010000000108020000009077"
    "53de"
    "0000000c49444154789c63f8ffff3f0005fe02fe0def46b8"
    "0000000049454e44ae426082"
)


def main() -> int:
    png_bytes = bytes.fromhex(_TINY_PNG_HEX)
    # Fixed temp filename (not NamedTemporaryFile) so python-docx's
    # per-image Picture-n pic:cNvPr/@name is deterministic across runs —
    # NamedTemporaryFile produces a random basename which ends up
    # embedded in the docx's XML and defeats reproducible-save.
    tmp_path = Path(tempfile.gettempdir()) / "corpus-image-inline.png"
    tmp_path.write_bytes(png_bytes)

    doc = Document()
    paragraph = doc.add_paragraph()
    paragraph.add_run().add_picture(str(tmp_path), width=Inches(1.0))
    _OUT.parent.mkdir(parents=True, exist_ok=True)
    doc.save(_OUT, reproducible=True)

    tmp_path.unlink(missing_ok=True)
    print(_OUT)
    return 0


if __name__ == "__main__":
    raise SystemExit(main())

Manifest (expanded)

{
  "$schema": "../manifest.schema.json",
  "id": "docx/image-inline",
  "title": "Inline image",
  "format": "docx",
  "category": "block-content",
  "summary": "An inline image (1x1 PNG) anchored inside a paragraph via <w:drawing><wp:inline>.",
  "spec": {
    "source": "ecma-376-5-part-1",
    "clause": "17.3.3.9",
    "element": "w:drawing",
    "rnc_reference": "spec/ecma-376-5/part-1/rnc/WordprocessingML.rnc",
    "xsd_reference": "spec/ecma-376-5/part-1/xsd/wml.xsd",
    "notes": "An inline picture is a <w:drawing> whose child is <wp:inline> (namespace http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing). The inline layout variant flows with text; the alternative is <wp:anchor> for floating positioning.\n\nRenderer note: when projecting an embedded image into the DOM, renderers may set the <img> src to either a data: URL (base64-inlined, self-contained, ~33% size overhead) or a blob: URL (Object URL referencing an in-memory Blob, zero overhead but requires a JS runtime and explicit revokeObjectURL lifecycle). Both are equally valid DOM strategies; choosing one over the other is a legitimate implementation tradeoff (memory footprint vs. runtime coupling). The render assertion accepts either."
  },
  "fixtures": {
    "machine": "docx/image-inline",
    "office": "docx/image-inline"
  },
  "generator": {
    "python": "scripts/gen_image_inline.py"
  },
  "assertions": [
    {
      "id": "drawing-element-present",
      "part": "word/document.xml",
      "namespaces": {
        "w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
      },
      "xpath": "//w:drawing",
      "must": "exist",
      "description": "At least one <w:drawing> element must be present in the body."
    },
    {
      "id": "wp-inline-present",
      "part": "word/document.xml",
      "namespaces": {
        "w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
        "wp": "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"
      },
      "xpath": "//w:drawing//wp:inline",
      "must": "exist",
      "description": "The drawing must use the inline layout variant (wp:inline), not wp:anchor."
    }
  ],
  "render_assertions": [
    {
      "id": "img-element-present",
      "kind": "css_selector",
      "selector": ".docx-wrapper img",
      "must": "exist",
      "description": "An <img> element must appear in the rendered DOM."
    },
    {
      "id": "img-src-is-embedded",
      "kind": "css_selector",
      "selector": ".docx-wrapper img[src^='data:image/'], .docx-wrapper img[src^='blob:']",
      "must": "exist",
      "description": "The rendered <img> must carry an embedded source — either a data:image/ URL (base64-inlined) or a blob: URL (Object URL). Both are valid DOM representations of an image extracted from the docx package; the choice is a renderer-level memory/runtime tradeoff."
    },
    {
      "id": "img-has-a11y-hook",
      "kind": "css_selector",
      "selector": ".docx-wrapper img[alt], .docx-wrapper img[aria-hidden='true'], .docx-wrapper img[aria-label], .docx-wrapper img[aria-labelledby], .docx-wrapper figure img, .docx-wrapper [role='img']",
      "must": "exist",
      "description": "Accessibility hook: the rendered image must carry some screen-reader-visible signal — an alt attribute (even alt=''), aria-hidden='true' to explicitly mark decorative, aria-label/aria-labelledby to supply a name, a <figure> wrapper, or an explicit role='img'. Accepts any of these conventions; the assertion fails only when NONE are present (the typical renderer-with-zero-a11y case)."
    }
  ]
}

Fixture

Download image-inline.docx (19.1 KB)

Reference preview

Reference (machine, page 1 PNG)

docx/image-inline page 1 reference

Reference PDF


Download PDF Open in PDF.js

Spec notes

An inline picture is a <w:drawing> whose child is <wp:inline> (namespace http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing). The inline layout variant flows with text; the alternative is <wp:anchor> for floating positioning. Renderer note: when projecting an embedded image into the DOM, renderers may set the <img> src to either a data: URL (base64-inlined, self-contained, ~33% size overhead) or a blob: URL (Object URL referencing an in-memory Blob, zero overhead but requires a JS runtime and explicit revokeObjectURL lifecycle). Both are equally valid DOM strategies; choosing one over the other is a legitimate implementation tradeoff (memory footprint vs. runtime coupling). The render assertion accepts either.