Reputation: 33
I'm new to Apache's PDFBox. I'm using version 2.0.0, taken from the SVN repository.
Actually I try to increase the cropbox of a PDPage object. OK, no challenge. But the page content remains in the lower left corner of the cropbox. I want it centered in the new cropbox space.
I understood that all content is positioned absolutely in PDF. So my question: Is there a way using PDFBox to translate the origin (x, y) of my PDPage or the content elements?
Regards
Hans
Upvotes: 2
Views: 3633
Reputation: 3735
To increase the CropBox, you set the MediaBox like this:
PDRectangle box = new PDRectangle(pageWidth, pageHeight);
page.setMediaBox(box); // MediaBox > BleedBox > TrimBox/CropBox
Upvotes: 0
Reputation: 95918
The first approach would be to simply change the crop box like this:
PDDocument document = PDDocument.load(new File("data/test.pdf"));
PDDocumentCatalog catalog = document.getDocumentCatalog();
@SuppressWarnings("unchecked")
List<PDPage> pages = catalog.getAllPages();
float expand = 72;
for (PDPage page : pages)
{
PDRectangle cropBox = page.findCropBox();
PDRectangle newCropBox = new PDRectangle();
newCropBox.setLowerLeftX(cropBox.getLowerLeftX() - expand);
newCropBox.setLowerLeftY(cropBox.getLowerLeftY() - expand);
newCropBox.setUpperRightX(cropBox.getUpperRightX() + expand);
newCropBox.setUpperRightY(cropBox.getUpperRightY() + expand);
page.setCropBox(newCropBox);
}
document.save("data/out/test-expand-crop-simple.pdf");
This only works sometimes, though, because according to the specification ISO 32000-1, section 14.11.2 Page Boundaries
The crop, bleed, trim, and art boxes shall not ordinarily extend beyond the boundaries of the media box. If they do, they are effectively reduced to their intersection with the media box.
(also see this answer)
Thus, we have to make sure that the crop box even after enlarging still fits into the media box, e.g. like this:
PDDocument document = PDDocument.load(new File("data/test.pdf"));
PDDocumentCatalog catalog = document.getDocumentCatalog();
@SuppressWarnings("unchecked")
List<PDPage> pages = catalog.getAllPages();
float expand = 72;
for (PDPage page : pages)
{
PDRectangle cropBox = page.findCropBox();
PDRectangle newCropBox = new PDRectangle();
newCropBox.setLowerLeftX(cropBox.getLowerLeftX() - expand);
newCropBox.setLowerLeftY(cropBox.getLowerLeftY() - expand);
newCropBox.setUpperRightX(cropBox.getUpperRightX() + expand);
newCropBox.setUpperRightY(cropBox.getUpperRightY() + expand);
page.setCropBox(newCropBox);
PDRectangle mediaBox = page.findMediaBox();
PDRectangle newMediaBox = new PDRectangle();
newMediaBox.setLowerLeftX(mediaBox.getLowerLeftX() - expand);
newMediaBox.setLowerLeftY(mediaBox.getLowerLeftY() - expand);
newMediaBox.setUpperRightX(mediaBox.getUpperRightX() + expand);
newMediaBox.setUpperRightY(mediaBox.getUpperRightY() + expand);
page.setMediaBox(newMediaBox);
}
document.save("data/out/test-expand-crop-and-media.pdf");
Upvotes: 1
Reputation: 33
The Pageoffset dictionary entry was not very helpful. It can be used as a parameter for GhostScript. But GS does not really create a dictionary entry. Instead it offsets the content of all pages. A capability which doesn't exist in PDFBox.
I found a solution using LayerUtility:
PDDocument docIn = null;
try
{
docIn = PDDocument.load("./pdf/Test1.pdf");
float fBorder = 10 * MM_TO_UNITS; // Arbitrary 10 mm
PDDocument docOut = new PDDocument();
PDPage pageIn = (PDPage)docIn.getDocumentCatalog().getPages().getKids().get(0);
PDRectangle rectCrop = pageIn.findCropBox();
PDPage pageClone = clonePage(docOut, pageIn, true),
pageOut = new PDPage(
new PDRectangle(rectCrop.getWidth() + 2 * fBorder, rectCrop.getHeight() + 2 * fBorder)
);
docOut.addPage(pageOut);
PDPageContentStream stream = new PDPageContentStream(docOut, pageOut);
stream.close();
LayerUtility lu = new LayerUtility(docOut);
lu.wrapInSaveRestore(pageOut);
PDXObjectForm xobj = lu.importPageAsForm(docIn, pageClone);
AffineTransform at = new AffineTransform();
// That's the point where x,y offset takes place
at.setToTranslation(fBorder, fBorder);
lu.appendFormAsLayer(pageOut, xobj, at, "layerx");
docOut.addPage(pageOut);
docOut.save("./pdf/Test1out.pdf");
}
finally
{
if (docIn != null)
{
docIn.close();
}
}
I'm not very happy with this. Because it changes the page structure. But at least I have a solution.
Regards Hans
Upvotes: 0
Reputation: 33
The central code to manipulate the crop box looks as follows:
@Override
protected void treeNodeChanged(PDFTreeNode node)
{
if (node instanceof PDFFloatNode)
{
PDFFloatNode nodeF = (PDFFloatNode)node;
String strDataKey = node.getDataKey();
if ("x".equals(strDataKey))
{
m_rect.setLowerLeftX(nodeF.getFloat());
}
else if ("y".equals(strDataKey))
{
m_rect.setLowerLeftY(nodeF.getFloat());
}
else if ("width".equals(strDataKey))
{
m_rect.setUpperRightX(nodeF.getFloat());
}
else if ("height".equals(strDataKey))
{
m_rect.setUpperRightY(nodeF.getFloat());
}
}
if (m_parent != null)
{
m_parent.treeNodeChanged(node);
}
}
Where m_rect is an instance of PDRectangle. In fact this information doesn't help you, @mkl. In between I found an information to solve the problem (I hope). There is an operation which is obviously not known in PDFBox.
<</PageOffset [-20 20]>> setpagedevice
Now I'm looking for a way to implement it into the PDF.
Thanks Hans
Upvotes: 0