Skip to content

DOCX: a wrapSquare/wrapTight anchored picture floats to the page top and the text resumes below it at full width, instead of wrapping beside it #2353

Open

Description

@developer0hye

Problem

An anchored picture (wp:anchor) with wp:wrapSquare or wp:wrapTight is emitted as #place(top + left, dx: …, dy: …, float: true) (generate_floating_image_with_vertical_offset, crates/office2pdf/src/render/typst_gen.rs). A Typst top float sits at the top of the page region and pushes the flow below it.

Word does two things differently:

  • It draws the picture at its anchor.
  • It sets every line that meets the picture's vertical band beside the picture, on the sides wrapText allows.

As a result, office2pdf sets text that Word puts beside the picture below it at full width. A picture anchored below earlier text is also drawn above that text, at the top of the page.

Measurements

Fixtures: docxide-pdf tests/fixtures/cases/ at fe7b8bea, Apache-2.0 synthetic. Every reference.pdf reports Creator: Microsoft Word; the pages are Letter with 72pt margins. Ours is the office2pdf main release CLI at 80aba9ca. Line boxes come from mutool draw -F stext, and picture boxes from -F trace fill_image transforms (y down, pt).

case47 page 1. The picture is in the first paragraph: positionH column 0, positionV paragraph 0, 150×50pt, wrapSquare wrapText="largest". The picture's position agrees, so this isolates the missing side-wrap:

picture x, y "Page 1: A 50pt" x0 / y0 first line back at the margin
Word 72.00, 72.00 231.10 / 72.08 72.03 / 126.60 (4th line)
ours 72.00, 72.00 72.00 / 138.50 every line, from 138.50

case41 page 1. The picture is alone in the second paragraph, after one text paragraph: positionH column align left, positionV paragraph 0, 180×180pt, wrapSquare bothSides, distR/distB 7.2pt:

picture top paragraph 1 y0 paragraph 3 first line x0 / y0 first line back at the margin
Word 111.65 72.08 259.35 / 136.60 (11 lines beside) 72.03 / 299.65
ours 72.00 268.50 72.00 / 307.60 (full width) —

office2pdf draws the picture at the top margin, above paragraph 1, and pushes paragraph 1 down 196.4pt. case41 pages 2 and 3 show the same flow for right- and centre-aligned pictures. Their horizontal position is a separate defect, #2352.

Real-world case. The document is docxide scraped/indonesian_benchmarking_guide, a third-party public document that is not committed here (input.docx sha256 99fd8ef0…e095). Its 15-page Word reference reports Creator: Microsoft Word.

  • It has a 251.1×373.5pt picture: wrapSquare bothSides, positionH margin align left, positionV paragraph align top.
  • Five empty paragraphs follow the picture's own paragraph. Then comes a paragraph holding only <w:br w:type="textWrapping" w:clear="all"/>.
  • Word draws the picture at the top of page 7 and resumes the heading "3. Metode Benchmarking" below it, at y0 459.79 on page 7.
  • office2pdf floats the picture to the top of page 7 but sets the heading on page 6 at y0 605.97, so pagination differs from there on.

This is the drawing half of #2230. A clearing break has nothing to clear until the picture has a wrap band.

Expected

For wrapSquare, wrapTight and wrapThrough:

  • The picture sits at its resolved anchor position.
  • Each line whose box meets the picture's band, extended by distT/distB, is shortened on the sides wrapText allows (bothSides, left, right, largest), keeping distL/distR from the picture.
  • Lines below the band return to the full column.

For wrapTight, Word follows the picture's wp:wrapPolygon. In case42, the lines narrow and widen along a non-rectangular outline. A square band is the wrapSquare rule only.

Lead

#2349 (crates/office2pdf/src/render/typst_gen_float_wrap.rs) implements this exclusion for w:tblpPr floating tables, using o2p-float-<id>-top/-bottom labels. #2351 builds the clearing break on that. A picture band could reuse both.

Related: #2230, #2229, #2352.

Activity

  1. added
    docx-corpusDOCX defect found on the docxide-pdf Word-reference corpus
    on Oct 19, 2026
  2. developer0hye commented on Oct 19, 2026

    @developer0hye
    OwnerAuthor

    Addendum: one case41 page 1 measurement contradicts the Expected rule as written. Settle the band's top edge by measurement or a probe when this is fixed, not from the wording above.

    • Paragraph 1's last line, "of the image.", is at x0 259.35 in Word, beside the picture (line box y 86.83–99.72, mutool draw -F stext).
    • The picture's top is 111.65 and distT is 7.2pt (91440 EMU). So that line ends above a band that starts at 104.45, and the "meets the band extended by distT/distB" rule would keep it at the margin.
    • Ours breaks paragraph 1 one word later. Its second line, "the image.", is at x0 72.00 (y0 283.05), below the floated picture.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    docx-corpusDOCX defect found on the docxide-pdf Word-reference corpus

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions