iText - Clone existing content and add in same page - java

I want to know if an existing content of a PDF can be cloned using iText. Basically I have a PDF in the below format:
Without cloning the content
I want to clone the content that is on the left side in the above PDF and want the result as per the below format.
After cloning the content
I am wondering if this is possible using iText PdfStamper class or any other class of iText?
Updating the code with iText7
public void clonePageContent(String dest) throws IOException {
// Initialize PDF Document
PdfDocument pdf = new PdfDocument(new PdfWriter(dest));
PdfDocument sourcePdf = new PdfDocument(new PdfReader(SRC));
// Original page
PdfPage origPage = sourcePdf.getPage(1);
// Original page size
Rectangle orig = origPage.getPageSize();
PdfFormXObject pageCopy = origPage.copyAsFormXObject(pdf);
// N-up page
PageSize nUpPageSize = PageSize.LETTER;
PdfPage page = pdf.addNewPage(nUpPageSize);
page.setRotation(90);
PdfCanvas canvas = new PdfCanvas(page);
// Scale page
AffineTransform transformationMatrix = AffineTransform
.getScaleInstance(
nUpPageSize.getWidth() / orig.getWidth() / 2f,
nUpPageSize.getHeight() / orig.getHeight() / 2f);
canvas.concatMatrix(transformationMatrix);
// Add pages to N-up page
canvas.addXObject(pageCopy, 0, orig.getHeight());
canvas.addXObject(pageCopy, orig.getWidth(), orig.getHeight());
pdf.close();
sourcePdf.close();
}
With the above code, I am not able to produce the output as expected. Can someone throw some light as to what should be tweaked to get the above expected output?

After so many days of struggle, the below code helps in achieving the above output that I was expecting. Hope this might be helpful to someone, someday!
P.S: I am newbie to iText7.
public void clonePageContent(String dest) throws IOException {
// Initialize PDF Document
PdfDocument pdf = new PdfDocument(new PdfWriter(dest));
PdfDocument sourcePdf = new PdfDocument(new PdfReader(SRC));
// Original page
PdfPage origPage = sourcePdf.getPage(1);
// Original page size
Rectangle orig = origPage.getPageSize();
PdfFormXObject pageCopy = origPage.copyAsFormXObject(pdf);
//PdfCanvas canvas = new PdfCanvas(pageCopy,sourcePdf);
// N-up page
PageSize nUpPageSize = PageSize.LETTER;
PdfPage page = pdf.addNewPage(nUpPageSize).setRotation(90);
PdfCanvas canvas = new PdfCanvas(page);
// Scale page
AffineTransform transformationMatrix = AffineTransform
.getScaleInstance(
page.getPageSize().getWidth() / orig.getWidth(), page.getPageSize().getHeight() / orig.getHeight()
);
canvas.concatMatrix(transformationMatrix);
System.out.println(page.getPageSize().getWidth());
System.out.println(orig.getWidth());
// Add pages to N-up page
canvas.addXObject(pageCopy, 0, 0);
canvas.addXObject(pageCopy, 0, 350f); //350f
//canvas.addXObject(pageCopy, orig.getRight(), orig.getWidth());
pdf.close();
sourcePdf.close();
}

Related

How to write content to a new page when it exceeds the given rectangle area (itext7)

How can I get the current page number?
Use case: An apllication written using itext5 needs to be rewritten using itext7.
Our app generates PDF files for our customer's monthly bills.
Structure of the pdf:
Create document:
PdfWriter writer = new PdfWriter(new FileOutputStream(filename));
PdfDocument pdfDocument = new PdfDocument(writer);
Document document = new Document(pdfDocument, PageSize.A4);
document.setMargins(82, 35, 0, 38);
buildBody(pdfData, document, writer);
pdfDocument.addEventHandler(PdfDocumentEvent.START_PAGE, new PdfStartPageHandler<>(pdfData, document, this));
pdfDocument.addEventHandler(PdfDocumentEvent.END_PAGE, new PdfEndPageHandler(document));
buildBodyContent(pdfData, document, writer);
document.close();
2.Each IEventHandler instance has this format(except the rectangle values):
public void handleEvent(Event event) {
document.add(lineSeparatorHeader);
document.add(paragraphInfo); //
document.add(lineSeparatorHeader);
}
paragraphInfo - is a Paragraph() which consists of one table with two columns
lineSeparatorHeader - is a LineSeparator()
The buildBody(pdfData, document, writer) must fill the body of my pdf page.
My problem is that I don't know how to handle the situation when the content exceeds the size of the rectangle. I would like it to create a new page, generate a new rectangle with the same dimensions and continue writing there.
A. is the header which needs to be on every page
B. is the body whose content is may occupy more than one page. In case it occupies more than one page, the new page must also contain the header and the footer.
C. is the footer
Accumulating your ideas and some suggestions from the comments, the following could be done:
Reserve space for a footer and a header by setting margins on a Document instance, ensuring that no content added to the Document will be placed on them.
Add footer and header events as you've already done.
PdfDocument pdfDoc = new PdfDocument(new PdfWriter(outFileName));
Document doc = new Document(pdfDoc);
int headerHeight = 100;
int footerHeight = 200;
float[] oldMargins = new float[] {doc.getTopMargin(), doc.getRightMargin(), doc.getBottomMargin(),
doc.getLeftMargin()};
doc.setMargins(doc.getTopMargin() + headerHeight, doc.getRightMargin(), doc.getBottomMargin() + footerHeight,
doc.getLeftMargin());
pdfDoc.addEventHandler(PdfDocumentEvent.START_PAGE, new IEventHandler() {
#Override
public void handleEvent(Event event) {
PdfDocumentEvent pdfDocumentEvent = (PdfDocumentEvent) event;
PdfPage page = pdfDocumentEvent.getPage();
Rectangle pageRectangle = page.getPageSize();
Rectangle headerArea = new Rectangle(oldMargins[3], pageRectangle.getTop() - oldMargins[0] - headerHeight,
pageRectangle.getWidth() - oldMargins[1] - oldMargins[3], headerHeight);
new Canvas(page, headerArea).add(
new Div()
.setHeight(headerArea.getHeight())
.setWidth(headerArea.getWidth())
.setBackgroundColor(ColorConstants.RED))
.close();
}
});
pdfDoc.addEventHandler(PdfDocumentEvent.END_PAGE, new IEventHandler(){
#Override
public void handleEvent(Event event) {
PdfDocumentEvent pdfDocumentEvent = (PdfDocumentEvent) event;
PdfPage page = pdfDocumentEvent.getPage();
Rectangle pageRectangle = page.getPageSize();
Rectangle footerArea = new Rectangle(oldMargins[3], pageRectangle.getBottom() + oldMargins[2],
pageRectangle.getWidth() - oldMargins[1] - oldMargins[3], footerHeight);
new Canvas(page, footerArea).add(
new Div()
.setHeight(footerArea.getHeight())
.setWidth(footerArea.getWidth())
.setBackgroundColor(ColorConstants.YELLOW))
.close();
}
});
for (int i = 0; i < 100; i++) {
doc.add(new Paragraph("I'm body's paragraph #" + i));
}
doc.close();
The resultant PDF looks as expected (no content overflows the footers and the headers):

itext : How to detect PDF orientation

I'm using itext5 to scale down pdf document, however i notice that the rotation information is rarely used in pdf documents metadata, it's still possible to find out the orientation by checking the width and the height of the page but with the following pdf document i end up with a pdf that has both pages in landscape orientation and in portrait orientation however all the pages are rendered in the same orientation (in the common pdf viewers).
My question is where is that information stored ? How the pdf viewer is able to render the document as it should ?
This the orignal pdf file
This is the metadata i'm able to retrieve
This is the method used :
Document document = new Document(MarginsPDFHelper.DIM_PAGE, MarginsPDFHelper.MARGIN_GEN, MarginsPDFHelper.MARGIN_GEN, MarginsPDFHelper.MARGIN_TOP, MarginsPDFHelper.MARGIN_BOT);
try {
PdfReader reader = new PdfReader(pdfByte);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
PdfWriter writer = PdfWriter.getInstance(document, outputStream);
document.open();
PdfContentByte content = writer.getDirectContent();
for (int i = 1; i <= reader.getNumberOfPages(); i++) {
document.newPage();
PdfImportedPage page = writer.getImportedPage(reader, i);
Rectangle pageSize = reader.getPageSizeWithRotation(i);
float scaleX = MarginsPDFHelper.DIM_PAGE.getWidth() / pageSize.getWidth();
float scaleY = MarginsPDFHelper.DIM_PAGE.getHeight() / pageSize.getHeight();
float scale = Math.min(scaleX, scaleY);
content.addTemplate(page, scale, 0, 0, scale, 0, 0);
}
return outputStream.toByteArray();
} catch (Exception e) {
LOGGER.error("Can not scale pdf", e);
} finally {
if (document.isOpen()) {
document.close();
} }
This the result i get after scaling down with itext5

create a one page PDF from two PDFs using PDFBOX

I have a small (quarter inch) one page PDF I created with PDFBOX with text (A). I want to put that small one page PDF (A) on the top of an existing PDF page (B), preserving the existing content of the PDF page (B). In the end, I will have a one page PDF, representing the small PDF on top(A), and the existing PDF intact making up the rest (B). How can I accomplish this with PDFBOX?
To join two pages one atop the other onto one target page, you can make use of the PDFBox LayerUtility for importing pages as form XObjects in a fashion similar to PDFBox SuperimposePage example, e.g. with this helper method:
void join(PDDocument target, PDDocument topSource, PDDocument bottomSource) throws IOException {
LayerUtility layerUtility = new LayerUtility(target);
PDFormXObject topForm = layerUtility.importPageAsForm(topSource, 0);
PDFormXObject bottomForm = layerUtility.importPageAsForm(bottomSource, 0);
float height = topForm.getBBox().getHeight() + bottomForm.getBBox().getHeight();
float width, topMargin, bottomMargin;
if (topForm.getBBox().getWidth() > bottomForm.getBBox().getWidth()) {
width = topForm.getBBox().getWidth();
topMargin = 0;
bottomMargin = (topForm.getBBox().getWidth() - bottomForm.getBBox().getWidth()) / 2;
} else {
width = bottomForm.getBBox().getWidth();
topMargin = (bottomForm.getBBox().getWidth() - topForm.getBBox().getWidth()) / 2;
bottomMargin = 0;
}
PDPage targetPage = new PDPage(new PDRectangle(width, height));
target.addPage(targetPage);
PDPageContentStream contentStream = new PDPageContentStream(target, targetPage);
if (bottomMargin != 0)
contentStream.transform(Matrix.getTranslateInstance(bottomMargin, 0));
contentStream.drawForm(bottomForm);
contentStream.transform(Matrix.getTranslateInstance(topMargin - bottomMargin, bottomForm.getBBox().getHeight()));
contentStream.drawForm(topForm);
contentStream.close();
}
(JoinPages method join)
You use it like this:
try ( PDDocument document = new PDDocument();
PDDocument top = ...;
PDDocument bottom = ...) {
join(document, top, bottom);
document.save("joinedPage.pdf");
}
(JoinPages test testJoinSmallAndBig)
The result looks like this:
Just as an additional point to #mkl's answer.
If anybody is looking to scale the PDFs before placing them on the page use,
contentStream.transform(Matrix.getScaleInstance(<scaling factor in x axis>, <scaling factor in y axis>)); //where 1 is the scaling factor if you want the page as the original size
This way you can rescale your PDFs.

Cannot capture annotations in a PDImageXObject using PDFBox

I am highlighting (in green) certain words on each page of my input pdf document using PDAnnotationTextMarkup. A sample screenshot is seen below;
However, when I crop this part of the page and try to save it as a PDImageXObject, I get the following result;
The code I am using to crop the image is as follows;
public PDImageXObject cropAndSaveImage(int pageNumber, Rectangle dimensions)
{
PDImageXObject pdImage = null;
// Extract arguments from the rectangle object
float x = dimensions.getXValue();
float y = dimensions.getYValue();
float w = dimensions.getWidth();
float h = dimensions.getHeight();
PDRectangle pdRectangle;
int pageResolution = 140;
try{
// Fetch the source page
PDPage sourcePage = document.getPage(pageNumber-1);
// Calculate height of the source page
PDRectangle mediaBox = sourcePage.getMediaBox();
float sourcePageHeight = mediaBox.getHeight();
// Fetch the original crop box of the page
PDRectangle originalCrop = sourcePage.getCropBox();
/*
* PDF Crop Box - Here we initialize the rectangle area
* that is needed to crop a region from the PDF document
*/
if(pageOriginShifted)
{
pdRectangle = new PDRectangle(x, sourcePageHeight - y, w, h);
}
else
{
pdRectangle = new PDRectangle(x, y, w, h);
}
// Crop the required rectangle from the source page
sourcePage.setCropBox(pdRectangle);
// PDF renderer
PDFRenderer renderer = new PDFRenderer(document);
// Convert to an image
BufferedImage bufferedImage = renderer.renderImageWithDPI(pageNumber-1, pageResolution, ImageType.RGB);
pdImage = LosslessFactory.createFromImage(document, bufferedImage);
// Restore the original page back to the document
sourcePage.setCropBox(originalCrop);
return pdImage;
}catch(Exception e)
{
Logger.logWithoutTimeStamp(LOG_TAG + "cropAndSaveImage()", Logger.ERROR, e);
}
return null;
}
I am quite perplexed on why the highlighted text in green won't show up. Any help in this regard is highly appreciated (I cannot attach the input PDF document owing to privacy issues).
Thanks in advance,
Bharat.

Insert image as new layer to existing PDF using PdfBox 1.8.8

I'm using PDFBox in my application to modify existing PDF files.
I need to place a barcode to the first page of the PDF document.
So first i create new PDF file with inserted barcode:
PDDocument document = new PDDocument();
PDXObjectImage ximage = new PDPixelMap(document, awtImage);
PDPage pag = new PDPage(new PDRectangle(ximage.getWidth(), ximage.getHeight()));
document.addPage(pag);
PDPageContentStream stream = new PDPageContentStream(document, pag, false, false);
stream.drawXObject(ximage, 0, 0, ximage.getWidth(), ximage.getHeight());
stream.close();
Then i try to place it as new layer into existing PDF:
Point barlocation = new Point(0,0);
float Height = page.getMediaBox().getHeight();
float Width = page.getMediaBox().getWidth();
barlocation.setLocation(Width - pag.getMediaBox().getWidth(), Height - pag.getMediaBox().getHeight()); //I need to place it in the top right corner
LayerUtility layerUtility = new LayerUtility(doc);
List bigPages = doc.getDocumentCatalog().getAllPages();
PDXObjectForm firstForm = layerUtility.importPageAsForm(document, 0);
AffineTransform affineTransform = new AffineTransform();
affineTransform.translate(barlocation.x , barlocation.y);
layerUtility.appendFormAsLayer((PDPage) bigPages.get(0), firstForm, affineTransform, "barcode layer");
doc.save(path);
doc.close();
So it works well with PDF document ver 1.5 (created in MS Word 2010/2013). But it's not working correctly with PDF document version 1.6 position and size of the inserted layer are wrong (i can't post an image, so you can see the result here:http://img4.imagetitan.com/img.php?image=11_capture567.png
What should I change? Thanks for reading and sorry for my bad English.

Categories

Resources