Open SeaRyanC opened 3 years ago
Thanks for reporting this. There is indeed a discrepancy between measureText
and strokeRect
(and probably all other methods). The issue is that most context2d methods don't respect the document unit. Instead, all parameters are interpreted as if they were given in the document unit instead of in pixels.
The desired behavior should be that all parameters are interpreted as pixels and converted to the document unit. A pull request to fix this would be very appreciated.
Can I work on this one ?
Sure ;)
Thanks @HackbrettXXX .. I am working on it..
There appears to be no problem with measureText()
, as it returns for me functionally the same value as the real HTML Canvas context in my browser.
HTML Canvas: measureText(text).width
: 214.1666717529297
jsPDF canvas: measureText(text).width
: 213.75465599999995
The actual problem appears to be that the font rendering itself isn't applying the proper 96.0 / 72.0
transform between points and canvas pixels.
HTML Canvas
jsPDF canvas
This quick monkey patch fixes things for me, so this may be a simple fix in the jsPDF code. It applies the necessary scale to get the text to render at the correct size, and applies the inverse of the scale modifier to the position and width parameter since those are already correctly scaled internally. Note that I only applied x-axis scaling as my understanding is that jsPDF does not support y-axis scaling with text currently.
const oldFillText = ctx.fillText
ctx.fillText = (text, x, y, w) => {
const scale = 96.0 / 72.0
const invScale = 1.0 / scale
ctx.save()
ctx.scale(scale, 1)
oldFillText.call(ctx, text, x * invScale, y, w * invScale)
ctx.restore()
}
jsPDF canvas (patched)
😊 "I'd be delighted to work on this issue, @SeaRyanC ! Could you please assign it to me?"
Context2d.measureText
saysstrokeRect
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 widthThe top line, shown here, is not the same width as the text:
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