Skip to content

Table align y not working #1620

Open
Open

Description

@AntoninD-Galadrim

Bug Report

Table align doesn't seem to work vertically

Description of the problem

Image

Code sample

(doc as any).table({
data: [
[
{
align: { y: 'bottom' },
backgroundColor: '#ccc',
text: 'test',
},
],
],
});

Your environment

pdfkit 0.17.1

Activity

  1. hollandjake commented on Jun 9, 2025

    @hollandjake
    Contributor

    Hi @AntoninD-Galadrim, since there is no other content on the row and the row is dynamically sized (since you haven't specified the height), it means that the height is the smallest it can be hence the alignY does nothing in this case.

    If you enable table({debug: true, ...}) you will see where the bounds of your text is.

    What you are likely looking at is a result of either the fonts baseline being wrong, or you have modified the text baseline.

    If you are still seeing this, can you send a screenshot with debug enabled

  2. hollandjake commented on Jun 9, 2025

    @hollandjake
    Contributor

    Image

    For reference here is what your example code generates (with debug enabled for clarity)

  3. AntoninD-Galadrim commented on Jun 12, 2025

    @AntoninD-Galadrim
    Author

    @hollandjake

      const doc = new PDFDocument();
      (doc as any).table({
        debug: true,
        data: [
          [
            {
              align: { y: 'bottom' },
              text: 'test',
            },
          ],
        ],
      });
      doc.end();
    
    Image

    This is what I get on my end, default font and everything.

  4. hollandjake commented on Jun 12, 2025

    @hollandjake
    Contributor

    Thank you for that, managed to replicate too. Investigating, it seems that the calculation for how high a line is, is always factoring in the lineGap despite that line being the last line in the string. This replicated the same behaviour as the heightOfString method. @blikblum thoughts on whether this is correct behaviour?

    For reference this also occurs in the doc.text method, moving the last lines y position to the next line including the gap.

    If we don't want this behaviour and we want the last line to exclude the gap. with some tweaks to the lineWrapper, and the heightOfString function. we can get the following:

    Image

    Where the height of the first textBox is computed with heightOfString you can see the line it cut, however the doc.y position is still including the gap so subsequent calls still use the gap. Code branch: https://github.com/hollandjake/pdfkit/tree/text-last-line-gap

  5. blikblum commented on Jun 12, 2025

    @blikblum
    Member

    thoughts on whether this is correct behaviour?

    At first look no.

    Need to look for the possible behavior changes in other use cases.

  6. blikblum commented on Jun 12, 2025

    @blikblum
    Member

    Assuming lineGap is the equivalent to line height is should be applied only between lines of text, description from google / AI:

    Font line height, also known as "leading," is the vertical space between lines of text. It's a fundamental typographic practice, impacting readability and making text easier to scan and understand. Line height is set in CSS, either by a percentage of the font size or a fixed length unit.
    Elaboration:

    Measurement:
    Line height is measured from the baseline of one line to the baseline of the next. 
    

    Units:
    It can be expressed in various units like pixels (px), em, rem, or as a percentage of the font size.

    Impact on Readability:
    Proper line height ensures enough space between lines, preventing text from looking dense and crowded, especially when using smaller fonts.

  7. blikblum commented on Jun 12, 2025

    @blikblum
    Member

    Although the specs hints it applies only between text lines, in browser css it affects before and after text

    https://developer.mozilla.org/en-US/play?id=arr45vJCgMKYeU1CksvmAB7uY9pKTMusgCGBNY5ZHI20jxBn9azXgmoDR9QaEgN9RhY3%2Brkx5EglCwRG

    We should evaluate how other pdf libs, typesetting systems (typst), handle this

  8. hollandjake commented on Jun 16, 2025

    @hollandjake
    Contributor

    @blikblum findings so far:

    • pdfmake:
      Image

    • css:
      Image

    • iterm:
      Image

    • quest pdf:
      Image

    if you want any more let me know.

    if we want, we could preserve existing behaviour (including the trailing space) by putting it behind an option flag in the heightOfString / boundsOfString / table functions

  9. blikblum commented on Jun 16, 2025

    @blikblum
    Member

    if we want, we could preserve existing behaviour (including the trailing space) by putting it behind an option flag in the heightOfString / boundsOfString / table functions

    It is better. You can use this option in table and let current behavior in other places

  10. hollandjake commented on Jun 17, 2025

    @hollandjake
    Contributor

    @blikblum just been doing some more testing and I noticed that the trailing line gap issue is only occuring in the system fonts, using roboto it does not cause it. could this be a disparity between system font and the internal font?#

    helvetica (system default):

    Image

    roboto (custom font):

    Image

  11. hollandjake commented on Jun 17, 2025

    @hollandjake
    Contributor

    using the feature flag on a default system font, we can now achieve the following:

    Image

    Use on a custom font does not seem to cause or break when using the flag

  12. blikblum commented on Jun 18, 2025

    @blikblum
    Member

    could this be a disparity between system font and the internal font?

    Good find

    custom font uses fontkit, system font are handled internally

    i will look at it ASAP

  13. AntoninD-Galadrim commented on Aug 5, 2025

    @AntoninD-Galadrim
    Author

    Thanks for the work everyone.
    Any news/fixes on this ?

  14. AntoninD-Galadrim commented on Sep 3, 2025

    @AntoninD-Galadrim
    Author

    @blikblum Sorry for the ping, do you know if there is some fix or workaround ?

  15. blikblum commented on Sep 3, 2025

    @blikblum
    Member

    Its my next task. I looed at a list bug past weekend. Will look at it next

  16. AntoninD-Galadrim commented on Sep 23, 2025

    @AntoninD-Galadrim
    Author

    Sorry to bother again, any news on this ?

  17. blikblum commented on Sep 27, 2025

    @blikblum
    Member

    Started analysis. Tracked the difference values when rendering a table cell. Now discover why the difference

  18. blikblum commented on Oct 4, 2025

    @blikblum
    Member

    My conclusions

    There's nothing inherently wrong with table alignment code

    The difference is how standard and embedded fonts are rendered

    Standard font (Helvetica) are rendered on the top of line height while embedded (Roboto) adds a little padding to the top

    Standard has lineGap positive value while embedded is 0, so it "fixes" when not including lineGap in line height calculation

    Here is a program that demonstrates the difference

    var fs = require('fs');
    var PDFDocument = require('../js/pdfkit');
    
    var doc = new PDFDocument();
    doc.registerFont('Roboto', '../tests/fonts/Roboto-Regular.ttf');
    
    doc.pipe(fs.createWriteStream('line-gap.pdf'));
    
    doc.fontSize(12);
    
    doc.moveTo(10, 20);
    doc.lineTo(80, 20);
    doc.dash(1, { space: 1 }).lineWidth(1).strokeOpacity(0.3);
    doc.stroke('blue');
    doc.text('test', 10, 20);
    
    console.log(
      `font settings lineGap: ${doc._font.lineGap} ascender: ${doc._font.ascender} descender: ${doc._font.descender}`,
    );
    let lineHeight = doc.currentLineHeight(false);
    console.log('lineHeight (without lineGap):', lineHeight);
    let baseline = 20 + lineHeight;
    doc.moveTo(10, baseline);
    doc.lineTo(50, baseline);
    doc.stroke('green');
    
    lineHeight = doc.currentLineHeight(true);
    console.log('lineHeight (with lineGap):', lineHeight);
    baseline = 20 + lineHeight;
    doc.moveTo(10, baseline);
    doc.lineTo(50, baseline);
    doc.stroke('black');
    
    console.log('Using Roboto font');
    doc.font('Roboto');
    console.log(
      `font settings lineGap: ${doc._font.lineGap} ascender: ${doc._font.ascender} descender: ${doc._font.descender}`,
    );
    doc.text('test', 50, 20);
    lineHeight = doc.currentLineHeight(false);
    console.log('lineHeight (without lineGap):', lineHeight);
    lineHeight = doc.currentLineHeight(true);
    console.log('lineHeight (with lineGap):', lineHeight);
    baseline = 20 + lineHeight;
    doc.moveTo(50, baseline);
    doc.lineTo(80, baseline);
    doc.stroke('red');
    
    doc.end();

    Result:

    Image

    console output:

    font settings lineGap: 231 ascender: 718 descender: -207
    lineHeight (without lineGap): 11.100000000000001
    lineHeight (with lineGap): 13.872
    Using Roboto font
    font settings lineGap: 0 ascender: 927.734375 descender: -244.140625
    lineHeight (without lineGap): 14.0625
    lineHeight (with lineGap): 14.0625
    

    So, how to fix it?. At this stage, i don't know

    Need to investigate if the way standard fonts are rendered is the expected

    Also, test with other fonts Courier, Inter etc

  19. mike-ayres commented on Jan 13, 2026

    @mike-ayres

    Not sure if this is the same issue or a new one, but I added a lineGap to one of my cells with alignment of { x: 'left', y: 'center' } and it does not align. All the other cells do align as expected. My ultimate goal is to add a bit of padding above and below the text in each cell.

    If I add a new dummy column with some text and the same line gap & alignment, it does not align but the previous cell mentioned in the first sentence does align, like the rest of the cells. All of these columns are set to center on the y property.

    Image

    Tested on node 22.14.0 with pdfkit 0.17.2 and 0.17.4.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions