Author: tilman
Date: Sat Aug 9 17:35:31 2025
New Revision: 1927718
Log:
PDFBOX-6049: introduce new adjustRotation option
Modified:
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/multipdf/Overlay.java
pdfbox/trunk/tools/src/main/java/org/apache/pdfbox/tools/OverlayPDF.java
Modified:
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/multipdf/Overlay.java
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/multipdf/Overlay.java
Sat Aug 9 16:40:21 2025 (r1927717)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/multipdf/Overlay.java
Sat Aug 9 17:35:31 2025 (r1927718)
@@ -67,6 +67,7 @@ public class Overlay implements Closeabl
}
private LayoutPage defaultOverlayPage;
+ private final Map<Integer,LayoutPage> rotatedDefaultOverlayPagesMap = new
HashMap<>();
private LayoutPage firstPageOverlayPage;
private LayoutPage lastPageOverlayPage;
private LayoutPage oddPageOverlayPage;
@@ -100,6 +101,7 @@ public class Overlay implements Closeabl
private int numberOfOverlayPages = 0;
private boolean useAllOverlayPages = false;
+ private boolean adjustRotation = false;
/**
* This will add overlays to a document.
@@ -204,6 +206,7 @@ public class Overlay implements Closeabl
}
openDocumentsSet.clear();
specificPageOverlayLayoutPageMap.clear();
+ rotatedDefaultOverlayPagesMap.clear();
}
private void loadPDFs() throws IOException
@@ -288,9 +291,9 @@ public class Overlay implements Closeabl
private final PDRectangle overlayMediaBox;
private final COSStream overlayCOSStream;
private final COSDictionary overlayResources;
- private final short overlayRotation;
+ private int overlayRotation;
- private LayoutPage(PDRectangle mediaBox, COSStream contentStream,
COSDictionary resources, short rotation)
+ private LayoutPage(PDRectangle mediaBox, COSStream contentStream,
COSDictionary resources, int rotation)
{
overlayMediaBox = mediaBox;
overlayCOSStream = contentStream;
@@ -326,7 +329,7 @@ public class Overlay implements Closeabl
resources = new PDResources();
}
return new LayoutPage(page.getMediaBox(),
createCombinedContentStream(contents),
- resources.getCOSObject(), (short) page.getRotation());
+ resources.getCOSObject(), page.getRotation());
}
private Map<Integer,LayoutPage> createPageOverlayLayoutPageMap(PDDocument
doc) throws IOException
@@ -468,7 +471,7 @@ public class Overlay implements Closeabl
array.add(createOverlayStream(page, layoutPage, formXObjectId));
}
- private LayoutPage getLayoutPage(int pageNumber, int numberOfPages)
+ private LayoutPage getLayoutPage(int pageNumber, int numberOfPages) throws
IOException
{
LayoutPage layoutPage = null;
if (!useAllOverlayPages &&
specificPageOverlayLayoutPageMap.containsKey(pageNumber))
@@ -494,6 +497,27 @@ public class Overlay implements Closeabl
else if (defaultOverlayPage != null)
{
layoutPage = defaultOverlayPage;
+
+ if (adjustRotation)
+ {
+ // PDFBOX-6049: consider the rotation of the document page
+ // Note that this segment is only the second best solution to
the problem. The best
+ // would be to make appropriate transforms in
calculateAffineTransform()
+ PDPage page = inputPDFDocument.getPage(pageNumber - 1);
+ if (page.getRotation() != 0)
+ {
+ LayoutPage rotatedLayoutPage =
rotatedDefaultOverlayPagesMap.get(page.getRotation());
+ if (rotatedLayoutPage == null)
+ {
+ // createLayoutPage must be called because we can't
reuse the COSStream
+ rotatedLayoutPage =
createLayoutPage(defaultOverlayDocument.getPage(0));
+ int newRotation = (rotatedLayoutPage.overlayRotation -
page.getRotation() + 360) % 360;
+ rotatedLayoutPage.overlayRotation = newRotation;
+ rotatedDefaultOverlayPagesMap.put(page.getRotation(),
rotatedLayoutPage);
+ }
+ return rotatedLayoutPage;
+ }
+ }
}
else if (useAllOverlayPages)
{
@@ -516,15 +540,15 @@ public class Overlay implements Closeabl
{
case 90:
at.translate(0, layoutPage.overlayMediaBox.getWidth());
- at.rotate(Math.toRadians(-90));
+ at.quadrantRotate(3); // 270
break;
case 180:
at.translate(layoutPage.overlayMediaBox.getWidth(),
layoutPage.overlayMediaBox.getHeight());
- at.rotate(Math.toRadians(-180));
+ at.quadrantRotate(2); // 180
break;
case 270:
at.translate(layoutPage.overlayMediaBox.getHeight(), 0);
- at.rotate(Math.toRadians(-270));
+ at.quadrantRotate(1); // 90
break;
default:
break;
@@ -795,4 +819,23 @@ public class Overlay implements Closeabl
{
evenPageOverlayDocument = evenPageOverlayPDF;
}
+
+ /**
+ * This sets whether the overlay is to be rotated according to the
rotation of the pages of the
+ * source document. This may look weird if the content of the document is
also rotated. So it's
+ * really a users decision to activate this option if the overlay appears
rotated in some pages
+ * of the result document and this isn't wanted.
+ * <p>
+ * This setting will only apply to usage of the default overlay, because
it is assumed that when
+ * using specific overlays for specific pages, it is known in advance what
kind of input there
+ * is.
+ *
+ * @param adjustRotation if true, the overlay will always look the same
when the result file is
+ * displayed on the screen. If false (default) then it will be rotated if
the page is rotated.
+ */
+ public void setAdjustRotation(boolean adjustRotation)
+ {
+ this.adjustRotation = adjustRotation;
+
+ }
}
Modified:
pdfbox/trunk/tools/src/main/java/org/apache/pdfbox/tools/OverlayPDF.java
==============================================================================
--- pdfbox/trunk/tools/src/main/java/org/apache/pdfbox/tools/OverlayPDF.java
Sat Aug 9 16:40:21 2025 (r1927717)
+++ pdfbox/trunk/tools/src/main/java/org/apache/pdfbox/tools/OverlayPDF.java
Sat Aug 9 17:35:31 2025 (r1927718)
@@ -60,6 +60,9 @@ public final class OverlayPDF implements
@Option(names = "-useAllPages", description = "overlay file used for
overlay, all pages are used by simply repeating them")
private File useAllPages;
+ @Option(names = "-adjustRotation", description = "adjust rotation for
rotated source pages (applies only if default overlay file is used)")
+ private boolean adjustRotation = false;
+
@Option(names = "-page", description = "overlay file used for the given
page number, may occur more than once")
Map<Integer, String> specificPageOverlayFile = new HashMap<>();
@@ -140,6 +143,7 @@ public final class OverlayPDF implements
{
overlayer.setInputFile(infile.getAbsolutePath());
}
+ overlayer.setAdjustRotation(adjustRotation);
try (PDDocument result = overlayer.overlay(specificPageOverlayFile))