Skip to content

Images in OOXML documents render as "Error: image not found or unsupported" #551

Description

@andiwand

Every image in a .docx / .xlsx document comes out as the core's broken-image placeholder. ODF documents are fine, which is what makes it easy to miss.

Found by sweeping OpenDocument.core's input corpus on a Pixel 9 Pro (#550). Roughly 23 of 225 documents are affected — every OOXML file in the corpus that contains an image.

Cause

CoreLoader publishes the translated document on the core's http server under /file/<prefix>/, but asks for absolute resource paths:

https://github.com/opendocument-app/OpenDocument.droid/blob/main/app/src/main/java/app/opendocument/droid/background/CoreLoader.kt#L209-L212

htmlConfig.embedImages = false
htmlConfig.embedShippedResources = true
htmlConfig.relativeResourcePaths = false

For OOXML the core then emits the path as it appears in the container, rooted:

<img alt="Error: image not found or unsupported" src="/word/media/image1.jpeg"/>

The WebView resolves that against the server root, not against /file/odr/, so it misses either way. Both 404 (checked against the running app over adb forward):

/word/media/image1.jpeg            HTTP 404
/file/odr/word/media/image1.jpeg   HTTP 404

ODF documents work because the core emits their paths relative, and those resolve under the service mount point:

<img src="Pictures/1000000000000303000001E0ABAD3FD0DB2BBAE0.png"/>
/file/odr/Pictures/10000000...png  HTTP 200, 434353 bytes, image/jpg

So the server serves document resources correctly; only the absolute form misses.

Neither of the two settings that look like the fix is one. relativeResourcePaths = true has no effect — the core gates that rebase on resource.is_shipped() (html.cpp:255-278), and a document resource is returned untouched. Mounting the service at the server root is impossible — HttpServer::prefix_pattern is ([a-zA-Z0-9_-]+), which rejects an empty prefix, and every route is nested under /file/<prefix>. embedImages = true does work, at the cost of base64 in memory on image-heavy files.

The bug is core-side, and not app-specific: the ooxml engines name an internal image by its absolute container path while odf names it relative, and the html layer emits whatever it is given. HtmlService::bring_offline throws not a relative path on the same input, so translate --embed-images=false on a docx fails outright. Fixed by opendocument-app/OpenDocument.core#727, which makes the emitted location relative to the document for every engine. This issue closes when the app picks up that release; embedImages = true is the workaround until then.

Repro

Any of these from the public corpus, all with --filter on the sweep tool or just opened by hand:

  • docx/file-sample_100kB.docx (also _500kB, _1MB)
  • docx/physics.docx
  • docx/sample2.docx, sample3.docx, sample4.docx
  • xlsx/sample.xlsx

Note

These lines arrived in #515, the odrcore JNI bindings migration, so this looks like an unintended regression rather than a deliberate setting.

Two things are separate from this and not fixed by it: the core also emits src="" for a few images (4 of 219 documents in its own reference output), and vector images (SVM/WMF) show the same placeholder for their own reasons.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions