Skip to content

fix: keep pictures whose mode cannot be written as PNG - #4683

Open
ryanmeowy wants to merge 2 commits into
docling-project:mainfrom
ryanmeowy:fix/image-loader-png-mode
Open

ryanmeowy wants to merge 2 commits into
docling-project:mainfrom
ryanmeowy:fix/image-loader-png-mode

Conversation

@ryanmeowy

@ryanmeowy ryanmeowy commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Issue resolved by this Pull Request:
Resolves #4682

Checklist:

  • Documentation has been updated, if necessary. (Not needed. This is a bug fix.)
  • Examples have been added, if necessary. (Not needed.)
  • Tests have been added, if necessary. An end-to-end check in tests/test_backend_html.py and one in tests/test_backend_mhtml.py; a unit test for the truncated-image path, carried over from fix(html): keep CMYK images and skip undecodable ones instead of failing #4681 by @usmanmateen, lives in tests/test_image_resource_loader.py.

Review evidence:

Behavior before. A picture in CMYK, LAB or F mode raised OSError: cannot write mode <mode> as PNG inside ImageRef.from_pil(). The shared ImageResourceLoader.create_image_ref() did not catch OSError, so the error escaped and aborted the whole conversion for the HTML, Markdown, AsciiDoc and JATS backends. The MHTML branch caught the error and dropped the picture. On the JATS backend the error also stopped the body walk, so the conversion lost all body content after the figure and still reported success.

Behavior after. The loader normalizes the picture first, as the Office backends already do. The except tuple also catches OSError. CMYK, LAB and F pictures are now kept and converted to RGB, through the embedded ICC profile when one is present. A picture that cannot be decoded no longer fails a conversion. The backend keeps the picture placeholder and emits a warning.

Checks.

Check Command Result
New tests pytest tests/test_backend_html.py tests/test_backend_mhtml.py tests/test_image_resource_loader.py 148 passed, 1 skipped
Shared-loader consumer suites pytest tests/test_backend_msword.py tests/test_backend_msword_lists.py tests/test_backend_msword_outline.py tests/test_backend_msword_spacer.py tests/test_backend_opendocument.py tests/test_office_image_modes.py tests/test_backend_image_native.py tests/test_api_image_request.py 386 passed, 1 skipped
Format and lint ruff format --check . and ruff check . All checks passed
Type check ty check 606 diagnostics, same as main (line shifts only)

Not run: conversion of real print-scanned document corpora, and the remote-fetch path of the loader (the test URL allowlist blocks it).

@github-actions

github-actions Bot commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

✅ DCO Check Passed

Thanks @ryanmeowy, all your commits are properly signed off. 🎉

@mergify

mergify Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

Merge Protections

🟢 Merge protection satisfied — ready to merge.

Show 1 satisfied protection

🟢 Enforce conventional commit

Make sure that we follow https://www.conventionalcommits.org/en/v1.0.0/

  • title ~= ^(fix|feat|docs|style|refactor|perf|test|build|ci|chore|revert)(?:\(.+\))?(!)?:

@ryanmeowy
ryanmeowy force-pushed the fix/image-loader-png-mode branch from a794ec3 to 82d6486 Compare October 8, 2026 08:40
@github-actions github-actions Bot added ai:ci-safe AI triage found no CI-safety concern (advisory) ai:possible-duplicate AI triage: another PR may fix the same problem asciidoc issue related to asciidoc backend bug Something isn't working html issue related to html backend markdown issue related to markdown backend labels Oct 8, 2026
@github-actions

github-actions Bot commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

AI triage (advisory)

Checked commit 5e46d36d59. The analysis read the diff only. It did not run code from this pull request.

This pull request prevents conversion failures when processing pictures with unsupported Pillow modes, such as CMYK, LAB, or F, or when processing truncated image data. It normalizes image modes to PNG-compatible formats and catches decoding exceptions in ImageResourceLoader.

CI safety: no concern found. A maintainer must still approve CI.

1 related pull request(s) in the same code
PR State Signal Assessment
#4681 closed also references issue #4682; referenced as #4681 related: This candidate is closed and not merged. The current pull request incorporates and extends the fixes and tests from this candidate.

The ai:* labels are advisory. They do not approve CI and they do not add tests:full. A new push runs this check again.

@codecov

codecov Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@ceberam

ceberam commented Oct 8, 2026 •

Copy link
Copy Markdown
Member

@ryanmeowy The PR #4681 , which addresses issue #4680 , was open earlier on this same topic.
Can you explain how different your PR is from #4681 . In particular, does it resolve the issues described in #4682 and in #4680 ? Are there gaps that are not covered in your PR? Does it provide a better implementation in terms of code quality and pythonic patterns, test coverage and robustness, maintainability and complexity?

@ryanmeowy

Copy link
Copy Markdown
Contributor Author

Thanks @ceberam, and thanks @usmanmateen — I hadn't seen #4681 when opening this one; we clearly hit the same root cause independently.

How it differs: the two hunks in image_resource_loader.py are identical (same resulting content). This PR additionally normalizes the embedded-MHTML branch in html_backend.py (_create_image_ref), which does not go through the loader — for images embedded in the MHTML archive itself, from_pil is called directly, so with only the loader change a CMYK image embedded in MHTML is still dropped with a warning instead of converted. That path is why #4682 exists as a separate report.

Does it resolve #4682 and #4680? Yes to both. #4680's repro (CMYK + truncated JPEG in HTML/Markdown) succeeds here. #4682 additionally documents the MHTML drop (fixed by the html_backend.py hunk) and the JATS silent truncation (an escaping exception aborts the rest of the document body — fixed here since the loader no longer raises; covered end-to-end).

Gaps: the La PNG mode still degrades to warn+drop (Pillow cannot write La to any raster format, so unreachable via real files); SVG resources untouched (never reach PIL); remote-fetch behavior unchanged.

Tests: #4681's are unit-level (direct loader calls); ours run end-to-end through DocumentConverter across HTML, Markdown, AsciiDoc, JATS and MHTML, which is what catches the MHTML wiring that loader unit tests cannot reach.

Happy to defer to #4681 since it was opened first — two ways: (a) I close this and move the MHTML fix + end-to-end tests into a follow-up PR on top of it, or (b) if you prefer a single PR, this one is a strict superset of #4681. Either works for me; I only care that the MHTML path doesn't stay broken.

@ceberam ceberam linked an issue Oct 8, 2026 that may be closed by this pull request
@ceberam

ceberam commented Oct 8, 2026

Copy link
Copy Markdown
Member

Thanks @ryanmeowy for your review.
Even though your issue and PR was opened later (with few minutes of difference), the completeness argument is here more relevant.
We closed #4681 and we will review this PR instead.

@ryanmeowy
ryanmeowy force-pushed the fix/image-loader-png-mode branch from 82d6486 to 2a6bd02 Compare October 8, 2026 09:46
@github-actions github-actions Bot removed ai:ci-safe AI triage found no CI-safety concern (advisory) ai:possible-duplicate AI triage: another PR may fix the same problem labels Oct 8, 2026
@ryanmeowy

Copy link
Copy Markdown
Contributor Author

Thanks @usmanmateen — your cross-review made this easy for everyone: verifying the MHTML gap against your own branch is exactly the diligence that settles a duplicate. Carrying over test_create_image_ref_skips_undecodable_image as you offered, with attribution in the commit. And thanks @ceberam for the quick triage.

@github-actions github-actions Bot added ai:ci-safe AI triage found no CI-safety concern (advisory) ai:possible-duplicate AI triage: another PR may fix the same problem labels Oct 8, 2026
@usmanmateen usmanmateen mentioned this pull request Oct 8, 2026
3 tasks done

@ceberam ceberam left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @ryanmeowy for the PR. The fix is correct, the code is clean, and the tests are meaningful. Please address the suggestions below, plus a minor inconsistency note.

Comment thread tests/test_image_resource_loader.py Outdated
Comment thread docling/backend/utils/image_resource_loader.py
Comment thread tests/test_backend_image_resource_modes.py Outdated
@github-actions github-actions Bot added ai:ci-safe AI triage found no CI-safety concern (advisory) ai:possible-duplicate AI triage: another PR may fix the same problem and removed ai:ci-safe AI triage found no CI-safety concern (advisory) ai:possible-duplicate AI triage: another PR may fix the same problem labels Oct 9, 2026
@ryanmeowy
ryanmeowy requested a review from ceberam October 11, 2026 03:09
@ryanmeowy

Copy link
Copy Markdown
Contributor Author

Hi @ceberam — sorry to ping you directly, and apologies if this is a bad time.

Just a gentle bump on #4683. I think I've covered everything from your review: I dropped the provenance comment, added the explicit img.load() in create_image_ref, and moved the tests into test_backend_html.py and test_backend_mhtml.py. CI is green and the review threads are resolved. No rush at all — whenever you have a moment to take another look, I'd appreciate it.

Small extra ask, only if it's easy: #4745's latest commit is stuck in action_required, so the CI workflows need a maintainer to approve them before they will run. If you happen to be passing by, could you hit "Approve and run" on that one?

Thanks, and sorry again for the nudge.

ceberam
ceberam previously approved these changes Oct 23, 2026

@ceberam ceberam left a comment •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @ryanmeowy for the heads-up. It all seems good but there are actually some conflicts after we merged some PRs recently. Could you please rebase to main and address them?

@ryanmeowy
ryanmeowy force-pushed the fix/image-loader-png-mode branch from 2981226 to 628a576 Compare October 25, 2026 03:56
@github-actions github-actions Bot added ai:ci-safe AI triage found no CI-safety concern (advisory) and removed ai:ci-safe AI triage found no CI-safety concern (advisory) ai:possible-duplicate AI triage: another PR may fix the same problem labels Oct 25, 2026
@ryanmeowy
ryanmeowy force-pushed the fix/image-loader-png-mode branch from 628a576 to 83a84e9 Compare October 25, 2026 04:14
@github-actions github-actions Bot added ai:ci-safe AI triage found no CI-safety concern (advisory) and removed ai:ci-safe AI triage found no CI-safety concern (advisory) labels Oct 25, 2026
@ryanmeowy

Copy link
Copy Markdown
Contributor Author

@ceberam Rebased onto main and resolved the conflicts — 83a84e9a. Thanks!

@PeterStaar-IBM

Copy link
Copy Markdown
Member

@ryanmeowy Can you fix the merge conflict?

ImageRef.from_pil() serializes to PNG, so images in CMYK, LAB or F mode
raise OSError: cannot write mode <mode> as PNG.

In the shared ImageResourceLoader.create_image_ref() that error is not in
the except tuple, so it escaped and aborted the whole conversion for the
HTML, Markdown, AsciiDoc and JATS backends. In the MHTML branch of
html_backend the error is caught, so the picture was silently dropped
instead.

Normalize the image first, as the Office backends already do, and catch
OSError so that a single unreadable image can never fail a conversion.

Unit test for the truncated-image (OSError) path carried over from
PR 4681 by @usmanmateen.

Co-authored-by: usmanmateen <usmanmateen255@gmail.com>

Signed-off-by: Ryan Yang <ryanxys@gmail.com>
Single-source the loader coverage: keep one end-to-end HTML check and
the MHTML check for the PNG-mode normalization, dropping the Markdown
and AsciiDoc variants that only re-exercise the DocumentConverter
plumbing, and delete the dedicated test module in favor of the existing
backend suites. Call img.load() in create_image_ref for parity with the
MHTML and OpenDocument paths. Drop the provenance comment; attribution
is tracked in the commit trailer.

Signed-off-by: Ryan Yang <ryanxys@gmail.com>
@ryanmeowy
ryanmeowy force-pushed the fix/image-loader-png-mode branch from 83a84e9 to 5e46d36 Compare October 26, 2026 13:03
@github-actions github-actions Bot removed the ai:ci-safe AI triage found no CI-safety concern (advisory) label Oct 26, 2026
@ryanmeowy

Copy link
Copy Markdown
Contributor Author

@PeterStaar-IBM Fixed — rebased onto main again (5e46d36d). The conflict was in tests/test_backend_html.py with #4912; both tests are kept. CI should pick it up shortly.

@github-actions github-actions Bot added the ai:ci-safe AI triage found no CI-safety concern (advisory) label Oct 26, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai:ci-safe AI triage found no CI-safety concern (advisory) asciidoc issue related to asciidoc backend bug Something isn't working html issue related to html backend markdown issue related to markdown backend

Projects

None yet

3 participants