@@ -67,6 +67,7 @@ public enum Position
6767 }
6868
6969 private LayoutPage defaultOverlayPage ;
70+ private final Map <Integer ,LayoutPage > rotatedDefaultOverlayPagesMap = new HashMap <>();
7071 private LayoutPage firstPageOverlayPage ;
7172 private LayoutPage lastPageOverlayPage ;
7273 private LayoutPage oddPageOverlayPage ;
@@ -100,6 +101,7 @@ public enum Position
100101
101102 private int numberOfOverlayPages = 0 ;
102103 private boolean useAllOverlayPages = false ;
104+ private boolean adjustRotation = false ;
103105
104106 /**
105107 * This will add overlays to a document.
@@ -204,6 +206,7 @@ public void close() throws IOException
204206 }
205207 openDocumentsSet .clear ();
206208 specificPageOverlayLayoutPageMap .clear ();
209+ rotatedDefaultOverlayPagesMap .clear ();
207210 }
208211
209212 private void loadPDFs () throws IOException
@@ -288,9 +291,9 @@ private static final class LayoutPage
288291 private final PDRectangle overlayMediaBox ;
289292 private final COSStream overlayCOSStream ;
290293 private final COSDictionary overlayResources ;
291- private final short overlayRotation ;
294+ private int overlayRotation ;
292295
293- private LayoutPage (PDRectangle mediaBox , COSStream contentStream , COSDictionary resources , short rotation )
296+ private LayoutPage (PDRectangle mediaBox , COSStream contentStream , COSDictionary resources , int rotation )
294297 {
295298 overlayMediaBox = mediaBox ;
296299 overlayCOSStream = contentStream ;
@@ -326,7 +329,7 @@ private LayoutPage createLayoutPage(PDPage page) throws IOException
326329 resources = new PDResources ();
327330 }
328331 return new LayoutPage (page .getMediaBox (), createCombinedContentStream (contents ),
329- resources .getCOSObject (), ( short ) page .getRotation ());
332+ resources .getCOSObject (), page .getRotation ());
330333 }
331334
332335 private Map <Integer ,LayoutPage > createPageOverlayLayoutPageMap (PDDocument doc ) throws IOException
@@ -468,7 +471,7 @@ private void overlayPage(PDPage page, LayoutPage layoutPage, COSArray array,
468471 array .add (createOverlayStream (page , layoutPage , formXObjectId ));
469472 }
470473
471- private LayoutPage getLayoutPage (int pageNumber , int numberOfPages )
474+ private LayoutPage getLayoutPage (int pageNumber , int numberOfPages ) throws IOException
472475 {
473476 LayoutPage layoutPage = null ;
474477 if (!useAllOverlayPages && specificPageOverlayLayoutPageMap .containsKey (pageNumber ))
@@ -494,6 +497,27 @@ else if ((pageNumber % 2 == 0) && (evenPageOverlayPage != null))
494497 else if (defaultOverlayPage != null )
495498 {
496499 layoutPage = defaultOverlayPage ;
500+
501+ if (adjustRotation )
502+ {
503+ // PDFBOX-6049: consider the rotation of the document page
504+ // Note that this segment is only the second best solution to the problem. The best
505+ // would be to make appropriate transforms in calculateAffineTransform()
506+ PDPage page = inputPDFDocument .getPage (pageNumber - 1 );
507+ if (page .getRotation () != 0 )
508+ {
509+ LayoutPage rotatedLayoutPage = rotatedDefaultOverlayPagesMap .get (page .getRotation ());
510+ if (rotatedLayoutPage == null )
511+ {
512+ // createLayoutPage must be called because we can't reuse the COSStream
513+ rotatedLayoutPage = createLayoutPage (defaultOverlayDocument .getPage (0 ));
514+ int newRotation = (rotatedLayoutPage .overlayRotation - page .getRotation () + 360 ) % 360 ;
515+ rotatedLayoutPage .overlayRotation = newRotation ;
516+ rotatedDefaultOverlayPagesMap .put (page .getRotation (), rotatedLayoutPage );
517+ }
518+ return rotatedLayoutPage ;
519+ }
520+ }
497521 }
498522 else if (useAllOverlayPages )
499523 {
@@ -516,15 +540,15 @@ private PDFormXObject createOverlayFormXObject(LayoutPage layoutPage, PDFCloneUt
516540 {
517541 case 90 :
518542 at .translate (0 , layoutPage .overlayMediaBox .getWidth ());
519- at .rotate ( Math . toRadians (- 90 ));
543+ at .quadrantRotate ( 3 ); // 270
520544 break ;
521545 case 180 :
522546 at .translate (layoutPage .overlayMediaBox .getWidth (), layoutPage .overlayMediaBox .getHeight ());
523- at .rotate ( Math . toRadians (- 180 ));
547+ at .quadrantRotate ( 2 ); // 180
524548 break ;
525549 case 270 :
526550 at .translate (layoutPage .overlayMediaBox .getHeight (), 0 );
527- at .rotate ( Math . toRadians (- 270 ));
551+ at .quadrantRotate ( 1 ); // 90
528552 break ;
529553 default :
530554 break ;
@@ -795,4 +819,23 @@ public void setEvenPageOverlayPDF(PDDocument evenPageOverlayPDF)
795819 {
796820 evenPageOverlayDocument = evenPageOverlayPDF ;
797821 }
822+
823+ /**
824+ * This sets whether the overlay is to be rotated according to the rotation of the pages of the
825+ * source document. This may look weird if the content of the document is also rotated. So it's
826+ * really a users decision to activate this option if the overlay appears rotated in some pages
827+ * of the result document and this isn't wanted.
828+ * <p>
829+ * This setting will only apply to usage of the default overlay, because it is assumed that when
830+ * using specific overlays for specific pages, it is known in advance what kind of input there
831+ * is.
832+ *
833+ * @param adjustRotation if true, the overlay will always look the same when the result file is
834+ * displayed on the screen. If false (default) then it will be rotated if the page is rotated.
835+ */
836+ public void setAdjustRotation (boolean adjustRotation )
837+ {
838+ this .adjustRotation = adjustRotation ;
839+
840+ }
798841}
0 commit comments