Skip to content

fix(xl-pdf-exporter): Keep image aspect ratio, page fit fixes#2887

Open
Wqrld wants to merge 1 commit into
TypeCellOS:mainfrom
Wqrld:pdf-image-aspect-fix
Open

fix(xl-pdf-exporter): Keep image aspect ratio, page fit fixes#2887
Wqrld wants to merge 1 commit into
TypeCellOS:mainfrom
Wqrld:pdf-image-aspect-fix

Conversation

@Wqrld

@Wqrld Wqrld commented Jul 7, 2026

Copy link
Copy Markdown

Disclaimer: AI code, tested by a human, PR by a human.

Summary

This PR modifies image handling in the pdf export so aspect ratios are preserved and no unnecessary whitespace is created.

Rationale

Currently, images get squished, lose their resolution, or otherwise can get malformed in a pdf export. See #2866

Changes

  • Clamp image box height
  • Preserve aspect ratio
  • Handle captions
  • add basic tests

Impact

Exported PDF documents might look slightly different. I have not found any real problematic side effects yet in my testing.

Testing

Added automated tests. Also tested manually with images of different sizes and locations.

Screenshots/Video

after.pdf
before.pdf

Checklist

  • [?] Code follows the project's coding standards.
  • Unit tests covering the new feature have been added.
  • All existing tests pass. *Some regression seemingly elsewhere on my PC
  • The documentation has been updated to reflect the new feature

Additional Notes

Fixes #2866

Tests now patch the jpeg sizes. Not ideal but seems to work fine. AI code might not fully match your expected code style so if you wish to use the changes in a separate commit, feel free to.

Summary by CodeRabbit

  • New Features

    • PDF exports now handle images and captions more consistently, including better sizing, alignment, and page-fit behavior.
    • Tall images are now kept within a single page when possible, improving document layout.
  • Bug Fixes

    • Fixed image rendering so images no longer overflow or leave extra blank pages in PDF output.
    • Improved placeholder image handling in tests to match requested dimensions more accurately.

… in PDF export (TypeCellOS#2866)

Images in PDF exports were previously given only a fixed width, so
oversized bitmaps could distort, overflow the page horizontally, or
spill an empty trailing page when taller than the page (images render
in an unbreakable group).

- Clamp the image box with maxWidth: 100% and a maxHeight cap derived
  from the page height, page padding, per-block padding, and one
  reserved caption line.
- Use objectFit: contain + objectPosition so a clamped bitmap keeps its
  aspect ratio and hugs the edge matching the block's textAlignment.
- Clamp captions with maxWidth: 100% so they wrap instead of overflowing.
- Teach the shared test file resolver to serve placehold.co URLs at the
  dimensions requested in the URL (patched into the placeholder JPEG's
  SOF0 marker), failing loudly if the marker is missing.

Known limitations (documented in code): multi-line captions and
in-flow headers can still make a page-height image group spill.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 7, 2026

Copy link
Copy Markdown

@Wqrld is attempting to deploy a commit to the TypeCell Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds PAGE_HEIGHT and BLOCK_VERTICAL_PADDING constants to the PDF exporter, introduces image/caption sizing helpers (previewWidthToPoints, points, imageStyle) to preserve aspect ratio and avoid unwanted page breaks, and extends the test file resolver to patch placeholder JPEG dimensions dynamically, with new tests covering these behaviors.

Changes

PDF Image Sizing Fix

Layer / File(s) Summary
Layout constants
packages/xl-pdf-exporter/src/pdf/pdfExporter.tsx
Adds exported PAGE_HEIGHT and BLOCK_VERTICAL_PADDING constants and applies the latter to block wrapper paddingVertical.
Image and caption sizing helpers
packages/xl-pdf-exporter/src/pdf/defaultSchema/blocks.tsx
Adds CAPTION_FONT_SIZE and helper functions previewWidthToPoints, points, and imageStyle to compute width/maxWidth/maxHeight and object-fit/position, replacing inline sizing logic for images and captions.
Test resolver JPEG dimension patching
shared/util/testFileResolver.ts
Parses requested width/height from placehold.co URLs and patches the JPEG's SOF0 segment via a new patchJpegDimensions helper instead of always returning a fixed 332x322 image.
Image export tests
packages/xl-pdf-exporter/src/pdf/pdfExporter.test.tsx
Adds imports and three tests verifying clamped image alignment, tall image scaling to a single page, and tall image with caption remaining on one page.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Suggested reviewers: nperez0111

Poem

A rabbit hopped through pixels and points,
Fixing ratios at page-break joints,
No more squished bunnies stretched too wide,
Now images scale with graceful pride,
Captions tucked snug, dimensions just right —
Thump-thump! 🐇✨ ship it tonight!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the PR’s main change: fixing image aspect ratio and page-fit behavior in xl-pdf-exporter.
Description check ✅ Passed The description includes the required summary, rationale, changes, impact, testing, screenshots, checklist, and notes sections.
Linked Issues check ✅ Passed The changes address [#2866] by preserving image aspect ratio, clamping image layout, and adding tests for tall images and captions.
Out of Scope Changes check ✅ Passed No obvious unrelated code changes stand out; the edits are limited to PDF image sizing, tests, and the test file resolver.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (3)
packages/xl-pdf-exporter/src/pdf/defaultSchema/blocks.tsx (1)

295-329: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

exporter: any parameter defeats the existing type via internal cast.

imageStyle takes exporter: any then immediately casts it to PDFExporter<any, any, any> internally (Line 300). Typing the parameter as PDFExporter<any, any, any> directly would preserve type-checking on exporter.styles at call sites and remove the redundant cast.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/xl-pdf-exporter/src/pdf/defaultSchema/blocks.tsx` around lines 295 -
329, The imageStyle helper currently accepts exporter as any and then
immediately casts it to PDFExporter<any, any, any>, which bypasses type safety.
Update imageStyle to type the exporter parameter directly as PDFExporter<any,
any, any> and remove the internal cast so exporter.styles is checked at the call
sites and the redundant any is eliminated.
packages/xl-pdf-exporter/src/pdf/pdfExporter.tsx (1)

32-37: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Manually-synced magic constant risks silent drift.

PAGE_HEIGHT must be kept in sync by hand with the <Page size="A4"> element (Line 270). If that size prop ever changes, this constant silently goes stale and imageStyle's maxHeight clamp (in blocks.tsx) will be wrong without any compile-time or test signal tying the two together.

Consider deriving the page height from a single shared source (e.g. a PAGE_SIZE object passed to both <Page size=...> and used to compute PAGE_HEIGHT), or at minimum adding a runtime assertion/test that fails if they diverge.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/xl-pdf-exporter/src/pdf/pdfExporter.tsx` around lines 32 - 37, The
PAGE_HEIGHT constant in pdfExporter.tsx is manually synchronized with the <Page
size="A4"> prop and can drift silently. Update the
pdfExporter/toReactPDFDocument flow to use a single shared PAGE_SIZE source for
both the <Page> component and PAGE_HEIGHT, or add a runtime/test assertion that
verifies the computed height still matches the page size used by
toReactPDFDocument and the maxHeight clamp in blocks.tsx.
packages/xl-pdf-exporter/src/pdf/pdfExporter.test.tsx (1)

272-316: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

Byte-level regex for page count is a bit brittle but acceptable here.

pdf.match(/\/Type\s*\/Page[^s]/g)).toHaveLength(1) inspects raw PDF bytes rather than parsing PDF structure. It correctly excludes /Type /Pages via the negative-lookahead-style [^s], but any future react-pdf output change (e.g. extra whitespace variants, or a /Type /Page appearing in an unrelated object such as an XObject dictionary) could make this fragile. A PDF-parsing library (e.g. pdf-lib) would give a more robust page count, but that's a heavier lift than warranted here for two tests.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/xl-pdf-exporter/src/pdf/pdfExporter.test.tsx` around lines 272 -
316, The page-count assertions in these PDFExporter tests rely on matching raw
PDF bytes with a brittle regex. Update the two tests in PDFExporter.test.tsx to
count pages using a PDF parser such as pdf-lib instead of matching /Type /Page
in the buffer, and keep the assertions in the existing image-scaling and caption
cases tied to the PDF generated by PDFExporter.toReactPDFDocument.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/xl-pdf-exporter/src/pdf/defaultSchema/blocks.tsx`:
- Around line 295-329: The imageStyle helper currently accepts exporter as any
and then immediately casts it to PDFExporter<any, any, any>, which bypasses type
safety. Update imageStyle to type the exporter parameter directly as
PDFExporter<any, any, any> and remove the internal cast so exporter.styles is
checked at the call sites and the redundant any is eliminated.

In `@packages/xl-pdf-exporter/src/pdf/pdfExporter.test.tsx`:
- Around line 272-316: The page-count assertions in these PDFExporter tests rely
on matching raw PDF bytes with a brittle regex. Update the two tests in
PDFExporter.test.tsx to count pages using a PDF parser such as pdf-lib instead
of matching /Type /Page in the buffer, and keep the assertions in the existing
image-scaling and caption cases tied to the PDF generated by
PDFExporter.toReactPDFDocument.

In `@packages/xl-pdf-exporter/src/pdf/pdfExporter.tsx`:
- Around line 32-37: The PAGE_HEIGHT constant in pdfExporter.tsx is manually
synchronized with the <Page size="A4"> prop and can drift silently. Update the
pdfExporter/toReactPDFDocument flow to use a single shared PAGE_SIZE source for
both the <Page> component and PAGE_HEIGHT, or add a runtime/test assertion that
verifies the computed height still matches the page size used by
toReactPDFDocument and the maxHeight clamp in blocks.tsx.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8ebcee73-1b04-418d-80a7-e38259f43f4f

📥 Commits

Reviewing files that changed from the base of the PR and between 3094559 and 1e76b69.

⛔ Files ignored due to path filters (3)
  • packages/xl-pdf-exporter/src/pdf/__snapshots__/example.jsx is excluded by !**/__snapshots__/**
  • packages/xl-pdf-exporter/src/pdf/__snapshots__/exampleWithAlignedImages.jsx is excluded by !**/__snapshots__/**
  • packages/xl-pdf-exporter/src/pdf/__snapshots__/exampleWithHeaderAndFooter.jsx is excluded by !**/__snapshots__/**
📒 Files selected for processing (4)
  • packages/xl-pdf-exporter/src/pdf/defaultSchema/blocks.tsx
  • packages/xl-pdf-exporter/src/pdf/pdfExporter.test.tsx
  • packages/xl-pdf-exporter/src/pdf/pdfExporter.tsx
  • shared/util/testFileResolver.ts

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.

PDF export : image ratio not kept

1 participant