【问题标题】:Rotate PDF around its center using PDFBox in java使用Java中的PDFBox围绕其中心旋转PDF
【发布时间】:2016-11-15 14:00:23
【问题描述】:
PDDocument document = PDDocument.load(new File(input));
PDPage page = document.getDocumentCatalog().getPages().get(0);
PDPageContentStream cs = new PDPageContentStream(document, page,PDPageContentStream.AppendMode.PREPEND, false, false); 
cs.transform(Matrix.getRotateInstance(Math.toRadians(45), 0, 0));

我正在使用上面的代码来旋转 PDF。

对于上图,我得到以下输出

从该代码中,页面的内容已经移出框架,并且没有围绕其中心进行旋转。但我想得到输出为

请给我一些建议。提前致谢。

【问题讨论】:

  • 看起来您希望页面最终会显示在一个倾斜的矩形中。它不会。 PDF 页面总是有垂直或水平的边缘。这种页面的内容可以是任意方向的。要将旋转的内容放在可见矩形内(带有水平/垂直边缘),您可以使用Matrix.getRotateInstance 调用的附加两个参数将其移到那里(您将它们留给0,0),或者您可以通过设置移动可见矩形相应页面的媒体框和裁剪框。
  • getRotateInstance 的第二个和第三个参数是在旋转之前和之后完成的 x 和 y 平移,以便您有效地围绕与原点不同的点进行旋转。尝试将页面宽度的一半作为 x,将页面高度的一半作为 y。如果它不起作用,请在两者前面加上一个减号 - 我总是忘记您是否应该将其指定为向原点的平移(在这种情况下它们应该是负数)或作为旋转点(在这种情况下他们应该是积极的)
  • @mkl - 我尝试将媒体和裁剪框设置为 page.setCropBox(new PDRectangle(0f,0f,595f,841f)); page.setMediaBox(new PDRectangle(0f,0f,595f,841f));但得到相同的结果
  • @ErwinBolwidt - 我尝试使用 x 和 y 翻译,方法是将值设置为两种情况(正和负)的一半。但仍然无法得到正确的结果。
  • "我尝试将媒体和裁剪框设置为 page.setCropBox(new PDRectangle(0f,0f,595f,841f)); page.setMediaBox(new PDRectangle(0f,0f,595f ,841f)); 但得到相同的结果” - 显然。您将页面旋转到左侧,因此它的部分内容现在具有负 x 坐标值。要将其放入框内,框也必须以负 x 坐标开始,而不是您选择的 0。

标签: java pdfbox


【解决方案1】:

有两种主要的方法可以旋转页面内容并使其在查看器中显示,就好像旋转发生在可见页面的中间一样:一种是通过将旋转与平移连接起来,实际上确实围绕它的中间旋转,或者移动裁剪框,使页面区域中心跟随旋转。

实际上是围绕中心旋转

为此,我们封装了两个平移之间的旋转,第一个将坐标系的原点移动到页面中心,第二个将其再次移回。

PDDocument document = PDDocument.load(resource);
PDPage page = document.getDocumentCatalog().getPages().get(0);
PDPageContentStream cs = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.PREPEND, false, false); 
PDRectangle cropBox = page.getCropBox();
float tx = (cropBox.getLowerLeftX() + cropBox.getUpperRightX()) / 2;
float ty = (cropBox.getLowerLeftY() + cropBox.getUpperRightY()) / 2;
cs.transform(Matrix.getTranslateInstance(tx, ty));
cs.transform(Matrix.getRotateInstance(Math.toRadians(45), 0, 0));
cs.transform(Matrix.getTranslateInstance(-tx, -ty));
cs.close();

(RotatePageContent 测试testRotateCenter)

显然,您可以将矩阵相乘,然后只向 PDF 添加一个转换。

拉动裁剪框

为此,我们计算页面中心的移动并相应地移动框。

PDDocument document = PDDocument.load(resource);
PDPage page = document.getDocumentCatalog().getPages().get(0);
PDPageContentStream cs = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.PREPEND, false, false);
Matrix matrix = Matrix.getRotateInstance(Math.toRadians(45), 0, 0);
cs.transform(matrix);
cs.close();

PDRectangle cropBox = page.getCropBox();
float cx = (cropBox.getLowerLeftX() + cropBox.getUpperRightX()) / 2;
float cy = (cropBox.getLowerLeftY() + cropBox.getUpperRightY()) / 2;
Point2D.Float newC = matrix.transformPoint(cx, cy);
float tx = (float)newC.getX() - cx;
float ty = (float)newC.getY() - cy;
page.setCropBox(new PDRectangle(cropBox.getLowerLeftX() + tx, cropBox.getLowerLeftY() + ty, cropBox.getWidth(), cropBox.getHeight()));
PDRectangle mediaBox = page.getMediaBox();
page.setMediaBox(new PDRectangle(mediaBox.getLowerLeftX() + tx, mediaBox.getLowerLeftY() + ty, mediaBox.getWidth(), mediaBox.getHeight()));

(RotatePageContent 测试testRotateMoveBox)

旋转后缩小内容以适应

如果想要缩小旋转的内容以使其完全适合,可以将其作为第一个变体的简单扩展:

PDDocument document = PDDocument.load(resource);
PDPage page = document.getDocumentCatalog().getPages().get(0);
PDPageContentStream cs = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.PREPEND, false, false);

Matrix matrix = Matrix.getRotateInstance(Math.toRadians(45), 0, 0);
PDRectangle cropBox = page.getCropBox();
float tx = (cropBox.getLowerLeftX() + cropBox.getUpperRightX()) / 2;
float ty = (cropBox.getLowerLeftY() + cropBox.getUpperRightY()) / 2;

Rectangle rectangle = cropBox.transform(matrix).getBounds();
float scale = Math.min(cropBox.getWidth() / (float)rectangle.getWidth(), cropBox.getHeight() / (float)rectangle.getHeight());

cs.transform(Matrix.getTranslateInstance(tx, ty));
cs.transform(matrix);
cs.transform(Matrix.getScaleInstance(scale, scale));
cs.transform(Matrix.getTranslateInstance(-tx, -ty));
cs.close();

(RotatePageContent 测试testRotateCenterScale)

更改裁剪框以使所有以前的页面区域保持可见

如果想要更改裁剪框以使所有内容都适合而无需缩放,则可以将其作为第二种变体的简单扩展:

PDDocument document = PDDocument.load(resource);
PDPage page = document.getDocumentCatalog().getPages().get(0);
PDPageContentStream cs = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.PREPEND, false, false);
Matrix matrix = Matrix.getRotateInstance(Math.toRadians(45), 0, 0);
cs.transform(matrix);
cs.close();

PDRectangle cropBox = page.getCropBox();
Rectangle rectangle = cropBox.transform(matrix).getBounds();
PDRectangle newBox = new PDRectangle((float)rectangle.getX(), (float)rectangle.getY(), (float)rectangle.getWidth(), (float)rectangle.getHeight());
page.setCropBox(newBox);
page.setMediaBox(newBox);

(RotatePageContent 测试testRotateExpandBox)

示例结果

下图显示了上述每种方法的输出:

  1. 实际上是围绕中心旋转
  2. 旋转后缩小内容以适应
  3. 拉动裁剪框
  4. 更改裁剪框以使所有以前的页面区域保持可见

图 4 的比例与其他的不同,它应该显示得更大。

【讨论】:

  • 谢谢 mkl。我得到了完美的结果。再次感谢您如此详细的解释。
  • document.save() 命令在 RotatePageContent 测试示例中,但不在实际答案中。
  • 确实,这里的代码着重于实例化所需的对象并使用它们来创建所需的效果。之后文档是否保存在某处或以其他方式使用,例如逐页复制到其他文档中,这里不感兴趣。
  • @mkl 感谢您的详细回答。我的评论只是为了帮助那些对 pdfBox 一无所知的人(比如我)节省一些时间。不要批评你的回答。
  • @nishantbhardwaj2002 矩阵旋转始终围绕点 [0,0] 工作,要围绕其中心旋转图像,您必须首先移动图像使其中心位于 [0,0] 然后把它翻译回原来的位置。
猜你喜欢
  • 2014-04-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-18
相关资源
最近更新 更多