Skip to content

Fix legacy XLSX drawing and merged-cell rendering - #130

Merged
shps951023 merged 1 commit into
mainfrom
fix/issue-129-xlsx-rendering
Sep 4, 2026
Merged

shps951023 merged 1 commit into
mainfrom
fix/issue-129-xlsx-rendering

Conversation

@shps951023

@shps951023 shps951023 commented Sep 4, 2026

Copy link
Copy Markdown
Member

Fix Microsoft 365 compatibility for the Issue202609031340.xlsx rendering case.

Changes

  • honor authored narrow default column widths and worksheet vertical centering
  • discover legacy VML/OLE replacement graphics and rasterize EMF previews without executing OLE payloads
  • parse full VML anchors and preserve drawing-layer placement
  • preserve OOXML stacked text (textRotation="255")
  • continue vertically merged cells across automatic page breaks
  • accept UTF-8 BOM benchmark manifests so filtered reports and PNGs refresh reliably
  • add the anonymized issue fixture, O365 reference, focused regression coverage, and benchmark evidence

Validation

  • dotnet build --configuration Release --nologo
  • dotnet test tests\MiniPdf.Tests --configuration Release --nologo (185 passed)
  • scripts\Run-Benchmark_issues.ps1 -Filter "Issue202609031340" -SkipReference -SkipInstall -Heatmaps
  • 4/4 pages; visual 0.9524; overall 0.9341
  • pages 1-2 report PNGs exactly match fresh 150 DPI renders (diff_bbox=None)

Compatibility and security

  • O365 is the authoritative reference; LibreOffice behavior was used only as implementation guidance.
  • OLE payloads are never executed; only packaged replacement graphics are read.
  • Windows EMF rasterization uses the existing guarded System.Drawing path.

Closes #129

Summary by CodeRabbit

  • New Features

    • Improved Excel-to-PDF conversion with support for rotated cell text and vertically centered worksheets.
    • Preserved legacy VML images from Excel files, including more accurate placement, sizing, and cropping.
    • Improved rendering of merged-cell text across page breaks and clipped content.
    • Improved handling of worksheet column widths and page layout.
  • Bug Fixes

    • Fixed recognition of STKaiti font names, improving Chinese font rendering.
    • Improved conversion of metafile images for more reliable output.

Honor authored dimensions and vertical centering, render safe VML/OLE previews, preserve stacked text and cross-page merged cells, and make issue benchmark manifests BOM tolerant.

Refs #129
Copilot AI lite review requested due to automatic review settings September 4, 2026 12:41
@shps951023
shps951023 merged commit 3d49e87 into main Sep 4, 2026
1 of 3 checks passed
@shps951023
shps951023 deleted the fix/issue-129-xlsx-rendering branch September 4, 2026 12:43
@coderabbitai

coderabbitai Bot commented Sep 4, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Team

Run ID: 425a70fe-498f-4c3c-b434-e8943d8b09b6

📥 Commits

Reviewing files that changed from the base of the PR and between a22eeeb and 612e3cc.

⛔ Files ignored due to path filters (14)
  • tests/Issue_Files/reference_xlsx/Issue202609031340.pdf is excluded by !**/*.pdf
  • tests/Issue_Files/reports_xlsx/images/Issue202609031340_p1_heatmap.png is excluded by !**/*.png
  • tests/Issue_Files/reports_xlsx/images/Issue202609031340_p1_minipdf.png is excluded by !**/*.png
  • tests/Issue_Files/reports_xlsx/images/Issue202609031340_p1_reference.png is excluded by !**/*.png
  • tests/Issue_Files/reports_xlsx/images/Issue202609031340_p2_heatmap.png is excluded by !**/*.png
  • tests/Issue_Files/reports_xlsx/images/Issue202609031340_p2_minipdf.png is excluded by !**/*.png
  • tests/Issue_Files/reports_xlsx/images/Issue202609031340_p2_reference.png is excluded by !**/*.png
  • tests/Issue_Files/reports_xlsx/images/Issue202609031340_p3_heatmap.png is excluded by !**/*.png
  • tests/Issue_Files/reports_xlsx/images/Issue202609031340_p3_minipdf.png is excluded by !**/*.png
  • tests/Issue_Files/reports_xlsx/images/Issue202609031340_p3_reference.png is excluded by !**/*.png
  • tests/Issue_Files/reports_xlsx/images/Issue202609031340_p4_heatmap.png is excluded by !**/*.png
  • tests/Issue_Files/reports_xlsx/images/Issue202609031340_p4_minipdf.png is excluded by !**/*.png
  • tests/Issue_Files/reports_xlsx/images/Issue202609031340_p4_reference.png is excluded by !**/*.png
  • tests/Issue_Files/xlsx/Issue202609031340.xlsx is excluded by !**/*.xlsx
📒 Files selected for processing (11)
  • src/MiniPdf/DocxReader.cs
  • src/MiniPdf/ExcelReader.cs
  • src/MiniPdf/ExcelToPdfConverter.cs
  • src/MiniPdf/PdfPage.cs
  • src/MiniPdf/PdfTextBlock.cs
  • src/MiniPdf/PdfWriter.cs
  • tests/Issue_Files/reports_xlsx/comparison_manifest.json
  • tests/Issue_Files/reports_xlsx/comparison_report.json
  • tests/Issue_Files/reports_xlsx/comparison_report.md
  • tests/MiniPdf.Benchmark/compare_pdfs.py
  • tests/MiniPdf.Tests/XlsxIssueFileTests.cs

📝 Walkthrough

Walkthrough

The XLSX reader now parses rotated text, vertical page centering, and legacy VML images. The PDF converter renders stacked text, merged-cell continuations, centered worksheets, and positioned previews. Tests and benchmark reports cover the updated output.

Changes

XLSX rendering pipeline

Layer / File(s) Summary
XLSX metadata and legacy image parsing
src/MiniPdf/ExcelReader.cs, src/MiniPdf/DocxReader.cs
The reader propagates textRotation and verticalCentered values. It parses VML image anchors, offsets, styles, and crops. EMF and WMF previews use configurable PNG rasterization.
Worksheet layout and PDF rendering
src/MiniPdf/ExcelToPdfConverter.cs
The converter renders rotation 255 as stacked characters, continues vertically merged cells across pages, clips merged-cell text, centers worksheet content, positions VML images, and honors explicit default column widths.
PDF page transformation support
src/MiniPdf/PdfPage.cs, src/MiniPdf/PdfTextBlock.cs
PDF pages track worksheet ranges and VML images. Vertical centering translates page blocks and text clip rectangles.
Benchmark and regression validation
tests/MiniPdf.Tests/XlsxIssueFileTests.cs, tests/MiniPdf.Benchmark/compare_pdfs.py, tests/Issue_Files/reports_xlsx/*
The regression test validates four-page output, stacked text, centered content, and VML preview positions. Benchmark loading accepts BOM-prefixed manifests, and comparison reports include the new case and updated reference results.

STKaiti font normalization

Layer / File(s) Summary
STKaiti alias mapping
src/MiniPdf/PdfWriter.cs
NormalizeFontName maps supported Chinese and lowercase STKaiti names to stkaiti.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant XLSX
  participant ExcelReader
  participant ExcelToPdfConverter
  participant PdfPage
  XLSX->>ExcelReader: Read styles, page setup, and legacy VML
  ExcelReader->>ExcelToPdfConverter: Provide rotation, centering, and image metadata
  ExcelToPdfConverter->>PdfPage: Render worksheet content and previews
  ExcelToPdfConverter->>PdfPage: Apply worksheet centering and block translation
Loading
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/issue-129-xlsx-rendering

Comment @coderabbitai help to get the list of available commands.

Copilot AI 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.

🟡 Changes recommended

Legacy VML image ingestion can admit non-PNG/JPG payloads which downstream rendering will mis-declare as PNG, risking corrupted output or runtime failures.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR targets Microsoft 365 compatibility for the Issue202609031340.xlsx fixture by improving XLSX layout fidelity (default column widths, vertical centering), legacy VML/OLE preview image extraction (including EMF rasterization without executing OLE payloads), stacked-text handling (textRotation="255"), and vertically merged-cell continuation across automatic page breaks. It also updates benchmark tooling/artifacts to tolerate UTF-8 BOM manifests and adds focused regression coverage and refreshed benchmark evidence.

Changes:

  • Add XLSX parsing/rendering support for vertical centering, stacked text (textRotation=255), legacy VML image anchors, and cross-page vertical merge continuations.
  • Extend legacy image ingestion to rasterize EMF/WMF previews on Windows, and normalize font name mapping for stkaiti.
  • Update benchmark loader to accept UTF-8 BOM JSON and refresh issue benchmark artifacts + add focused regression test.
File summaries
File Description
tests/MiniPdf.Tests/XlsxIssueFileTests.cs Adds a focused regression test for layout, centering, stacked text rotation, and (Windows-only) OLE preview images.
tests/MiniPdf.Benchmark/compare_pdfs.py Loads BOM-prefixed JSON manifests and updates report API typing.
tests/Issue_Files/reports_xlsx/comparison_report.md Refreshes rendered comparison report content, labels, and adds the new case + heatmaps.
tests/Issue_Files/reports_xlsx/comparison_report.json Adds the new case metrics/details to the machine-readable report.
tests/Issue_Files/reports_xlsx/comparison_manifest.json Updates manifest content/format (including BOM) and adds the new issue case.
src/MiniPdf/PdfWriter.cs Extends font-name normalization to map STKaiti variants consistently.
src/MiniPdf/PdfTextBlock.cs Adds TranslateY helper used for vertical centering adjustments.
src/MiniPdf/PdfPage.cs Implements page-level vertical centering using computed content bounds and worksheet-range tracking.
src/MiniPdf/ExcelToPdfConverter.cs Wires vertical centering + stacked text support into rendering, adds merged-cell continuation and VML image placement handling.
src/MiniPdf/ExcelReader.cs Parses textRotation, vertical centering flag, reads legacy VML drawing images (including EMF->PNG conversion), and extends embedded image metadata.
src/MiniPdf/DocxReader.cs Makes EMF/WMF rasterization helper reusable with configurable raster height.
Review details
  • Files reviewed: 11/25 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +3699 to +3713
var extension = Path.GetExtension(mediaPath).TrimStart('.').ToLowerInvariant();
if (extension is "emf" or "wmf")
{
var cropLeft = ReadVmlCrop(imageData?.Attribute("cropleft")?.Value);
var cropTop = ReadVmlCrop(imageData?.Attribute("croptop")?.Value);
var cropRight = ReadVmlCrop(imageData?.Attribute("cropright")?.Value);
var cropBottom = ReadVmlCrop(imageData?.Attribute("cropbottom")?.Value);
var visibleHeightFraction = Math.Max(0.01f, 1f - cropTop - cropBottom);
var rasterHeight = (int)Math.Ceiling(heightPt.Value * 300f / 72f / visibleHeightFraction);
var converted = DocxReader.TryConvertMetafileToPng(data, widthEmu, heightEmu,
cropLeft, cropTop, cropRight, cropBottom, rasterHeight);
if (converted == null) continue;
data = converted;
extension = "png";
}
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.

Fix XLSX VML previews, stacked text, and merged-cell pagination

2 participants