Is there any trick to rotate text in PDFKit?

8.6k views Asked by At

I'm using PDFKit.org to generate PDF via JavaScript.

The documentation is pretty self-explanatory, but I'm facing an unsolved problem, and I guess some StackOverflow members may have already found a trick to do it.

I have to rotate a text at some point, and the documentation only explain how to rotate a shape ( like a rect() ).

I already tried several things, but none of them work so far.

So I'm looking for either a way to rotate it by tweaking the code, or maybe some of you can show me a part of the documentation I may have missed?

4

There are 4 answers

3
Olivier Lance On

There's no special trick, but it's critical to correctly understand how transformations are applied in PDFKit.

The main thing to understand is that you don't rotate text or a shape: you rotate your document, as implied by doc.rotate(...).rect(...).

It might help you to see your document as a canvas with physical properties. One of its properties is its rotation.
If you want to draw rotated text on a page of paper, what you will likely do is physically rotate your page, then write some text horizontally as you'd usually do, then rotate back the page to its normal state.
What you end up with then, is a rotated text on a straight page:

This is exactly how PDFKit works: you apply a transformation on your document, draw everything you need to draw in this transformed context, and set back the document to its previous state.

To achieve that you have two methods: doc.save() and doc.restore().

  • Use save() before applying a transformation, so that everything that's been drawn before that isn't affected.
  • You can then transform your canvas and draw what you need
  • Once you've drawn everything that needed to be transformed, call restore() to put back the document in its initial state. It's basically going to roll back all transformations (ie. rotation, scaling, translation) performed after the latest save() call.

To (kinda) reproduce the above diagram you'd do:

doc.text('text', ...)
doc.save()
doc.rotate(90).text('rotated text', ...)
doc.restore()

One last thing to understand is that your document's coordinates system is affected by transformations:

So if text was drawn at coordinates (0, 0), then rotated text was drawn at something like (0, documentHeight / 2 - offset).
It's pretty easy to deal with when using multiples of 90 degrees rotations, but you'll have to play with trigonometry otherwise :)

To facilitate things, you can play with the origin of the rotation to make sure you rotate the document around a point that makes sense to your next drawings!

0
Tarmo Elfving On

I pulled my hair out a bit with that problem or fact described in the answer. Tried many things but text ended up going its own ways always.

Here is little clip that i used to place texts in different orientations. This function does the calculation of new x and y in rotated coordinate system.

var doTransform = function (x, y, angle) {
var rads = angle / 180 * Math.PI;
var newX = x * Math.cos(rads) + y * Math.sin(rads);
var newY = y * Math.cos(rads) - x * Math.sin(rads);

return {
    x: newX,
    y: newY,
    rads: rads,
    angle: angle
    };
};

This one then goes through array of texts that have x,y,rotation. Uncerscore used for looping.

var drawTexts = function (doc, texts) {

_.each(texts, t => {
    doc.save();
    doc.fontSize(t.size);
    var loc = doTransform(t.x, t.y, t.rotation);        
    doc.rotate(t.rotation);        
    doc.text(t.text, loc.x, loc.y);               
    doc.restore();
    });

};

First the 'world' is rotated and then the text is placed to the new (x,y) which is the same spot as (t.x,t.y) but in rotated world.

0
Olivier Allouch On

You can use svg. see https://pdfmake.github.io/docs/document-definition-object/svgs/

pdfmake uses svg-to-pdfkit for that.

transform="rotate...." seems supported in the source, see https://github.com/alafr/SVG-to-PDFKit/blob/master/source.js#L431 :

    } else if (func === 'rotate' && nums.length === 3) {
      let a = nums[0] * Math.PI / 180;
      result = multiplyMatrix(result, [1, 0, 0, 1, nums[1], nums[2]], [Math.cos(a), Math.sin(a), -Math.sin(a), Math.cos(a), 0, 0], [1, 0, 0, 1, -nums[1], -nums[2]]);
    }
0
Artur Pschybysz On

The best way to write rotated text is to rotate pdf around a certain point (where you want to have a starting point of your text), then write it and rotate the pdf document back. Code example:

doc.rotate(angle, { origin: [x,y] });
doc.text( 'TEST', x, y);
doc.rotate(angle * (-1), { origin: [x,y] });

This way you don't need to calculate a new position.

Also it's worth knowing that pdfkit takes x and y of our text as left top point of our texts "box" (it did matter in my case).