Skip to content

Align continued text with center or right alignment as one line - #1816

Closed
Likheet wants to merge 1 commit into
foliojs:masterfrom
Likheet:fix/240-continued-alignment
Closed

Likheet wants to merge 1 commit into
foliojs:masterfrom
Likheet:fix/240-continued-alignment

Conversation

@Likheet

@Likheet Likheet commented Oct 13, 2026

Copy link
Copy Markdown

What kind of change does this PR introduce?

Bug fix. Fixes #240 and #774.

With continued: true, each segment of a line is aligned on its own, in the space the previous segment left, so with align: 'center' or align: 'right' the segments overlap:

doc.text('Normal Text ', { align: 'center', continued: true }).text('Second segment');

On master "Normal" starts at x = 272.4 and "Second" at 294.6, on top of "Normal Text". The same text in a single call starts at 227.4 (word boxes from pdftotext -bbox).

As described in #240, the line has to be held back until the next segment is known. To avoid tracking the text state for that, the segments are drawn as usual, just not onto the page yet:

  • text() gets its own line callback, _textLine. A line of continued text with center or right alignment is drawn left aligned, and while it is held, everything addContent writes goes into the held line instead of the page, so color changes and anything else drawn between the segments keep their order.
  • Once the line is complete (another line starts, a text() call does not continue it, or before the page changes or the document ends), its segments are written inside q 1 0 0 1 dx 0 cm … Q, where dx is the offset the same line gets as a single text. It uses the same widths _fragment aligns by, now in _alignedWidth.
  • Links, goTo and destinations of the held segments are created after the move, with the CTM they were drawn with, so they cover the text.

Everything else takes the same path as before. I generated 600 random documents with left and justify continued text and with center and right text without continued, in Helvetica, Times and Courier, with links, underlines and indents, on master and on this branch, and they are byte-identical.

For center and right continued text, I compared 300 random texts split into 2 to 4 segments at word boundaries against the same text in one call: 295 are laid out identically. The other 5 break an over-long word at a different place, which master does with left alignment too. I used Courier for this because a continued segment is placed after the unkerned width of the previous one, so with a kerned font the words after the first segment can be off by a kerning pair from the single call, as they already are with left alignment.

The tests in tests/unit/text.spec.js read the output with pdf.js and check that continued text is laid out like the same text in one call: a single line, a line completed by text that wraps, a line followed by a page break, a document that ends while the line is held, links, and a line with segments in different font sizes. All 8 fail on master.

Checklist:

  • Unit Tests
  • Documentation
  • Update CHANGELOG.md
  • Ready to be merged

With continued: true each segment was aligned on its own, in the space
the previous segment left, so the segments of a center or right aligned
line overlapped (foliojs#240, foliojs#774).

Such a line is now held back until it is complete. Its segments are
drawn left aligned as usual, but into the held line instead of the
page, and once the line ends they are moved into place together, the
way a line of a single text call is aligned. Links, goTo and
destinations of the held line are added after the move.
@blikblum

Copy link
Copy Markdown
Member

This introduces a lot of complexity. The comment #240 (comment) is still valid.

As pointed, continued is a temporary / hackish solution to a proper layout system. pdfkit must remain lean, low level, providing primitives for a proper layout like pdfmake or react-pdf

@Likheet

Likheet commented Oct 14, 2026

Copy link
Copy Markdown
Author

Gotcha gotcha, thanks for taking a look. I’ll close this. Would a short note in the Rich Text docs be useful instead, saying center and right alignment don’t apply across continued segments? I can send that separately :)

@Likheet Likheet closed this Oct 14, 2026
@blikblum

Copy link
Copy Markdown
Member

Gotcha gotcha, thanks for taking a look. I’ll close this. Would a short note in the Rich Text docs be useful instead, saying center and right alignment don’t apply across continued segments? I can send that separately :)

Yes please a short one

In fact, this is something that we should look to provide in future just not in the core package or with continued API.

Something like:

const layout = beginLayout(doc)
layout.text('xxx', options)
layout.end()

This way we allow more advanced layout without bloating core experience

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.

Using continued with center and right alignment is broken

2 participants