Skip to content

fix: tolerate real-world producer quirks found in invoice OFDs - #9

Merged
lzwind merged 1 commit into
linuxdeepin:mainfrom
add-uos:fix/real-world-ofd-compat
Oct 20, 2026
Merged

lzwind merged 1 commit into
linuxdeepin:mainfrom
add-uos:fix/real-world-ofd-compat

Conversation

@add-uos

@add-uos add-uos commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

概要

真实世界的 OFD 文件(发票生成器尤为典型)会触发三处解析/渲染死路;由于 deepin-reader 链接同一套库,以下失败在阅读器中同样复现:

  1. 重复 MultiMedias 块:部分发票生成器在 DocumentRes.xml 输出多个 <MultiMedias> 目录,serde 报 duplicate field 直接失败。改为与 Fonts 块相同的处理:lenient 模式合并(Option<T> → Vec<T>),strict 模式仍然拒绝
  2. 空 <Clips/> 元素:lenient 模式视为无裁剪继续渲染,strict 模式保持报错
  3. 图片声明格式与实际不符:发票把 JPEG 数据声明成 PNG。改为按字节签名嗅探解码(未支持签名仍然拒绝),目录声明仅作元数据

修复前 6 张真实报销发票仅 2 张可渲染,修复后 6/6 全部正常。

测试

  • 新增 3 组回归测试(多 MultiMedias 合并/strict 拒绝、空 Clips lenient/strict、格式嗅探覆盖旧断言并改名)
  • cargo test -p rofd-core -p rofd-render 全量通过;cargo clippy --all-targets -- -D warnings 干净
  • 关联:feat: add OFD thumbnail and space preview support dde-file-manager#4575(文管 OFD 缩略图/空格预览,依赖本修复才能渲染真实发票)

Summary by Sourcery

Improve OFD parsing and rendering resilience for malformed or inconsistent data produced by real-world invoice generators.

Bug Fixes:

  • Tolerate duplicate MultiMedias resource blocks and empty Clips elements in lenient mode while preserving strict-mode validation.
  • Decode images according to detected byte signatures rather than unreliable catalog declarations, including BigTIFF data.

Enhancements:

  • Retain image format mismatch errors for public API compatibility while treating declared formats as metadata.

Build:

  • Add TIFF support for BigTIFF regression coverage.

Tests:

  • Add regression tests covering duplicate MultiMedias handling, empty Clips strictness, and signature-driven image decoding.

@sourcery-ai

sourcery-ai Bot commented Sep 29, 2026

Copy link
Copy Markdown

Reviewer's Guide

The PR hardens OFD parsing and rendering against common invoice-producer deviations by merging repeated resource blocks and tolerating empty clipping containers in lenient mode, while retaining strict-mode validation. Image decoding now trusts supported byte signatures over potentially incorrect declared formats, with regression tests covering each compatibility behavior.

Sequence diagram for image format sniffing during rendering

sequenceDiagram
    participant Renderer
    participant Preflight
    participant ImageResource
    participant Decoder
    Renderer->>Preflight: preflight(resource, limits)
    Preflight->>ImageResource: asset_path()
    Preflight->>Preflight: detect_format(resource)
    Preflight->>Decoder: Decode using detected byte signature
    Decoder-->>Preflight: Decoded image
    Preflight-->>Renderer: Rendering source
Loading

Flow diagram for lenient and strict OFD compatibility handling

flowchart TD
    A[Parse OFD resources and page content] --> B{Duplicate MultiMedias blocks?}
    B -->|No| C[Build ResourceCatalog]
    B -->|Lenient| D[Merge MultiMedias entries]
    B -->|Strict| E[Reject duplicate MultiMedias]
    D --> C
    A --> F{Empty Clips element?}
    F -->|No| G[Process clipping paths]
    F -->|Lenient| H[Treat Clips as absent]
    F -->|Strict| I[Reject invalid Clips]
    H --> J[Render page]
    G --> J
    C --> J
    E --> K[Parse failure]
    I --> K
Loading

File-Level Changes

Change Details Files
Make resource parsing tolerant of repeated MultiMedias blocks while preserving strict validation.
  • Parse all MultiMedias blocks instead of failing on duplicate XML fields.
  • Merge entries from every block into the resource catalog in lenient mode.
  • Reject multiple blocks explicitly in strict mode.
  • Add lenient and strict regression coverage.
crates/rofd-core/src/raw.rs
crates/rofd-core/src/resources.rs
crates/rofd-core/tests/resources.rs
Treat empty Clips elements according to document strictness.
  • Ignore empty elements in lenient mode.
  • Continue reporting invalid structure in strict mode.
  • Add separate regression tests for both behaviors.
crates/rofd-core/src/content.rs
crates/rofd-core/tests/clipping.rs
Decode images from detected byte signatures rather than unreliable catalog format metadata.
  • Remove the declared-versus-detected format mismatch rejection.
  • Use the detected format as the decoding authority while retaining rejection of unsupported signatures.
  • Update image tests to verify decoding succeeds when declarations disagree and unsupported signatures still fail.
crates/rofd-render/src/images.rs
crates/rofd-render/tests/images.rs

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - I've reviewed your changes and they look great!


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

@add-uos
add-uos force-pushed the fix/real-world-ofd-compat branch from d211395 to e5a1a0a Compare October 20, 2026 09:05
Real-world OFD files (invoice generators in particular) hit three
parsing/rendering dead ends; every failure below also reproduces in
deepin-reader since it links the same library:

- rofd-core: accept several <MultiMedias> blocks in one resource
  catalog (mirrors the existing Fonts handling) instead of failing
  with a serde duplicate-field error; strict mode still rejects them
- rofd-core: treat an empty <Clips/> element as absent in lenient
  mode instead of rejecting the whole page; strict mode still errors
- rofd-render: decode images by their detected byte signature rather
  than the catalog-declared format (invoices declare PNG for JPEG
  data); unsupported signatures are still rejected

With these, 6/6 real invoice OFDs render (2/6 before). Regression
tests added for all three; existing suites updated where the old
strictness was asserted.
@add-uos
add-uos force-pushed the fix/real-world-ofd-compat branch from e5a1a0a to a9fcc2f Compare October 20, 2026 09:10
@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: add-uos, lzwind

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@lzwind
lzwind merged commit f27fb87 into linuxdeepin:main Oct 20, 2026
13 of 14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants