iText -> how to do PDF Page Imposition - java

Could someone kindly show a working code example for PDF page imposition using iText?
It seems I've exhausted my Google options: there's no code samples for that out there.
Thanks,
InnerOrchestra
ps: By imposition, a printing technical term, I mean, for example, having an 11x17 sheet of paper hold two 8.5x11 pages. For business cards, this would be the same page (3.75x2.25) and for a booklet it would not since the sheet would be folded and the page placement would vary depending on booklet settings.

You could have saved yourself plenty of time by reading Chapter 6 of my book or by simply taking a look at the examples on the iText site. Take for instance the NUpTool example. As you're working in the printing sector, you should be familiar with the term "N-upping". It's when you take a document and then create a new one with 2 pages on one (2-upping), 4 pages on one (4-upping), etc...
Your request is very similar, but easier to achieve, because when we take a document, let's say text_on_stationery.pdf and we 2-up it using the example from my book, you have to scale down the pages, resulting for instance in the document result2up.pdf.
In your case, it's not that hard because you don't need to scale anything. You just need to create a Document object with twice the size of the original document, create PdfImportedPage objects to import the pages, and use addTemplate() with the correct offset to add them side by side on the new document.
There are quite some examples that demonstrate the use of PdfImportedPage: http://itextpdf.com/themes/keyword.php?id=236
It is strange that Google didn't show you the SuperImposing example when looking for "imposing". In this example, we add four different layers on top of each other:
PdfReader reader = new PdfReader(SOURCE);
// step 1
Document document = new Document(PageSize.POSTCARD);
// step 2
PdfWriter writer
= PdfWriter.getInstance(document, new FileOutputStream(RESULT));
// step 3
document.open();
// step 4
PdfContentByte canvas = writer.getDirectContent();
PdfImportedPage page;
for (int i = 1; i <= reader.getNumberOfPages(); i++) {
page = writer.getImportedPage(reader, i);
canvas.addTemplate(page, 1f, 0, 0, 1, 0, 0);
}
// step 5
document.close();
reader.close();
In other words, a 4-page document, is now a 1-page document where all the pages are rendered on top of each other. What you now need to do, is to change step 1, so that the dimension of the new pages are different, and to adapt step 4, so two pages are added next to each other and a new page is added after each two pages:
page = writer.getImportedPage(reader, i);
canvas.addTemplate(page, 1f, 0, 0, 1, 0, 0);
i++;
if (i <= reader.getNumberOfPages())
page = writer.getImportedPage(reader, i);
canvas.addTemplate(page, 1f, 0, 0, 1, width / 2, 0);
document.newPage();
In this example, I assume that the height of the original document is equal to the height of the new document and that the width of the new document is twice the width of the original document. It goes without saying that you can also choose to create a new document with the same width and a double height. In that case, you need:
page = writer.getImportedPage(reader, i);
canvas.addTemplate(page, 1f, 0, 0, 1, 0, height / 2);
i++;
if (i <= reader.getNumberOfPages())
page = writer.getImportedPage(reader, i);
canvas.addTemplate(page, 1f, 0, 0, 1, 0, 0);
document.newPage();

Related

PDF Cut Vertically and Merge

I have a booklet pdf. I want to Split in half i.e Vertical + Re-paginate from booklet scan
Ex: booklet pages would be 1, 8 and 7, 2 etc.,
After processing i want to have a PDF with 1, 2, 3, 4, ....
Please advise which PDF library would be able to do the above in java
Thanks
Depending on how the booklet was scanned into the PDF, I think you might be able to do this using a Java library that can extract and merge PDF pages.
For example, in the LEADTOOLS Java PDF Library, which is what I am familiar with since I work for the vendor, there is a PDFFile class that can be used to extract and merge pages from and to a PDF file.
PDFFile file = new PDFFile(bookletFile);
int pageCount = file.getPageCount();
for (int i = 1; i <= pageCount; i++)
{
File destinationFile = new File(destinationFolder, String.format("Extracted_Page{0}.pdf", i));
file.extractPages(i, i, destinationFile.getPath());
}
Since the booklet looks like it’s scanned in a way that every other page will contain a double page. To split them, you can load every other extracted page as a raster image then use the library's raster imaging classes to save each half as a separate raster PDF:
RasterCodecs codecs = new RasterCodecs();
RasterImage firstHalfImage = codecs.load(extractedDoublePage);
// Create a LeadRect that encompasses the second half
LeadRect secondHalfLeadRect = new LeadRect(firstHalfImage.getImageWidth() / 2, 0, firstHalfImage.getImageWidth() / 2, firstHalfImage.getImageHeight());
// Create a new image containing the second half
RasterImage secondHalfImage = firstHalfImage.clone(secondHalfLeadRect);
// Crop First Image to contain only first half
LeadRect firstHalfLeadRect = new LeadRect(0, 0, firstHalfImage.getImageWidth() / 2, firstHalfImage.getImageHeight());
CropCommand cropCommand = new CropCommand(firstHalfLeadRect);
cropCommand.run(firstHalfImage);
You can then use the RasterCodecs.Save() method to save each image as a raster PDF file.
Finally, once you have split everything accordingly, you can use the PDFFile.MergeWith() method to combine all the pages back into one file in the needed order.

What is an alternate way to implement PdfContentByte and PdfTemplate in iText 7

I am working on migration from iText 5 to iText 7. I have iText 5 code as below. I am not sure which alternative from iText 7(may be Canvas) should be used to implement PdfContentByte and PdfTemplate.
produce(com.itextpdf.text.pdf.PdfWriter writer, width, height, ...) {
com.itextpdf.text.pdf.PdfContentByte cb = writer.getDirectContent();
com.itextpdf.text.pdf.PdfTemplate template = cb.createTemplate(width, height);
try
{
template.beginText();
template.setFontAndSize(font, fontSize);
template.setTextMatrix(0, 0);
template.showTextAligned(com.itextpdf.text.pdf.PdfContentByte.ALIGN_CENTER, value, width/2, linePos, 0);
template.endText();
}
catch(Exception e)
{
}
cb.addTemplate(template, left, areaTop - top - height);
}
Can anyone please suggest the correct alternative to achieve this?
Thanks!
The PdfContentByte instance returned by iText 5 PdfWriter.getDirectContent() essentially is the content of the current page plus a number of methods to add more content.
An iText 5 PdfTemplate essentially is a PDF form XObject and its content plus a number of methods to add more content.
In iText 7 there are dedicated classes PdfPage and PdfFormXObject for pages and PDF form XObjects respectively, and there are classes PdfCanvas and Canvas providing low level and high level methods respectively to add more content to pages or form XObjects.
Thus, the following corresponds approximately to your iText 5 code:
PdfDocument pdfDoc = ...
PdfPage page = ... // e.g. pdfDoc.addNewPage();
PdfFormXObject pdfFormXObject = new PdfFormXObject(new Rectangle(width, height));
try (Canvas canvas = new Canvas(pdfFormXObject, pdfDoc)) {
canvas.showTextAligned(value, width/2, linePos, TextAlignment.CENTER);
}
PdfCanvas pdfCanvas = new PdfCanvas(page);
pdfCanvas.addXObject(pdfFormXObject, left, bottom);
(From AddCanvasToDocument test testAddCanvasForManjushaDC)
I say "approximately" because the architecture of iText 5 and iText 7 differ, so there is not necessarily an exact correspondence, in particular best practices in iText 5 don't directly translate to best practices in iText 7.

How to show an image with large dimensions across multiple pages in a PDF using iText5?

I have a graph image with large dimensions which I need to display in a PDF file.
I can't scale to fit the image as this would make text on the node illegible.
How could I split the image into multiple pages while retaining its original dimensions?
Please take a look at the TiledImage example. It takes an image at its original size and it tiles it over 4 pages: tiled_image.pdf
To make this work, I first asked the image for its size:
Image image = Image.getInstance(IMAGE);
float width = image.getScaledWidth();
float height = image.getScaledHeight();
To make sure each page is as big as one fourth of the page, I define this rectangle:
Rectangle page = new Rectangle(width / 2, height / 2);
I use this rectangle when creating the Document instance and I add the same image 4 times using different coordinates:
Document document = new Document(page);
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(dest));
document.open();
PdfContentByte canvas = writer.getDirectContentUnder();
canvas.addImage(image, width, 0, 0, height, 0, -height / 2);
document.newPage();
canvas.addImage(image, width, 0, 0, height, 0, 0);
document.newPage();
canvas.addImage(image, width, 0, 0, height, -width / 2, - height / 2);
document.newPage();
canvas.addImage(image, width, 0, 0, height, -width / 2, 0);
document.close();
Now I have distributed the image over different pages, which is exactly what you are trying to achieve ;-)

iText PDFDocument page size inaccurate

I am trying to add a header to existing pdf documents in Java with iText. I can add the header at a fixed place on the document, but all the documents are different page sizes, so it is not always at the top of the page. I have tried getting the page size so that I could calculate the position of the header, but it seems as if the page size is not actually what I want. On some documents, calling reader.getPageSize(i).getTop(20) will place the text in the right place at the top of the page, however, on some different documents it will place it half way down the page. Most of the pages have been scanned be a Xerox copier, if that makes a difference. Here is the code I am using:
PdfReader reader = new PdfReader(readFilePath);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(writeFilePath));
BaseFont bf = BaseFont.createFont(BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
for (int i = 1; i <= reader.getNumberOfPages(); i++) {
PdfContentByte cb = stamper.getOverContent(i);
cb.beginText();
cb.setFontAndSize(bf, 14);
float x = reader.getPageSize(i).getWidth() / 2;
float y = reader.getPageSize(i).getTop(20);
cb.showTextAligned(PdfContentByte.ALIGN_CENTER, "Copy", x, y, 0);
cb.endText();
}
stamper.close();
PDF that works correctly
PDF that works incorrectly
Take a look at the StampHeader1 example. I adapted your code, introducing ColumnText.showTextAligned() and using a Phrase for the sake of simplicity (maybe you can change that part of your code too):
public void manipulatePdf(String src, String dest) throws IOException, DocumentException {
PdfReader reader = new PdfReader(src);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
Phrase header = new Phrase("Copy", new Font(FontFamily.HELVETICA, 14));
for (int i = 1; i <= reader.getNumberOfPages(); i++) {
float x = reader.getPageSize(i).getWidth() / 2;
float y = reader.getPageSize(i).getTop(20);
ColumnText.showTextAligned(
stamper.getOverContent(i), Element.ALIGN_CENTER,
header, x, y, 0);
}
stamper.close();
reader.close();
}
As you have found out, this code assumes that no rotation was defined.
Now take a look at the StampHeader2 example. I'm using your "Wrong" file and I've added one extra line:
stamper.setRotateContents(false);
By telling the stamper not to rotate the content I'm adding, I'm adding the content using the coordinates as if the page isn't rotated. Please take a look at the result: stamped_header2.pdf. We added "Copy" at the top of the page, but as the page is rotated, we see the word appear on the side. The word is rotated because the page is rotated.
Maybe that's what you want, maybe it isn't. If it isn't, please take a look at StampHeader3 in which I calculate x and y differently, based on the rotation of the page:
if (reader.getPageRotation(i) % 180 == 0) {
x = reader.getPageSize(i).getWidth() / 2;
y = reader.getPageSize(i).getTop(20);
}
else {
x = reader.getPageSize(i).getHeight() / 2;
y = reader.getPageSize(i).getRight(20);
}
Now the word "Copy" appears on what is perceived as the "top of the page" (but in reality, it could be the side of the page): stamped_header3.pdf

How to make PdfWriter to write at top of pdf file in java using itext

I am generating charts using jfreechart.Now as per my requirement i need to export that chart into pdf using itext in java.Here i am able to export jfreechart to pdf but it is coming at the bottom of the pdf file whereas i want it to be top.
Here is my code..
PdfWriter writer = null;
Document document = new Document();
try {
writer = PdfWriter.getInstance(document, new FileOutputStream(
fileName));
document.open();
PdfContentByte contentByte = writer.getDirectContent();
PdfTemplate template = contentByte.createTemplate(width, height);
Graphics2D graphics2d = template.createGraphics(width, height,
new DefaultFontMapper());
Rectangle2D rectangle2d = new Rectangle2D.Double(0, 0, width,
height);
chart.draw(graphics2d, rectangle2d);
graphics2d.dispose();
contentByte.addTemplate(template, 0, 0);
How to set PdfWriter to write at the top of the pdf file.Please help me.
You are adding the template at the bottom of the page:
contentByte.addTemplate(template, 0, 0);
There are different options you can choose from.
You can add the template at another coordinate:
contentByte.addTemplate(template, 36, 400);
This will add the document at position x = 36 and y = 400. In this case, you need to do your math: instead of 400, you should take the top coordinate of the page (e.g. y = 842) minus a margin (e.g. 36) minus the height of the image.
If can be easier to choose a different option:
Image img = Image.getInstance(template);
document.add(img);
Now you're template is added in the flow of the document, just like all other high-level objects (just like Paragraphs and PdfPTables).

Categories