FOP-3112: Rotate annotations
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop-pdf-images/trunk@1906240 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/java/org/apache/fop/render/pdf/pdfbox/PDFBoxAdapter.java b/src/java/org/apache/fop/render/pdf/pdfbox/PDFBoxAdapter.java
index d380267..6cc06d2 100644
--- a/src/java/org/apache/fop/render/pdf/pdfbox/PDFBoxAdapter.java
+++ b/src/java/org/apache/fop/render/pdf/pdfbox/PDFBoxAdapter.java
@@ -182,7 +182,7 @@
throws IOException {
COSDictionary sourcePageResources = getResources(page);
uniqueName = new UniqueName(key, sourcePageResources, pdfDoc.isFormXObjectEnabled());
- handleAnnotations(sourceDoc, page, atdoc);
+ handleAnnotations(sourceDoc, page, atdoc, pos);
if (pageNumbers.containsKey(targetPage.getPageIndex())) {
pageNumbers.get(targetPage.getPageIndex()).set(0, targetPage.makeReference());
}
@@ -458,7 +458,8 @@
*/
}
- private void handleAnnotations(PDDocument sourceDoc, PDPage page, AffineTransform at) throws IOException {
+ private void handleAnnotations(PDDocument sourceDoc, PDPage page, AffineTransform at, Rectangle pos)
+ throws IOException {
PDDocumentCatalog srcCatalog = sourceDoc.getDocumentCatalog();
PDAcroForm srcAcroForm = srcCatalog.getAcroForm();
List pageAnnotations = page.getAnnotations();
@@ -466,7 +467,7 @@
return;
}
- PDFBoxAdapterUtil.moveAnnotations(page, pageAnnotations, at);
+ PDFBoxAdapterUtil.moveAnnotations(page, pageAnnotations, at, pos);
//Pseudo-cache the target page in place of the original source page.
//This essentially replaces the original page reference with the target page.
diff --git a/src/java/org/apache/fop/render/pdf/pdfbox/PDFBoxAdapterUtil.java b/src/java/org/apache/fop/render/pdf/pdfbox/PDFBoxAdapterUtil.java
index fdeffc6..b397a7c 100644
--- a/src/java/org/apache/fop/render/pdf/pdfbox/PDFBoxAdapterUtil.java
+++ b/src/java/org/apache/fop/render/pdf/pdfbox/PDFBoxAdapterUtil.java
@@ -18,7 +18,9 @@
/* $Id$ */
package org.apache.fop.render.pdf.pdfbox;
+import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
@@ -36,6 +38,8 @@
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation;
+import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceDictionary;
+import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceStream;
import org.apache.fop.pdf.PDFArray;
import org.apache.fop.pdf.PDFDictionary;
@@ -164,12 +168,12 @@
}
}
- protected static void moveAnnotations(PDPage page, List pageAnnotations, AffineTransform at) {
+ protected static void moveAnnotations(PDPage page, List pageAnnotations, AffineTransform at, Rectangle pos) {
PDRectangle mediaBox = page.getMediaBox();
PDRectangle cropBox = page.getCropBox();
PDRectangle viewBox = cropBox != null ? cropBox : mediaBox;
for (Object obj : pageAnnotations) {
- PDAnnotation annot = (PDAnnotation)obj;
+ PDAnnotation annot = (PDAnnotation) obj;
PDRectangle rect = annot.getRectangle();
float translateX = (float) (at.getTranslateX() - viewBox.getLowerLeftX());
float translateY = (float) (at.getTranslateY() - viewBox.getLowerLeftY());
@@ -178,18 +182,43 @@
rect.setLowerLeftX(rect.getLowerLeftX() + translateX);
rect.setUpperRightY(rect.getUpperRightY() + translateY);
rect.setLowerLeftY(rect.getLowerLeftY() + translateY);
+ int rotation = PDFUtil.getNormalizedRotation(page);
+ if (rotation > 0) {
+ AffineTransform transform = AffineTransform.getTranslateInstance(translateX, translateY);
+ float height = (float)pos.getHeight() / 1000f;
+ rotateStream(transform, rotation, height, annot);
+ transform.translate(-translateX, -translateY);
+ rect = applyTransform(rect, transform);
+ }
annot.setRectangle(rect);
}
-// COSArray vertices = (COSArray) annot.getCOSObject().getDictionaryObject("Vertices");
-// if (vertices != null) {
-// Iterator iter = vertices.iterator();
-// while (iter.hasNext()) {
-// COSFloat x = (COSFloat) iter.next();
-// COSFloat y = (COSFloat) iter.next();
-// x.setValue(x.floatValue() + translateX);
-// y.setValue(y.floatValue() + translateY);
-// }
-// }
}
}
+
+ private static void rotateStream(AffineTransform transform, int rotation, float height, PDAnnotation annot) {
+ transform.rotate(Math.toRadians(-rotation));
+ transform.translate(-height, 0);
+ COSDictionary mkDict = (COSDictionary) annot.getCOSObject().getDictionaryObject(COSName.MK);
+ if (mkDict != null) {
+ mkDict.removeItem(COSName.R);
+ }
+ PDAppearanceDictionary appearance = annot.getAppearance();
+ if (appearance != null) {
+ for (PDAppearanceStream stream : appearance.getNormalAppearance().getSubDictionary().values()) {
+ stream.setMatrix(new AffineTransform());
+ }
+ for (PDAppearanceStream stream : appearance.getDownAppearance().getSubDictionary().values()) {
+ stream.setMatrix(new AffineTransform());
+ }
+ }
+ }
+
+ private static PDRectangle applyTransform(PDRectangle rect, AffineTransform apAt) {
+ Rectangle2D.Float rectangle = new Rectangle2D.Float();
+ rectangle.setRect(rect.getLowerLeftX(), rect.getLowerLeftY(), rect.getWidth(), rect.getHeight());
+ Rectangle2D rectangleT = apAt.createTransformedShape(rectangle).getBounds2D();
+ rect = new PDRectangle((float)rectangleT.getX(), (float)rectangleT.getY(),
+ (float)rectangleT.getWidth(), (float)rectangleT.getHeight());
+ return rect;
+ }
}
diff --git a/test/java/org/apache/fop/render/pdf/PDFBoxAdapterTestCase.java b/test/java/org/apache/fop/render/pdf/PDFBoxAdapterTestCase.java
index 1c2157b..1c6f5a4 100644
--- a/test/java/org/apache/fop/render/pdf/PDFBoxAdapterTestCase.java
+++ b/test/java/org/apache/fop/render/pdf/PDFBoxAdapterTestCase.java
@@ -131,6 +131,7 @@
protected static final String TYPE0CFF = "type0cff.pdf";
protected static final String ACCESSIBLERADIOBUTTONS = "accessibleradiobuttons.pdf";
protected static final String PATTERN = "pattern.pdf";
+ protected static final String FORMROTATED = "formrotated.pdf";
private static PDFPage getPDFPage(PDFDocument doc) {
final Rectangle2D r = new Rectangle2D.Double();
@@ -762,4 +763,13 @@
}
Assert.assertEquals(compositeList, Arrays.asList(18, 19, 39, 42, 62, 63, 29));
}
+
+ @Test
+ public void testFormRotated() throws IOException {
+ PDFDocument pdfdoc = new PDFDocument("");
+ loadPage(pdfdoc, FORMROTATED);
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ pdfdoc.output(bos);
+ Assert.assertFalse(bos.toString("UTF-8").contains("/R 90"));
+ }
}
diff --git a/test/resources/org/apache/fop/render/pdf/formrotated.pdf b/test/resources/org/apache/fop/render/pdf/formrotated.pdf
new file mode 100755
index 0000000..5ef173b
--- /dev/null
+++ b/test/resources/org/apache/fop/render/pdf/formrotated.pdf
Binary files differ