I need to rotate the contents of a PDF page by an arbitrary angle and the PDPage.setRotation(int) command is restricted to multiples of 90 degrees. The contents of the page are vector and text and I need to be able to zoom in on the contents later, which means that I cannot convert the page to an image because of the loss of resolution.
问题:
回答1:
In comments it already has been indicated that to draw some content, e.g. an existing regular portrait or landscape page, at an arbitrary angle onto a new regular portrait or landscape page, one can use the mechanism presented in this answer.
As the code presented there
- requires the PDFBox development 2.0.0-SNAPSHOT version and
- makes use of form xobjects which in the context at hand is not necessary,
though, here a quick&dirty solution working for the current regular release 1.8.8 without introducing form xobjects.
This method
void transformPage(PDDocument document, PDPage page, AffineTransform at) throws IOException, COSVisitorException
{
PDRectangle cropBox = page.findCropBox();
float xOffset = (cropBox.getUpperRightX() + cropBox.getLowerLeftX()) / 2f;
float yOffset = (cropBox.getUpperRightY() + cropBox.getLowerLeftY()) / 2f;
AffineTransform transform = AffineTransform.getTranslateInstance(xOffset, yOffset);
transform.concatenate(at);
transform.concatenate(AffineTransform.getTranslateInstance(-xOffset, -yOffset));
PDPageContentStream stream = new PDPageContentStream(document, page, true, false);
stream.concatenate2CTM(transform);
stream.close();
COSBase contents = page.getCOSDictionary().getDictionaryObject(COSName.CONTENTS);
if (contents instanceof COSStreamArray)
{
COSStreamArray contentsArray = (COSStreamArray) contents;
COSArray newArray = new COSArray();
newArray.add(contentsArray.get(contentsArray.getStreamCount() - 1));
for (int i = 0; i < contentsArray.getStreamCount() - 1; i++)
{
newArray.add(contentsArray.get(i));
}
COSStreamArray newStreamArray = new COSStreamArray(newArray);
page.getCOSDictionary().setItem(COSName.CONTENTS, newStreamArray);
}
}
applies the given transformation to the given page. To make the use case at hands (to rotate the contents of a PDF page) easier, the transformation is enveloped in translations moving the origin of the coordinate system to the center of the page for the transformation.
The method can be used like this
try ( InputStream sourceStream = getClass().getResourceAsStream("13.pdf") )
{
final PDDocument document = PDDocument.load(sourceStream);
final AffineTransform transform = AffineTransform.getRotateInstance(Math.PI / 4);
List<PDPage> pages = document.getDocumentCatalog().getAllPages();
for (PDPage page: pages)
{
transformPage(document, page, transform);
}
document.save("13-transformedPages.pdf");
}
to rotate the pages of a document counterclockwise by 45° (PI/4, mathematically positive rotation direction).
回答2:
Please read ISO-32000-1 (this is the ISO standard for PDF), more specifically Table 30 ("Entries in a page object"). It defines the Rotate
entry like this (literal copy/paste):
The number of degrees by which the page shall be rotated clockwise when displayed or printed. The value shall be a multiple of 90. Default value: 0.
Whenever an ISO standard uses the word shall, you are confronted a normative rule (as opposed to when the standard uses the word should in which case you're facing a recommendation).
In short: you are asking something that is explicitly forbidden by the PDF specification. Meeting your requirement is impossible in PDF. Your page can have an orientation of 0, 90, 180 or 270 degrees. You will have to rotate the contents on the page instead of rotating the page.