How to fix the orientation of a PDF page in order to scale it?
I need to scale down the pages of an existing PDF document. This works fine if the pages aren't rotated, but I don't succeed in rotating pages correctly, for instance if they have a rotation of 270 degrees:
for(int i=1; ireader.getNumberOfPages(); i++){ int rotation = reader.getPageRotation(i); float pageWidth = reader.getPageSizeWithRotation(i).getWidth(); float pageHeight = reader.getPageSizeWithRotation(i).getHeight(); doc.newPage(); PdfImportedPage page = writer.getImportedPage(reader, i); if (rotation == 0) { cb.addTemplate(page, 1f, 0, 0, scaleHeight, x, y); } else if (rotation == 90) { cb.addTemplate(page, 0, -1f, 1f, 0, 0, pageHeight); } else if (rotation == 180) { cb.addTemplate(page, 1f, 0, 0, -1f, pageWidth, pageHeight); } else if (rotation == 270) { cb.addTemplate(page, 0, -1f, 1f, 0, 0, pageHeight); } }
- How do I properly rotate the page contents?
- How can I scale the rotated contents correctly?
Posted on StackOverflow on Mar 19, 2014 by user3854377
Please take a look at the ScaleDown example that can be used to scale down pages, keeping the original orientation.
This example uses a page event named it ScaleEvent
:
public class ScaleEvent extends PdfPageEventHelper {
protected float scale = 1;
protected PdfDictionary pageDict;
public ScaleEvent(float scale) {
this.scale = scale;
}
public void setPageDict(PdfDictionary pageDict) {
this.pageDict = pageDict;
}
@Override
public void onStartPage(PdfWriter writer, Document document) {
writer.addPageDictEntry(PdfName.ROTATE, pageDict.getAsNumber(PdfName.ROTATE));
writer.addPageDictEntry(PdfName.MEDIABOX, scaleDown(pageDict.getAsArray(PdfName.MEDIABOX), scale));
writer.addPageDictEntry(PdfName.CROPBOX, scaleDown(pageDict.getAsArray(PdfName.CROPBOX), scale));
}
}
When you create the event, you pass a value scale
that will define the scale factor. I apply the scale to the width and the height, feel free to adapt it if you only want to scale the height or the width only.
The information about page size and rotation is stored in the page dictionary. Obviously the ScaleEvent
needs the values of the original document, and that why we'll pass a pageDict
for every page we copy.
Every time a new page is created, we will copy/replace:
-
the
/Rotate
value. Remove this line if you want to remove the rotation, -
the
/MediaBox
value. This defines the full size of the page. -
the
/CropBox
value. This defines the visible size of the page.
As we want to scale the page, we use the following scaleDown()
method:
public PdfArray scaleDown(PdfArray original, float scale) {
if (original == null)
return null;
float width = original.getAsNumber(2).floatValue()
- original.getAsNumber(0).floatValue();
float height = original.getAsNumber(3).floatValue()
- original.getAsNumber(1).floatValue();
return new PdfRectangle(width * scale, height * scale);
}
Suppose that I want to reduce the page width and height to 50% of the original width and height, then I create the event like this:
PdfReader reader = new PdfReader(src);
float scale = 0.5f;
ScaleEvent event = new ScaleEvent(scale);
event.setPageDict(reader.getPageN(1));
I can define a Document
with any page size I want as the size will be changed in the ScaleEvent
anyway. For this to work I need to declare the event to the PdfWriter
instance before opening the document:
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(dest));
writer.setPageEvent(event);
document.open();
Now it's only a matter of looping over the pages:
int n = reader.getNumberOfPages();
Image page;
for (int p = 1; p
I am wrapping the imported page inside an Image
because I personally think that the methods available for the Image
class are easier to use than defining the parameters of the addTemplate()
method. If you want to use addTemplate()
instead of Image
, feel free to do so; the result will be identical (contrary to what you wrote in a comment, wrapping a page inside an image will not cause any loss of "resolution" as all the text remains available as vector data).
Note that I update the pageDict
for every new page.
This code takes the file orientations.pdf measuring 8.26 by 11.69 in and transforms it into the file scaled_down.pdf measuring 4.13 by 5.85 in.