Repository navigation
fix(xlsx): clip page fills one sheet point inside the top and left gridlines - #1743
Merged
Merged
Conversation
…idlines Excel clips every printed page's cell fills to the page's grid region inset by one sheet point on the top and left edges; the bottom and right edges keep the positive-axis bleed and later rows and columns keep their raw origin. The converter painted the first row and column from the raw gridline, so the reported workbook's title fill started at x=50/y=54 where native shows 51/55. Three native exports of the public #982 workbook settle the rule: the unscaled sheet without a print area clips at [51, 55, 474, 418] around a raw [50, 54, 474, 145] fill, the fitted 0.82 explicit-area sheet clips one scaled point inside its origin, and its unscaled continuation page clips at x=473 for a raw fill at 472, so the clip is per page. The fill pass now trims a tracked fill whose track starts on the table's grid origin, taken from the table's start tag in the frame that holds the fills because Typst inlines single-item frames. Fill tests that anchored on the first cell's fill now subtract the clip, and a new test pins the rule at both print scales on one and two sheet pages. Evidence for page 1 of the fixture is under assets/bugfixes/issue-1605/. Fixes #1605 Related: #1742, #1659 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Yonghye Kwon <developer.0hye@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
File submission policy
Before attaching or committing files, read the submission policy.
Complete a security review and obtain your organization's internal approval for
public sharing where applicable. You are responsible for lawful disclosure;
the project and maintainers disclaim related liability to the extent permitted
by applicable law.
Summary
Excel clips every printed page's cell fills to that page's grid region inset by one sheet point on the top and left edges, while the bottom and right edges keep the one-point positive-axis bleed and every later row and column keeps its raw origin. The converter painted the first row and first column from the raw gridline, so the rose title of the reported workbook started at x=50/y=54 where native shows x=51/y=55.
The rule was read off three native Excel 16.112 exports of the public #982 workbook rather than argued from one page: the unscaled first sheet without a print area clips its fills to
[51, 55, 474, 418]around a raw title rectangle of[50, 54, 474, 145]; the fitted 0.82 sheet with the explicitA1:R12print area clips at[55.76, 54.12]for a grid origin of[54.94, 53.30](one scaled sheet point); and that sheet's unscaled export (#1598) clips its continuation page at x=473 for a raw fill that starts at x=472, so the clip is per page, not per sheet. Cell text is unaffected because Excel already seats content inside[B+1, B_next].Key changes:
excel_fill_paint.rs: a tracked fill whose track starts on the table's grid origin loses one sheet point (1 × print scale) on that edge — position moves in and the size shrinks — beside the existing bleed extension; interior fills, fills behind an unfilled gutter row or column, the bleed and the row-first paint order (XLSX: cell fill extensions overpaint neighboring colors #1599) are untouched. The origin is the table's start tag in the frame that holds the fills, because Typst inlines a single-item frame into its parent and a one-cell table's fill then carries page coordinates.typst_gen_table_border_tests.rs:page_fills_lose_one_sheet_point_on_the_top_and_left_grid_edgespins the rule at scale 1.0 and 0.82 on one page and on a second sheet page (the parser's continuation page), asserting the inset first row/column, the unchanged interior origins and the surviving bleed. Three existing fill tests derived the grid origin from the first cell's fill and now subtract the clip; the one-cell Excel/Word/centred-stroke comparison asserts the Excel fill starts one point inside the shared origin and reaches one point past its right boundary.assets/bugfixes/issue-1605/: fix-mode evidence (gt/before/after at 300 DPI,layout-audit.json, strictrender-clusters-page-1.json).The layout harness could not see this defect before the fix: matching raw rectangles skip the visible-coverage check, so native's clipped fill against our unclipped one reported
geometry 0. Filed as #1742.Related issue
Fixes #1605
Related: #1742, #1659
Testing
cargo test --locked -p office2pdf --lib page_fills_lose_one_sheet_point— fails onmain(first column/row fills start at the grid origin at both scales, on both pages) and passes with the change.cargo test --locked -p office2pdf --lib border_tests— 44 passed.cargo test --locked --workspace— 3721 passed, 0 failed.cargo +1.97 clippy --locked --workspace --all-targets -- -D warningsandcargo fmt --all -- --checkclean.2aa03caf…); before binary ismainat 4919bfc; both conversions with--font-pathfor the Office cloud-font cache and Excel's DFonts bundle.mutool draw -F traceon page 1: after the fix the rose title paints[51, 55, 474, 145](native[51, 55, 474, 145]visible under its clip; before[50, 54, 474, 145]), the pale body starts at y=144 under it as native does. Page 2 is pixel-identical before and after (magick compare -metric AE0 at 150 DPI, identical trace rectangles), because its first filled cells sit inside gutter rows and columns.python3 scripts/compare_layout.py GT.pdf after.pdf --page 1 --noise-floor 0.5 --audit --fine-shift 0.5 --json;python3 scripts/compare_render.py GT.pdf after.pdf --page 1 --dpi 300 --fine-shift 0.5 --artifacts-dir … --cluster-report … --cluster-dispositions … --strict-clusters(71/71 clusters dispositioned, strict PASS);python3 scripts/compare_text_layer.py GT.pdf after.pdf --page 1(text layer intact).Visual impact
Visual audit
tests/fixtures/xlsx/issue_1603_gift_budget.xlsx(publicGift Budget and Tracker1.xlsxfrom Gift Budget and Tracker1.xlsx misc issues #982, SHA-25625f5dc75dab19ea12042979a61842314ddc226e3e45d447e36b2a2a104112613)fixassets/bugfixes/issue-1605/layout-audit.jsonassets/bugfixes/issue-1605/render-clusters-page-1.jsonTEM|PLATEcrop and matched 480x70px crops at the start and end of the long body lineEnter in table the names…. In the corner crops the before panel's rose fill begins four device pixels (one point) above and left of native on both edges; the after panel's fill edge coincides with native on both edges, and the diff page shows no line along the panel's top or left boundary while the panel's bottom seam against the pale body is also clean (XLSX: cell fill extensions overpaint neighboring colors #1599 fixed earlier). Every remaining diff cluster is glyph-sized: the body lines match at their start and drift right by about 0.8pt by the end of the line (whole-point glyph advances, XLSX: Excel for Mac advances each sheet glyph a whole point, so long strings drift up to 1.3pt from our fractional advances #1659), the title'sMshows the same drift on its diagonals, and the 8pt footer shows outline-only differences.Note:keeps its bold weight and every other run is regular; no italic, underline, hairline or border exists on this page in either render, and no cluster touches the fill edges.assets/bugfixes/issue-1605/gt.jpgassets/bugfixes/issue-1605/before.jpgassets/bugfixes/issue-1605/after.jpgassets/bugfixes/issue-1605/compare.jpgVisual comparison
Required inspection
Deviation audit
Checklist
Signed-off-byline🤖 Generated with Claude Code