Apache PDFBox旋转PDImageXObject

5

我正在使用2.0.0-SNAPSHOT进行尝试,并希望将页面设置为横向并旋转我的图片。因此,我已经执行了page.setRotation(90);

使用PDFBox和AffineTransform似乎存在一个错误。

这段代码并没有像我期望的那样做任何事情:

AffineTransform at = new AffineTransform(w, 0, 0, h, 20, 20);
at.translate(0.5, 1);
at.rotate(Math.toRadians(90));

为了将图片保持在页面上,宽度和高度必须非常小,自旋转会挤压图像,在旋转之前平移似乎会使图像缩放得很大。

这是一个错误吗?还是我没有理解PDFBox?


那么你创建了一个转换矩阵。但是你如何使用它?你期望你的转换值会产生什么效果? - mkl
@djb:我已经更新了我的回答。昨天我没有测试90度页面旋转,当我使用它时,我得到了你描述的效果。 - Tilman Hausherr
@djb 通常情况下,如果问题中提供的示例代码可以轻松地用于重现问题,则会很有帮助。您只提供了设置页面旋转和生成仿射变换的代码,但没有说明如何使用该仿射变换。Tilman费心编写了这样的代码,而其他人则没有。如果您提供了代码,您可能会得到更多的回复。 - mkl
@mkl - 我实际上有原始的旋转代码,Tilman要求我整理一下我的问题。旋转代码将其旋转到了屏幕之外,因此我留下的示例只显示了我描述的奇怪错误。 - djb
@djb ;) 好的,你永远无法取悦每个人。 - mkl
显示剩余2条评论
2个回答

5
不要进行额外的翻译,而是在创建AT时添加翻译。请记住旋转是围绕左下角轴进行的,因此将宽度w加到x位置上。
    PDPage page = new PDPage();
    document.addPage(page);
    page.setRotation(90);
    PDPageContentStream contentStream = new PDPageContentStream(document, page);

    int x = 150;
    int y = 300;

    // draw unrotated
    contentStream.drawXObject(ximage, x, y, ximage.getWidth() / 2, ximage.getHeight() / 2);

    // draw 90° rotated, placed on the right of the first image
    AffineTransform at = new AffineTransform(ximage.getHeight() / 2, 0, 0, ximage.getWidth() / 2, x + ximage1.getWidth(), y);
    at.rotate(Math.toRadians(90));
    contentStream.drawXObject(ximage, at);

这将绘制两次图像,一次正常绘制,一次旋转90°并位于右侧。使用“/2”缩放50%,当然您也可以使用其他因子。请注意,“/2”未用于初始x位置,因为需要(缩放后的)宽度两次。一次是为了定位到旧位置(因为轴!),另一次是将其移动到右侧,以使图像不重叠。
另外请注意,由于页面旋转,getHeight()和getWidth()被颠倒了。

啊哈,我解决了。你差不多就要成功了。这是诀窍: AffineTransform at = new AffineTransform(ximage.getWidth() / 2, 0, 0, ximage.getHeight() / 2, x + ximage1.getWidth(), y); - djb

2
AffineTransform at = new AffineTransform(w, 0, 0, h, 20, 20);
at.translate(0.5, 1);
at.rotate(Math.toRadians(90));

宽度和高度必须很小才能使图片保持在页面上,自身旋转会压缩图片,而在旋转之前进行平移似乎会将图片缩放得很大。

这是一个 bug 吗,还是我没有理解 PDFBox?

这不是 bug,只是数学问题。你需要明白,如果你有一个 AffineTransform at,然后调用 at.translate(...)at.rotate(...),你并没有将仿射变换的平移/旋转部分设置为给定值,而是用以前的变换和平移/旋转组合来替换你的变换。

这意味着例如:

AffineTransform at = new AffineTransform(w, 0, 0, h, 20, 20);
at.translate(0.5, 1);

不等于(not the same as)

AffineTransform at = new AffineTransform(w, 0, 0, h, 20.5, 21);

正如你所预料的那样,但相反
AffineTransform at = new AffineTransform(w, 0, 0, h, 20 + w/2, 20 + h);

这就是为什么宽度和高度必须很小才能保持图像在页面上 - 否则translate(0.5, 1)会推得非常远。
由于组合变换的顺序很重要,如果按照以下顺序创建变换,您可能会更满意:
AffineTransform at = AffineTransform.getTranslateInstance(0.5, 1);
at.rotate(Math.toRadians(90));
af.concatenate(new AffineTransform(w, 0, 0, h, 20, 20));

PS:正如Tilman所说:请记住旋转是以左下角为中心,因此这个组合也会旋转到屏幕外。只需将初始平移的x坐标加上h+20即可。


好的,我确实认为翻译是添加值。如Tilman的回答所述,我现在已经解决了这个问题 - 我使用了他的答案,但不得不交换高度和宽度。但你对矩阵信息也很有帮助,谢谢。 - djb

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