Skip to content

Carry a picture's hyperlink into the PDF as a link over the image - #257

Open
ikashapov wants to merge 1 commit into
nerdy-pro:mainfrom
ikashapov:issue-250-image-hyperlinks
Open

ikashapov wants to merge 1 commit into
nerdy-pro:mainfrom
ikashapov:issue-250-image-hyperlinks

Conversation

@ikashapov

Copy link
Copy Markdown
Contributor

Carry a picture's hyperlink into the PDF as a link over the image

Closes #250.

§21.1.2.3.5: Word stores a link added to a picture as <a:hlinkClick r:id="…"/> inside <wp:docPr>, resolved through the part's relationships like any other external hyperlink; LibreOffice wraps the run holding the drawing in <w:hyperlink> instead. Neither reached the PDF: the docPr child was accepted and dropped, and an image fragment did not inherit the enclosing hyperlink the way the text fragments beside it do.

Change

  • DocProperties carries the target. It is parsed as ExternalRel; the body-level resolve_hyperlinks pass and the subordinate-part rel rewrite turn it into the final URL exactly as they do for w:hyperlink. A relationship whose target is a bare #fragment names a bookmark in this document and becomes a GoTo.
  • Fragment::Image and FloatingImage carry a LinkTarget. Every site that draws a picture — the line, a wrapTopAndBottom float, a wrapped float, and the two cell-stacker paths — puts one annotation over exactly the drawn rectangle. A picture's own link wins over a w:hyperlink around its run.

Not read, deliberately: v:shape/@href (the VML spelling) and a:hlinkClick on pic:cNvPr, which Word writes alongside the docPr one.

Tests

tests/image_hyperlinks.rs, each drawing a 1×1 PNG and asserting an annotation covering exactly the image rectangle:

  • a:hlinkClick on an inline picture → LinkAnnotation over the image;
  • a picture inside w:hyperlink inherits the link;
  • a:hlinkClick on an anchored picture follows the float;
  • a relationship targeting #Top → InternalLink;
  • control: a picture without a link gets no annotation.

Four of five watched fail before the change.

§21.1.2.3.5: Word stores a link added to a picture as `<a:hlinkClick r:id>`
inside `<wp:docPr>`, resolved through the part's relationships like any other
external hyperlink; LibreOffice wraps the run holding the drawing in a
`w:hyperlink` instead. Neither reached the PDF. The `docPr` child was accepted
and dropped, and an image fragment did not inherit the enclosing hyperlink the
way the text fragments beside it do (issue nerdy-pro#250).

`DocProperties` now carries the target. It is parsed as `ExternalRel`, and the
body-level `resolve_hyperlinks` pass and the subordinate-part rel rewrite turn
it into the final URL exactly as they do for `w:hyperlink`; a relationship
whose target is a bare `#fragment` names a bookmark in this document and
becomes a GoTo. The fragment and the float both carry a `LinkTarget`, and every
site that draws the image — the line, a wrapTopAndBottom float, a wrapped
float, the two cell-stacker paths — puts one annotation over exactly the drawn
rectangle first. A picture's own link wins over a `w:hyperlink` around its run.

Not read: `v:shape/@href`, the VML spelling of the same thing, and
`a:hlinkClick` on `pic:cNvPr`, which Word writes alongside the `docPr` one.

Closes nerdy-pro#250
ikashapov added a commit to ikashapov/dxpdf that referenced this pull request Oct 14, 2026
One squashed commit carrying the tree of integration/2026-10-14, which was
previously a chain of ten merges ending at ac5787e (kept locally as
archive/integration-2026-10-14-merges). Base: upstream main 3a5c7ca.

Integrated, each at the head of its open upstream pull request:

- nerdy-pro#252  fix-layout-defects-228-232 (a40d5ce) — issues nerdy-pro#228–nerdy-pro#232: bookmark-only
        paragraphs, nested-table width, list instances over one abstract
        numbering, table width resolution (pct and tcW autofit), column
        balancing and separators
- nerdy-pro#183  issue-150-wmf-svg (6e5aa99) — WMF/EMF and SVG images
- nerdy-pro#184  issue-151-pgborders-docgrid (27204b3) — page borders, document grid
- nerdy-pro#186  issue-153-shaped-clusters (65739f6) — shaped text clusters
- nerdy-pro#187  issue-154-tracked-changes (6982b34) — tracked changes and comments
- nerdy-pro#185  issue-155-smartart-charts (3683223) — SmartArt and charts
- nerdy-pro#256  issue-253-del-instr-text (0656a52) — w:delInstrText tolerated
- nerdy-pro#257  issue-250-image-hyperlinks (cb5ce2b) — a:hlinkClick on pictures
- nerdy-pro#258  issue-188-font-absent-cost (9a63bf0) — no deep catalogue tier before
        the substitution table, no theme script-font preload
- nerdy-pro#259  issue-158-auto-hyphenation (9bfbae2) — w:autoHyphenation

Beyond the union of those branches, the integration itself changed:
- README keeps one row per feature after the merges; the matrix tally is
  recomputed from the rows.
- nerdy-pro#253's tests assert that a deleted field code is never drawn and never run
  text, because nerdy-pro#154 keeps w:del runs instead of dropping them at parse.
- nerdy-pro#250's push_link_over sits after nerdy-pro#151's resolve_line_metrics; nerdy-pro#158's
  HyphenationCtx.measure and rejoin_hyphenated take &dyn SplitMeasure (nerdy-pro#153).

Verified on this exact tree: cargo fmt, clippy and doc clean; cargo test
2977 passed / 0 failed (skipping the capi library freshness guards);
--no-default-features and --features capi build; the twelve-document
harness passes 12/12.

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

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

The links on the image are not working.

1 participant