Writing multiple lines and pages in PDFBox - Get PDPageContentStream Y-Axis - java

I'm testing PDFBox and I've a doubt writing a new document..
The following code writes 75 lines in a pdf file. The height of the file isn't enough. So I'd need to know when the contentStream reaches the end of page in order to create a new one and continue writing lines.
Any way to solve my question?
Thank you so much!
File pdfFile = new File("hello.pdf");
PDDocument doc = new PDDocument();
PDPage page = new PDPage();
PDPageContentStream contentStream = new PDPageContentStream(doc, page);
contentStream.setFont( PDType1Font.TIMES_ROMAN, 12);
float initPosY = page.getMediaBox().getHeight()-50;
contentStream.beginText();
contentStream.newLineAtOffset(25, initPosY);
contentStream.setLeading(30.5f);
for(int i=1; i<75;i++){
contentStream.showText("Line: "+i);
contentStream.newLine();
}
contentStream.endText();
contentStream.close();
doc.addPage(page);
doc.save(pdfFile);
doc.close();

Substract the leading value (30.5f) from initPosY in your loop after calling newLine(). When it is < 0, or below a useful value (e.g. 50 which is your top margin), then you should start a new page.

Related

Not able to add extra content to an existing PDF using PDFBox

I am using PdfBox to generate pdf with an existing Pdf containing the template which has to be used for every Pdf that i want to generate.
But When i try to load the template pdf and wants to write something in it, all previous contains were removed.
So i want both the content should be shown.
Please suggest any solution for it.
Here is the code i am trying to do :
//Loading an existing document
File file = new File("/home/spaneos/ScoringReports-TM-110617.pdf");
PDDocument document = PDDocument.load(file);
//Retrieving the pages of the document
PDPage page = document.getPage(0);
PDPageContentStream contentStream = new PDPageContentStream(document, page);
//Begin the Content stream
contentStream.beginText();
//Setting the font to the Content stream
contentStream.setFont( PDType1Font.TIMES_ROMAN, 16 );
//Setting the leading
contentStream.setLeading(14.5f);
//Setting the position for the line
contentStream.newLineAtOffset(25, 725);
String text1 = "This is an example of adding text to a page in the pdf document.we can add as many lines";
String text2 = "as we want like this using the ShowText() method of the ContentStream class";
//Adding text in the form of string
contentStream.showText(text1);
contentStream.newLine();
contentStream.showText(text2);
//Creating PDImageXObject object
PDImageXObject pdImage = PDImageXObject.createFromFile("/home/spaneos/Downloads/man-161282_960_720.png",document);
//creating the PDPageContentStream object
PDPageContentStream contents = new PDPageContentStream(document, page);
contentStream.endText();
System.out.println("Content added");
//Closing the PDPageContentStream object
contents.close();
//Closing the content stream
contentStream.close();
//Saving the document
document.save(System.getProperty("user.dir").concat("/PdfBox_Examples/sample.pdf"));
//Closing the document
document.close();
You create the PDPageContentStream instances like this
PDPageContentStream contentStream = new PDPageContentStream(document, page);
[...]
PDPageContentStream contents = new PDPageContentStream(document, page);
Creating it using this constructor replaces any existing content streams with the new one. Instead use this one:
PDPageContentStream contents = new PDPageContentStream(document, page, AppendMode.APPEND, true, true);
AppendMode.APPEND here tells PDFBox to append the new stream, the first true tells it to compress the stream, and the second true tells it to reset the graphics state at the start of your added stream.
Furthermore, you don't really use the second content stream...

Unable to add Pages to PDF using PDFBox using separate method from main()

I am trying to dynamically add PDF pages depending upon content size.
for that I did not want to clutter the main method, instead I created a separate method to write the PDF and call the method from main() like below:
//PDF Log Method
PDlog("Create First Page", "b");
PDlog("add more page", "b");
PDlog("close pdf", "b");
I have added system.out.println at the end of each if condition, and all three are getting printed on IDE screen. but an Empty PDF is being generated after 3 method calls end. When I had only one if condition and called the PDlog method only once, the PDF is being saved and closed properly.
How can I call this method multiple times from main and keep on adding page and content multiple times?
Below is the method code:
public static void PDlog(String action, String msg) throws IOException, ClassNotFoundException, SQLException, InterruptedException, COSVisitorException {
//Master PDF Log File --------------------------------------------------------------------
String masterPDLog = "X:\\eHub\\QA\\eHub_Automation_Log.pdf";
// Create a document and add a page to it
PDDocument document = new PDDocument();
PDPage page = new PDPage(PDPage.PAGE_SIZE_A4);
if (action.equals("Create First Page")) {
document.addPage(page);
// Create a new font object selecting one of the PDF base fonts
PDFont font = PDType1Font.TIMES_ROMAN;
PDFont boldFont = PDType1Font.TIMES_BOLD;
//File for CTS Logo --------------------
InputStream in = new FileInputStream(new File("X:\\eHub\\QA\\img\\cts.jpg"));
PDJpeg img = new PDJpeg(document, in);
// Start a new content stream which will "hold" the to be created content
PDPageContentStream contentStream = new PDPageContentStream(document, page);
//Place CTS Logo
//contentStream.drawImage(img, 500, 750);
contentStream.drawXObject( img, 450, 700, 50, 50 );
// Define a text content stream using the selected font, moving the cursor and drawing the text "Hello World"
contentStream.beginText();
contentStream.setFont( boldFont, 20 );
contentStream.setNonStrokingColor(Color.BLUE);
contentStream.moveTextPositionByAmount( 120, 650 );
contentStream.drawString("eHub Automated Data Quality Report");
contentStream.endText();
contentStream.beginText();
contentStream.setFont( boldFont, 20 );
contentStream.setNonStrokingColor(Color.BLUE);
contentStream.moveTextPositionByAmount( 140, 600 );
contentStream.drawString("Data Profiling/Quality/Analysis");
contentStream.endText();
// Make sure that the content stream is closed:
contentStream.close();
//document.save(masterPDLog);
System.out.println("1ST PAGE ADDED");
}
else if (action.equals("add more page")) {
PDFont font = PDType1Font.TIMES_ROMAN;
document.addPage(page);
PDPageContentStream contentStream = new PDPageContentStream(document, page);
contentStream.beginText();
contentStream.setFont( font, 20 );
contentStream.setNonStrokingColor(Color.BLACK);
contentStream.moveTextPositionByAmount( 100, 800 );
contentStream.drawString("eHub Automated Data Quality Report");
contentStream.endText();
contentStream.close();
//document.save(masterPDLog);
System.out.println("2ND PAGE ADDED");
}
else if (action.equals("close pdf")) {
PDFont font = PDType1Font.TIMES_ROMAN;
PDPageContentStream contentStream = new PDPageContentStream(document, page);
contentStream.beginText();
contentStream.setFont( font, 20 );
contentStream.setNonStrokingColor(Color.BLACK);
contentStream.moveTextPositionByAmount( 100, 800 );
contentStream.drawString("eHub Automated Data Quality Report");
contentStream.endText();
contentStream.close();
document.save(masterPDLog);
document.close();
System.out.println("PDF CLOSED");
}
You create the document each time, that is why.
Just pass the document object to your method, and create the document first - here's your code, corrected:
public static void main(String[] args) throws IOException, COSVisitorException
{
PDDocument document = new PDDocument();
pdlog("Create First Page", "b", document);
pdlog("add more page", "b", document);
pdlog("close pdf", "b", document);
}
public static void pdlog(String action, String msg, PDDocument document) throws IOException, COSVisitorException
{
//Master PDF Log File --------------------------------------------------------------------
String masterPDLog = "X:\\eHub\\QA\\eHub_Automation_Log.pdf";
// Create a document and add a page to it
PDPage page = new PDPage(PDPage.PAGE_SIZE_A4);
if (action.equals("Create First Page"))
{
document.addPage(page);
// Create a new font object selecting one of the PDF base fonts
PDFont font = PDType1Font.TIMES_ROMAN;
PDFont boldFont = PDType1Font.TIMES_BOLD;
//File for CTS Logo --------------------
InputStream in = new FileInputStream(new File("X:\\eHub\\QA\\img\\cts.jpg"));
PDJpeg img = new PDJpeg(document, in);
// Start a new content stream which will "hold" the to be created content
PDPageContentStream contentStream = new PDPageContentStream(document, page);
//Place CTS Logo
//contentStream.drawImage(img, 500, 750);
contentStream.drawXObject(img, 450, 700, 50, 50);
// Define a text content stream using the selected font, moving the cursor and drawing the text "Hello World"
contentStream.beginText();
contentStream.setFont(boldFont, 20);
contentStream.setNonStrokingColor(Color.BLUE);
contentStream.moveTextPositionByAmount(120, 650);
contentStream.drawString("eHub Automated Data Quality Report");
contentStream.endText();
contentStream.beginText();
contentStream.setFont(boldFont, 20);
contentStream.setNonStrokingColor(Color.BLUE);
contentStream.moveTextPositionByAmount(140, 600);
contentStream.drawString("Data Profiling/Quality/Analysis");
contentStream.endText();
// Make sure that the content stream is closed:
contentStream.close();
//document.save(masterPDLog);
System.out.println("1ST PAGE ADDED");
}
else if (action.equals("add more page"))
{
PDFont font = PDType1Font.TIMES_ROMAN;
document.addPage(page);
PDPageContentStream contentStream = new PDPageContentStream(document, page);
contentStream.beginText();
contentStream.setFont(font, 20);
contentStream.setNonStrokingColor(Color.BLACK);
contentStream.moveTextPositionByAmount(100, 800);
contentStream.drawString("eHub Automated Data Quality Report");
contentStream.endText();
contentStream.close();
//document.save(masterPDLog);
System.out.println("2ND PAGE ADDED");
}
else if (action.equals("close pdf"))
{
PDFont font = PDType1Font.TIMES_ROMAN;
PDPageContentStream contentStream = new PDPageContentStream(document, page);
contentStream.beginText();
contentStream.setFont(font, 20);
contentStream.setNonStrokingColor(Color.BLACK);
contentStream.moveTextPositionByAmount(100, 800);
contentStream.drawString("eHub Automated Data Quality Report");
contentStream.endText();
contentStream.close();
document.save(masterPDLog);
document.close();
System.out.println("PDF CLOSED");
}
}
Your "close pdf" action does not make much sense, you are writing to a PDPage that is never appended.
1st of all, thanks Tilman for answering my actual question.
In the meantime, for practical purposes, I have changed my approach to writing dynamically to a PDF, as the code flows through If Else and Loops.... instead I have chosen to simply keep on Logging to simple text file using PrintWriter.
At the final end of the code, I am calling a method to Read each line of the Text Log file and place in a PDF document. To Summarize: One time Text to PDF conversion.
I explored iText and chose it over Apache PDFBox, it is perhaps 2-3 times faster than PDFBox and adding page is implicit and automatic.

Create mutli-page document dynamically using PDFBox

I am attempting to create a PDF report from a Java ResultSet. If the report was only one page, I would have no problem here. The issue comes from the fact that the report could be anywhere from one to ten pages long. Right now, I have this to create a single-page document:
PDDocument document = new PDDocument();
PDPage page = new PDPage(PDPage.PAGE_SIZE_LETTER);
document.addPage(page);
PDPageContentStream content = new PDPageContentStream(document,page);
So my question is, how do I create pages dynamically as they are needed. Is there an object-oriented answer staring me in the face and I just cannot see it?
As I expected, the answer was staring me right in the face, I just needed someone to point it out for me.
PDDocument document = new PDDocument();
PDPage page = new PDPage(PDPage.PAGE_SIZE_LETTER);
document.addPage(page);
PDPageContentStream content = new PDPageContentStream(document,page);
//generate data for first page
content.close();
//if number of results exceeds what can fit on the first page
page = new PDPage(PDPage.PAGE_SIZE_LETTER);
document.addPage(page);
content = new PDPageContentStream(document,page);
//generate data for second page
content.close();
Thanks to #mkl for the answer.
To Create Multi Page PDF Document using PDFBox:
(a) Create new page, new content stream, Move to Top Left, start writing. While writing each word check whether space required is not crossing mediabox width. If crosses, move to next line leftmost and start writing. Continue writing till the last line of the page.
(b) Close the contentStream and add the current page to the document when the writing operation reaches the last line of the current page,
(c) Repeat steps (a) and (b) till the last record/row/line is written.
PDDocument document = new PDDocument();
PDFont font = PDType1Font.HELVETICA;
//For Each Page:
PDPage page = new PDPage(PDPage.PAGE_SIZE_A4);
PDPageContentStream contentStream = new PDPageContentStream(document, page);
contentStream.setFont(font, 12);
contentStream.beginText();
contentStream.moveTextPositionByAmount(100, 700);
contentStream.drawString("PDF BOX TEXT CONTENT");
contentStream.endText();
contentStream.close();
document.addPage(page);
//After All Content is written:
document.save(pdfFile);
document.close();
Hint: Use Font parameters like size/height and remaining media box height to determine the last line of the page.

Cannot figure out how to use PDFBox

I am trying to create a PDF file with a lot of text boxes in the document and textfields from another class. I am using PDFBox.
OK, creating a new file is easy and writing one line of text is easy. Now, when I am trying to insert the next text line or textfield, it overwrites the content.
PDDocument doc = null;
PDPage page = null;
try{
doc = new PDDocument();
page = new PDPage();
doc.addPage(page);
PDFont font = PDType1Font.HELVETICA_BOLD;
PDPageContentStream title = new PDPageContentStream(doc, page);
title.beginText();
title.setFont( font, 14 );
title.moveTextPositionByAmount( 230, 720 );
title.drawString("DISPATCH SUMMARY");
title.endText();
title.close();
PDPageContentStream title1 = new PDPageContentStream(doc, page);
title1.beginText();
title1.setFont( font, 11 );
title1.moveTextPositionByAmount( 30, 620 );
title1.drawString("DEPARTURE");
title1.endText();
title1.close();
doc.save("PDFWithText.pdf");
doc.close();
} catch (Exception e){
System.out.println(e);
}
It does give me an error: "You are overwriting an existing content, you should use the append mode".
So I am trying title1.appendRawCommands(String), but it is not working.
How would I add new text boxes and textfields (from another class)? I have read tens of tutorials on Internet, but they only show creating one line.
PDPageContentStream title1 = new PDPageContentStream(doc, page, true, true);
OP posted this as the answer, so this will flag to the system that there was an answer
Furthermore, if the first content stream contains operations substantially changing the graphics state, e.g. by changing the current transformation matrix, and one wants the new content stream to start with these changes reverted, one should use the constructor with three boolean parameters:
PDPageContentStream title1 = new PDPageContentStream(doc, page, true, true, true);
This implementation is deprecated.
PDPageContentStream title1 = new PDPageContentStream(doc, page, true, true);
The new implementation would be
PDPageContentStream title1 = new PDPageContentStream(doc, page, PDPageContentStream.AppendMode.OVERWRITE, true);

PDFBox setting A5 page size

Started playing with PDFBox
PDDocument document = new PDDocument();
PDPage page = new PDPage();
document.addPage( page );
PDFont font = PDType1Font.HELVETICA_BOLD;
PDPageContentStream contentStream = new PDPageContentStream(document, page);
contentStream.beginText();
contentStream.setFont( font, 12 );
contentStream.moveTextPositionByAmount( 100, 700 );
contentStream.drawString( "Hello World" );
contentStream.endText();
contentStream.close();
document.save("Page.pdf");
document.close();
but I want to set the file size to be PDPage.PAGE_SIZE_A5. I've tried setting all the
setXXXBox(PDRectangle mediaBox) method signatures but I can't get the expected output.
page.setArtBox(PDPage.PAGE_SIZE_A5); // ??
page.setMediaBox(PDPage.PAGE_SIZE_A5); // ??
Any ideas?
Quick note: in PDFBox 2 replace PDPage.PAGE_SIZE_A5 with PDRectangle.A5, i.e.
PDPage page = new PDPage(PDRectangle.A5);
Use PDPage.PAGE_SIZE_A5 to change size to A5
PDPage page = new PDPage(PDPage.PAGE_SIZE_A5);

Categories

Resources