parallax/jsPDF

context2d.measureText returns incorrect value

Open

#3,225 opened on Aug 3, 2021

View on GitHub
 (6 comments) (2 reactions) (0 assignees)JavaScript (4,596 forks)batch import
Bugdifficulty:mediumhacktoberfest

Repository metrics

Stars
 (28,280 stars)
PR merge metrics
 (No merged PRs in 30d)

Description

Context2d.measureText says

The measureText() method returns an object that contains the width of the specified text, in pixels.

strokeRect also takes a width in pixels. This program creates a PDF with the text "hello world", and prints a rectangle below it according to its measured width

const jspdf = require("jspdf");
const fs = require("fs");

const doc = new jspdf.jsPDF({
    unit: "mm",
    format: [8.5 * 25.4, 11 * 25.4],
});

const ctx = doc.context2d;

doc.setFont("Helvetica");
doc.setFontSize(12);
doc.setFillColor(0, 0, 0);

const width = ctx.measureText("hello world");
ctx.fillText("hello world", 50, 50);

// Reported width
ctx.strokeRect(50, 55, width.width, 2);
// Correction attempt 1
ctx.strokeRect(50, 60, width.width / 2.8346456, 2);
// Correction attempt 2
ctx.strokeRect(50, 65, width.width / 2.8346456 * (96 / 72), 2);
// Correction attempt 3
ctx.strokeRect(50, 70, width.width / 2.8346456 * (72 / 96), 2);

fs.writeFile("test.pdf", Buffer.from(doc.output("arraybuffer")), () => {});

The top line, shown here, is not the same width as the text: image

The next three lines show how to get from the returned value from the correct value; it looks like a lot of the math inside the implementation isn't necessary.

Additionally, the documented return type is Number, but it actually returns an object of the form { width: number } (as described in the general description).

https://github.com/MrRio/jsPDF/blob/cef97fb34eda41a8704c9f3983e680919a328ce4/src/modules/context2d.js#L1388

Contributor guide