Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

doc.internal.pageSize.getWidth() doesn't match measured value #2927

Closed
Tobbe opened this issue Sep 23, 2020 · 11 comments
Closed

doc.internal.pageSize.getWidth() doesn't match measured value #2927

Tobbe opened this issue Sep 23, 2020 · 11 comments

Comments

@Tobbe
Copy link

Tobbe commented Sep 23, 2020

function pdf() {
  const { jsPDF } = window.jspdf;
  const doc = new jsPDF("p", "px", "a4");
  const pageWidth = doc.internal.pageSize.getWidth();
  console.log("pageWidth", pageWidth);
  
  doc.save("pagesize.pdf")
}

You can run the above code here: https://jsfiddle.net/6htnzja8/1/

Running the example code and looking in the console jsPDF says the page width is 446.46 pixels. If I take a screenshot of the generated PDF and measure the size it's actually 793 pixels wide.

I think the value reported by jsPDF is wrong. Is it, or am I misunderstanding something?

@HackbrettXXX
Copy link
Collaborator

HackbrettXXX commented Sep 24, 2020

getWidth returns this:

    return (
      (pagesContext[pageNumber].mediaBox.topRightX -
        pagesContext[pageNumber].mediaBox.bottomLeftX) /
      scaleFactor
    );

scaleFactor is the factor that's multiplied to a value in px to get the value in pt (pdf units).

And the media box is printed to the PDF like this (in pdf units/`pt) (the media box is basically the page size):

    out(
      "/MediaBox [" +
        parseFloat(hpf(page.mediaBox.bottomLeftX)) +
        " " +
        parseFloat(hpf(page.mediaBox.bottomLeftY)) +
        " " +
        hpf(page.mediaBox.topRightX) +
        " " +
        hpf(page.mediaBox.topRightY) +
        "]"
    );

So the value returned from pageWidth should the correct width in px. How did you "measure" the width of the PDF? Did you make sure to use a 1:1 zoom? Or do you maybe use a high dpi display?

@Tobbe
Copy link
Author

Tobbe commented Sep 24, 2020

image

Did you mean to post some code?

@Tobbe
Copy link
Author

Tobbe commented Sep 24, 2020

Digging in to the code I found this

  switch (unit) {
    case "pt":
      scaleFactor = 1;
      break;
    case "mm":
      scaleFactor = 72 / 25.4;
      break;
    case "cm":
      scaleFactor = 72 / 2.54;
      break;
    case "in":
      scaleFactor = 72;
      break;
    case "px":
      if (hasHotfix("px_scaling") == true) {
        scaleFactor = 72 / 96;
      } else {
        scaleFactor = 96 / 72;
      }
      break;
    case "pc":
      scaleFactor = 12;
      break;
    case "em":
      scaleFactor = 12;
      break;
    case "ex":
      scaleFactor = 6;
      break;
    default:
      throw new Error("Invalid unit: " + unit);
  }

I don't think this simplistic approach works 🙁 The amount of pixels needed to represent an inch (or pt for that matter) is going to depend on the monitor PPI

@HackbrettXXX
Copy link
Collaborator

Yeah, accidentally hit "comment" there..., it's fixed, now.

@Tobbe
Copy link
Author

Tobbe commented Sep 24, 2020

@HackbrettXXX
Copy link
Collaborator

By px we mean "css pixels", which are fixed to 1px = 1/96in. See also my comment.

@Tobbe
Copy link
Author

Tobbe commented Sep 24, 2020

Creating an "a4" pdf with "pt" size the width is 595.28. Taking a screenshot (at 100% zoom) on my display (Dell XPS 9550, 1920x1080) the page is 793 px. So here the scale factor is ~1.33. But creating an "a4" pdf with "px" size the size is reported as 446.46, implying that the scale factor is ~0.75.

So probably related to this: if (hasHotfix("px_scaling") == true) {

What is that hotfix thing?

@Tobbe
Copy link
Author

Tobbe commented Sep 24, 2020

@Tobbe
Copy link
Author

Tobbe commented Sep 24, 2020

Enabling the px_scaling hotfix makes it work as it's supposed to 👍

@Tobbe Tobbe closed this as completed Sep 24, 2020
@HackbrettXXX
Copy link
Collaborator

Yeah, for myself and for future reference, I did the math once again:

96px = 1in (css pixels)
72pt = 1in   (PDF 1.3 specification)

-> 96px = 72pt
-> 1px = 72/96pt

Which means we have to multiply each pixel by 72/96 to get pt. So the scaleFactor of 72/96 is correct and one has to enable the hotfix in order to get the correct scaling for pixels. We should really document that the hotfix is required for the px unit and make this the default with the next major release.

Thanks for bringing that up ;)

@iron2414
Copy link

iron2414 commented Apr 15, 2021

Is this still working? I am using jsPDF 2.3.1 and trying to put images inside a pdf, but they get blurry. When i try to enable "px_scaling" mentioned here, and https://github.com/MrRio/jsPDF/blob/master/HOTFIX_README.md the code won't compile. After checking the package, there is no "hotfix" in the code, and the jsPDF constructor only takes "jsPDFOptions"

  export interface jsPDFOptions {
    orientation?: "p" | "portrait" | "l" | "landscape";
    unit?: "pt" | "px" | "in" | "mm" | "cm" | "ex" | "em" | "pc";
    format?: string | number[];
    compress?: boolean;
    precision?: number;
    filters?: string[];
    userUnit?: number;
    encryption?: EncryptionOptions;
  }

Edit: I had to pass it in as a constructor parameter, and surpress the statement with // @ts-ignore. It works now properly.

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

No branches or pull requests

3 participants