Skip to content

BL-15958 Expand full-bleed page-size support and dotImpose handoff - #8263

Merged
StephenMcConnel merged 1 commit into
masterfrom
BL-15958-page-sizes
Oct 8, 2026
Merged

StephenMcConnel merged 1 commit into
masterfrom
BL-15958-page-sizes

Conversation

@hatton

@hatton hatton commented Aug 31, 2026 •

Copy link
Copy Markdown
Member

[Claude Opus 5.5 from Hatton's machine during preflight]

Part 2 of 3 of the BL-15958 work, split out of #7713. Independent of the other two: the edge-to-edge theme (#8262, merged) and edit-mode crop marks (#8264).

Problem

Bloom could make a full-bleed PDF at only six paper sizes (A5, A4, A3, USComic, HalfFolio, Size6x9), each hard-coded in C#. The edge-to-edge theme lets a book at any size run its pictures to the paper's edge, so printing it with bleed needs every paper size to work. Page dimensions were also parsed separately by each part of the code that needed them.

What the PR does

  • One source of page sizes. The front-end build writes output/browser/pageSizesLookup.json from DistFiles/pageSizes.json: every layout's width and height in millimeters, plus base names (A4), ISO A/B sizes and square sizes. SizeAndOrientation reads it. ePUB page dimensions and PDF full-bleed sizes now come from it instead of their own parsing and the hard-coded list.
  • Full bleed at every paper size. Letter, Legal, B5, A6, Cm13 and the other paper sizes now offer full bleed. Device, Ebook and PictureStory layouts are screen shapes and still don't.
  • Explicit trim and bleed boxes. Before handing a full-bleed PDF to dotImpose, Bloom writes each page's trim and bleed boxes itself. It uses dotImpose 2.6.8 (a release from nuget.org) and its NullLayoutMethod(), which reads those boxes.
  • Booklets and crop marks. Booklet layouts keep trim-sized source pages. Crop marks turn on automatically when printing with bleed.

Risk Evaluation

Moderate, in publishing paths. SizeAndOrientation.SupportsFullBleed runs whenever a book's full-bleed setting is read, and now loads the lookup file (once, then cached). If that file is missing, every such read throws, which is why the file must come from the front-end build. Every full-bleed PDF now goes through the new box-writing code in PdfMaker before dotImpose. Every fixed-layout ePUB gets its viewport size from the lookup.

Ecosystem Impact

  • PDF: full-bleed output is now possible at more paper sizes, and every full-bleed PDF carries explicit trim and bleed boxes. Non-bleed PDFs are unchanged.
  • ePUB: viewport dimensions are unchanged for every layout in pageSizes.json, Device16x9 included (unit tests).
  • Dependency: sillsdev.dotImpose goes from 2.6.2 to 2.6.8.
  • Installer: the lookup ships as part of output/browser, which Bloom.proj already copies.
  • Bloom Player, BloomPUB, the book file format and older Bloom versions are not affected. No new localizable strings (one developer-facing error message changed).
  • Not checked by hand: printing a real full-bleed PDF at one of the newly enabled sizes from a running Bloom.

E2E Coverage

No e2e test covers full-bleed PDF output. rotate-and-flip-images.spec.ts previews an ePUB and a PDF of a normal (non-bleed) book, so it runs the ePUB dimension and plain PDF paths. The full-bleed sizes, page boxes and Ebook exclusion are covered by unit tests in PdfMakerTests, MakePdfUsingExternalPdfMakerProgramTests and EPubMakerTests.

Notion Test Suite

None.

Preflight report: https://bloombooks.github.io/dev-process-artifacts/deciders/BloomDesktop-BL-15958-page-sizes.html

Ref: https://issues.bloomlibrary.org/youtrack/issue/BL-15958

🤖 Generated with Claude Code


This change is Reviewable

Devin review

@greptile-apps

greptile-apps Bot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR centralizes page-size dimensions in a generated millimeter lookup and expands the PDF full-bleed pipeline to additional paper sizes and the dotImpose handoff.

  • Generates and distributes pageSizesLookup.json from the canonical page-size configuration.
  • Reuses the lookup for ePub dimensions and full-bleed PDF sizing.
  • Reconstructs PDF trim, bleed, crop, and art boxes before imposition.
  • Keeps booklet source pages trim-sized and adds PDF sizing/box tests.

Important Files Changed

Filename Overview
src/BloomExe/Book/SizeAndOrientation.cs Adds lazy loading and orientation-aware access to generated millimeter dimensions; the two new public methods need documentation comments.
src/content/pageSizes.ts Extends the existing page-size build step to deterministically generate a C#-consumable lookup with configured, ISO-series, and square aliases.
src/BloomExe/Publish/PDF/MakePdfUsingExternalPdfMakerProgram.cs Replaces the fixed full-bleed size switch with lookup-backed trim dimensions plus a 3 mm bleed on every edge.
src/BloomExe/Publish/PDF/PdfMaker.cs Recreates page boxes before dotImpose and supplies a consistent 3 mm full-bleed inset; compatibility with the currently published dotImpose behavior remains explicitly acknowledged by the PR.
src/BloomExe/Publish/PDF/PublishPdfApi.cs Automatically synchronizes crop-mark generation with the selected book's print-bleed preference.
src/BloomExe/Publish/PublishModel.cs Restricts bleed-sized source pages to non-booklet output so imposed booklet layouts continue using trim dimensions.
src/BloomExe/Publish/Epub/EpubMaker.cs Reuses the generated millimeter lookup and converts dimensions to CSS pixels for ePub output.
src/BloomTests/Publish/PDF/PdfMakerTests.cs Adds bleed-offset and dotImpose TrimBox coverage, including the dependency behavior explicitly called out as unresolved.
src/BloomTests/Publish/PDF/MakePdfUsingExternalPdfMakerProgramTests.cs Covers expanded portrait, landscape, square, and unsupported full-bleed page-size handling.

Reviews (1): Last reviewed commit: "BL-15958 Expand full-bleed page-size sup..." | Re-trigger Greptile

@hatton hatton left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@hatton+JHAI made 2 comments.
Reviewable status: 0 of 13 files reviewed, all discussions resolved.


src/BloomExe/Publish/PDF/MakePdfUsingExternalPdfMakerProgram.cs line 380 at r2 (raw file):

        /// <param name="landscape">True if landscape orientation, false if portrait</param>
        /// <returns>A tuple of (height, width) in mm, or null if the page size doesn't support full bleed</returns>
        public static (double height, double width)? GetFullBleedPageSize(

[Claude Opus 5.5 following a prompt from Hatton]

Why this method could shrink so much:

The old switch listed the six sizes that supported full bleed (A5, A4, A3, USComic, HalfFolio, Size6x9), with their portrait trim sizes hard-coded here in millimeters, and swapped width and height for landscape. The trim size now comes from SizeAndOrientation.TryGetPaperLayoutInMillimeters, which reads the same DistFiles/pageSizesLookup.json that the build generates from pageSizes.json. It handles orientation too: it uses the ...Portrait or ...Landscape entry when one exists and otherwise rotates the other orientation, as the old if (landscape) swap did. That is why the A4/A3 constants and the swap are gone.

What a reviewer can check:

  • The six old sizes get the same trim sizes as before: A5 148x210 mm, A4 210x297 mm, A3 297x420 mm, USComic 6.625x10.25 in, HalfFolio 6.5x8.5 in, Size6x9 6x9 in. The 3 mm bleed on each side is still added here.
  • Every other paper size in pageSizes.json (Letter, Legal, HalfLetter, QuarterLetter, B5, A6, Cm13, ...) now supports full bleed too. This PR is meant to do that, and it is why the error message no longer lists the supported sizes.
  • Device and PictureStory layouts still return null. The lookup contains them because ePUB needs them, but TryGetPaperLayoutInMillimeters rejects those names before it looks anything up.

MakePdfUsingExternalPdfMakerProgramTests covers this: GetFullBleedPageSize_SupportedPaperSize_ReturnsBleedDimensions (A0, A6, B5, Letter, Legal, HalfLetter, QuarterLetter, USComic, Size6x9, Cm13, In8), GetFullBleedPageSize_Landscape_SwapsDimensions, and GetFullBleedPageSize_NonPaperLayout_ReturnsNull (Device16x9, an unknown name, empty, null).


src/BloomExe/Publish/Epub/EpubMaker.cs line 592 at r2 (raw file):

        }

        public static void GetPageDimensions(string pageSize, out double width, out double height)

[Claude Opus 5.5 following a prompt from Hatton]

Why this method could shrink so much:

The old code read pageSizes.json on every call, looped over the entries, and turned each px/mm/in string into pixels with ConvertDimension. The build now does the reading and unit conversion once. src/content/pageSizes.ts reads pageSizes.json and writes every entry, in millimeters, to DistFiles/pageSizesLookup.json. SizeAndOrientation.TryGetSizeInMillimeters loads that file once and caches it. The only step left here is converting millimeters to pixels at 96 DPI.

Behavior stays the same:

  • Every size listed in pageSizes.json is in the lookup with the same dimensions, Device16x9 and PictureStory included.
  • An unknown name still falls back to A5Portrait. The old code used sizes[0], which is A5Portrait.
  • Number parsing still ignores the user's culture: Node parses the JSON at build time, and C# reads the result through Json.NET, which parses invariantly.
  • One difference: name matching now ignores case (StringComparer.OrdinalIgnoreCase). The old code needed an exact match.

EPubMakerTests.GetPageDimensions covers sizes given in mm, inches and px, Device16x9 in both orientations, and an unknown name.

@hatton hatton left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@hatton+JHAI made 2 comments.
Reviewable status: 0 of 13 files reviewed, all discussions resolved.


src/BloomExe/Publish/Epub/EpubMaker.cs line 592 at r2 (raw file):

Previously, hatton+JHAI (Agent JHAI for John Hatton) wrote…

[Claude Opus 5.5 following a prompt from Hatton]

Why this method could shrink so much:

The old code read pageSizes.json on every call, looped over the entries, and turned each px/mm/in string into pixels with ConvertDimension. The build now does the reading and unit conversion once. src/content/pageSizes.ts reads pageSizes.json and writes every entry, in millimeters, to DistFiles/pageSizesLookup.json. SizeAndOrientation.TryGetSizeInMillimeters loads that file once and caches it. The only step left here is converting millimeters to pixels at 96 DPI.

Behavior stays the same:

  • Every size listed in pageSizes.json is in the lookup with the same dimensions, Device16x9 and PictureStory included.
  • An unknown name still falls back to A5Portrait. The old code used sizes[0], which is A5Portrait.
  • Number parsing still ignores the user's culture: Node parses the JSON at build time, and C# reads the result through Json.NET, which parses invariantly.
  • One difference: name matching now ignores case (StringComparer.OrdinalIgnoreCase). The old code needed an exact match.

EPubMakerTests.GetPageDimensions covers sizes given in mm, inches and px, Device16x9 in both orientations, and an unknown name.

[Claude Opus 5.5 following a prompt from Hatton]

Correction: since commit 22f162c the lookup is generated to output/browser/pageSizesLookup.json, not DistFiles/pageSizesLookup.json, and SizeAndOrientation reads it through BloomFileLocator.GetBrowserFile. The rest of the comment above still holds.


src/BloomExe/Publish/PDF/MakePdfUsingExternalPdfMakerProgram.cs line 380 at r2 (raw file):

Previously, hatton+JHAI (Agent JHAI for John Hatton) wrote…

[Claude Opus 5.5 following a prompt from Hatton]

Why this method could shrink so much:

The old switch listed the six sizes that supported full bleed (A5, A4, A3, USComic, HalfFolio, Size6x9), with their portrait trim sizes hard-coded here in millimeters, and swapped width and height for landscape. The trim size now comes from SizeAndOrientation.TryGetPaperLayoutInMillimeters, which reads the same DistFiles/pageSizesLookup.json that the build generates from pageSizes.json. It handles orientation too: it uses the ...Portrait or ...Landscape entry when one exists and otherwise rotates the other orientation, as the old if (landscape) swap did. That is why the A4/A3 constants and the swap are gone.

What a reviewer can check:

  • The six old sizes get the same trim sizes as before: A5 148x210 mm, A4 210x297 mm, A3 297x420 mm, USComic 6.625x10.25 in, HalfFolio 6.5x8.5 in, Size6x9 6x9 in. The 3 mm bleed on each side is still added here.
  • Every other paper size in pageSizes.json (Letter, Legal, HalfLetter, QuarterLetter, B5, A6, Cm13, ...) now supports full bleed too. This PR is meant to do that, and it is why the error message no longer lists the supported sizes.
  • Device and PictureStory layouts still return null. The lookup contains them because ePUB needs them, but TryGetPaperLayoutInMillimeters rejects those names before it looks anything up.

MakePdfUsingExternalPdfMakerProgramTests covers this: GetFullBleedPageSize_SupportedPaperSize_ReturnsBleedDimensions (A0, A6, B5, Letter, Legal, HalfLetter, QuarterLetter, USComic, Size6x9, Cm13, In8), GetFullBleedPageSize_Landscape_SwapsDimensions, and GetFullBleedPageSize_NonPaperLayout_ReturnsNull (Device16x9, an unknown name, empty, null).

[Claude Opus 5.5 following a prompt from Hatton]

Correction: since commit 22f162c the lookup is generated to output/browser/pageSizesLookup.json, not DistFiles/pageSizesLookup.json, and SizeAndOrientation reads it through BloomFileLocator.GetBrowserFile. The rest of the comment above still holds.

@hatton

hatton commented Oct 7, 2026

Copy link
Copy Markdown
Member Author

[Claude Opus 5.5 from Hatton's machine during preflight] @greptile-apps review

Comment thread src/content/pageSizes.ts
Comment thread src/BloomExe/Publish/PDF/MakePdfUsingExternalPdfMakerProgram.cs
Comment thread src/content/pageSizes.ts
Comment thread src/BloomExe/Book/SizeAndOrientation.cs
Comment thread src/BloomExe/Book/SizeAndOrientation.cs
Comment thread src/BloomTests/Publish/PDF/PdfMakerTests.cs
Comment thread src/BloomExe/Publish/PDF/PdfMaker.cs
@hatton

hatton commented Oct 7, 2026 •

Copy link
Copy Markdown
Member Author

[Claude Opus 5.5 from Hatton's machine during preflight] Consulted Devin on 2026-10-07 21:04 UTC up to commit 9aff745. It raised 4 bugs and 5 Investigate flags. It marks 2 of the bugs fixed (Ebook layouts offering full bleed, fixed in 9aff745; crop marks with old dotImpose, fixed by the 2.6.8 pin). The other 7 each have a review thread with its outcome: 1 fixed, 6 not an issue or no longer applying to the current code.

@hatton hatton left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@hatton reviewed 13 files and all commit messages.
Reviewable status: 0 of 13 files reviewed, 7 unresolved discussions.

Full-bleed PDFs were possible at only six hard-coded paper sizes. The
front-end build now writes output/browser/pageSizesLookup.json from
DistFiles/pageSizes.json (millimeter sizes plus base-name, ISO A/B and
square aliases), and SizeAndOrientation reads it. ePUB viewport sizes and
PDF full-bleed sizes come from that lookup, so every paper size supports
full bleed; Device, Ebook and PictureStory layouts still do not.

Before dotImpose, PdfMaker writes each full-bleed page's trim and bleed
boxes (3 mm bleed), and NoBooklet uses dotImpose 2.6.8's parameterless
NullLayoutMethod, which reads them. Booklets keep trim-sized source pages.
Crop marks turn on automatically when printing with bleed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@hatton
hatton force-pushed the BL-15958-page-sizes branch from 9aff745 to f635184 Compare October 7, 2026 21:58
@hatton
hatton marked this pull request as ready for review October 7, 2026 21:59

@StephenMcConnel StephenMcConnel 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.

@StephenMcConnel reviewed 13 files and all commit messages, and resolved 7 discussions.
Reviewable status: :shipit: complete! all files reviewed, all discussions resolved (waiting on hatton).

@StephenMcConnel StephenMcConnel 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.

Reviewable status: :shipit: complete! all files reviewed, all discussions resolved (waiting on hatton).

@StephenMcConnel
StephenMcConnel merged commit fafc42e into master Oct 8, 2026
2 checks passed
@StephenMcConnel
StephenMcConnel deleted the BL-15958-page-sizes branch October 8, 2026 17:07
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.

2 participants