PDFKit中旋转文本的技巧是什么?

11

我正在使用 PDFKit.org 来通过 JavaScript 生成 PDF。文档本身已经非常自解释,但我遇到了一个尚未解决的问题,我猜测 StackOverflow 的一些成员可能已经找到了一些诀窍来解决它。

我必须在某个时候旋转一段文字,但文档只讲解如何旋转形状(例如 rect())。

我已经尝试了几种方法,但是迄今为止都没有成功。

所以我正在寻找一种通过调整代码来旋转文本的方法,或者也许你们中的一些人可以向我展示我可能错过的文档部分?


阅读了示例的那部分后,我不得不问一下:为什么rotate对你没有起作用? - Jongware
1
实际上,rotate() 起作用了,但是缺失的部分是 save()restore() 函数,在 Olivier Lance 的回答中得以解决!所以基本上,在我最初的尝试中,我旋转了一次文档,而我的第二个 rotate()会搞乱 PDF 渲染,现在,由于 save() 的存在,我能够旋转一个包含文本的元素,并且不会弄乱事情 :) - LukyVj
4个回答

22

没有特殊技巧,但正确理解PDFKit中如何应用转换是至关重要的。

最主要的理解是:你不是旋转文本或形状:你旋转你的文档,正如doc.rotate(...).rect(...)所暗示的那样。

把文档看作具有物理属性的画布可能会对你有所帮助。它的一个属性是旋转。
如果您想在一页纸上绘制旋转的文本,您通常会做的是将页面物理旋转,然后水平书写一些文本,然后将页面旋转回到其正常状态。
然后你得到的是一个直立的页面上的旋转文本:

这正是PDFKit的工作方式:你在文档上应用变换,在这个变换的上下文中绘制你需要绘制的一切,然后将文档设置回其之前的状态。

为了实现这一点,你有两个方法:doc.save()doc.restore()

  • 在应用转换之前使用save(),以便在此之前绘制的所有内容不会受到影响。
  • 然后你可以转换你的画布并绘制你需要的东西
  • 当你绘制完需要变换的所有内容后,调用restore()将文档放回初始状态。这基本上会回滚执行最新的save()调用之后执行的所有变换(即旋转、缩放、平移)。

要想(有点)重现上面的图表,你可以这样做:

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

最后需要了解的一点是,文档的坐标系会受到变换的影响:

因此,如果text在坐标(0, 0)处绘制,则rotated text可能会绘制在(0, documentHeight / 2 - offset)之类的位置。
当使用90度的倍数旋转时,这非常容易处理,但如果不是,则需要使用三角函数进行调整 :)

为了方便处理,您可以调整旋转的原点,以确保将文档围绕合理的点旋转,适用于您接下来的绘图!


4
最好编写一个函数来完成这个任务,然后使用 drawRotatedText(x, y, angle, text) 方法进行绘制。(并将其添加到 PDFKit 中...) - Jongware
那是一个实现细节,但是没错 :) - Olivier Lance
Rad Lexus,这是一个有趣的选择,问题是我对PDFKit还不熟悉,因此不确定如何继续。如果你想把它做成Gist,那就去吧 :) 我会感激的! - LukyVj

10

编写旋转文本的最佳方法是围绕某个点(您想要文本起始点的位置)旋转pdf,然后编写它,并将pdf文档旋转回来。 代码示例:

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

这样,您就不需要计算新位置。

另外值得知道的是,pdfkit把文本的x和y当做文本“框”的左上角点(在我的情况下很重要)。


1
我在那个问题或答案中描述的事实上有些抓狂了。尝试了很多方法,但文字总是按自己的方式走。
这里有一个小片段,我用它来将文本放置在不同的方向上。该函数会计算旋转坐标系中的新x和y。
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
    };
};

这个函数会遍历一个包含x、y、旋转角度的文本数组,使用下划线进行循环。

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();
    });

};

首先,'world' 被旋转,然后将文本放置到新的 (x,y) 位置,该位置与旋转后的 (t.x,t.y) 相同。

-1

你可以使用SVG。请参见https://pdfmake.github.io/docs/document-definition-object/svgs/

pdfmake使用svg-to-pdfkit进行转换。

源代码中似乎支持transform="rotate....",请参见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]]);
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接