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);
Related
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.
I'm trying to embed a subset of noto-regular in my code. but I keeping on getting:
java.lang.UnsupportedOperationException: OTF fonts do not have a glyf table
at org.apache.fontbox.ttf.OpenTypeFont.getGlyph(OpenTypeFont.java:66)
at org.apache.fontbox.ttf.TTFSubsetter.addCompoundReferences(TTFSubsetter.java:481)
at org.apache.fontbox.ttf.TTFSubsetter.getGIDMap(TTFSubsetter.java:136)
at org.apache.pdfbox.pdmodel.font.TrueTypeEmbedder.subset(TrueTypeEmbedder.java:306)
at org.apache.pdfbox.pdmodel.font.PDType0Font.subset(PDType0Font.java:162)
at org.apache.pdfbox.pdmodel.PDDocument.save(PDDocument.java:1138)
I downloaded the font file NotoSansCJK-Regular.ttc from https://www.google.com/get/noto/help/cjk/
Font subsetting works for .ttf fonts, as I haven't had any issues if the document I saved contains no special characters.
EDIT
It appears that true type collection fonts can have shared glyf table (makes sense since the font collection contains Japanese glyphs). So the individual PDType0Font parsed from .ttc can't be treated as an individual font.
I loaded the font using:
ttc.processAllFonts((TrueTypeFont ttf) -> {
PDFont font = PDType0Font.load(doc, ttf, true);
fontList.add(font);
});
I'm guessing that there are extra work I needed to do to make this work, but I can't find any code samples anywhere.
EDIT2
Seems like the problem is that when subsetting specific OpenType font files, (which font collection contains) turns on an internal flag isPostScript. The flag is then checked and process is aborted when getGlyph() is called.
The following code generates the glyf table error when creating the pdf documents
// downloaded from Noto project site
String OTF_FILE = "./src/test/resources/NotoSansJP-Regular.otf";
PDDocument doc = new PDDocument();
PDFont otf = null;
try (InputStream inputStream = new FileInputStream(new File(OTF_FILE))) {
otf = PDType0Font.load(doc, new OTFParser().parse(inputStream), true);
PDPage page = new PDPage();
PDPageContentStream stream = new PDPageContentStream(doc, page);
stream.setFont(otf, 10f);
stream.beginText();
stream.newLineAtOffset(100f, 600f);
stream.showText("二ろほス反2化みた大第リきやね景手ハニエ者性ルヤリウ円脱");
stream.endText();
stream.close();
doc.addPage(page);
doc.save("test.pdf");
} catch (IOException iox) {
// failed
}
but it will generate the pdf fine as soon as I set the subsetting parameter to true in the PDType0Font.load call
Similarily if I load the otf font through the collection:
String OTF_FILE = "./src/test/resources/NotoSansCJK-Regular.ttc";
PDDocument doc = new PDDocument();
PDFont otf = null;
try (InputStream inputStream = new FileInputStream(new File(OTF_FILE))) {
TrueTypeCollection ttc = new TrueTypeCollection(inputStream);
otf = PDType0Font.load(doc, ttc.getFontByName("NotoSansCJKjp-Regular"), true);
PDPage page = new PDPage();
PDPageContentStream stream = new PDPageContentStream(doc, page);
stream.setFont(otf, 10f);
stream.beginText();
stream.newLineAtOffset(100f, 600f);
stream.showText("二ろほス反2化みた大第リきやね景手ハニエ者性ルヤリウ円脱");
stream.endText();
stream.close();
doc.addPage(page);
doc.save("test.pdf");
} catch (IOException iox) {
// failed
}
I either need to embed the whole font or subsetting will throw the error
EDIT 3
I ended up circumvent this by downloading the OTF font from "Language-specific OpenType/CFF (OTF)", which contains characters from all 4 regions and converted it using otf2ttf from fonttools
I am relativly new to Java and I want to replace an existing iText based Javascript with pdfbox. (Java 2.0)
I have a pdf-Formsheet (but this sheet has no Acroform entries) and I want to fill it with information (Name, Birthdate and so on). The pdf is in a rectangular special size (like a contact card).
My code so far:
File file = new File("ToBeFilled.pdf");
PDDocument document = PDDocument.load(file);
System.out.println("PDF loaded");
//Retrieving the page
PDPage page = (PDPage)document.getPages().get( 0 );
PDFont font = PDType1Font.HELVETICA_BOLD;
PDPageContentStream content = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.APPEND, true);
content.beginText();
//Setting the font to the Content stream
content.setFont(font, 30);
//Setting the position for the line (float x, float y), (0,0) = lower left corner
content.newLineAtOffset(100, 400);
String text = "This is the sample document and we are adding content to it.";
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
content.showText(text);
//Adding text in the form of string
content.newLine();
content.showText(text1);
content.newLine();
content.showText(text2);
//Ending the content stream
content.endText();
System.out.println("Text added");
content.close();
//Saving the document
document.save("newPrint.pdf");
//Closing the document
document.close();
The text does not show. What am I missing here? I thought with the correct text-positions I could simply write on the pdf?
The source is working.
Maybe your content.newLineAtOffset(100, 400); is too huge - out of bounds - for your little card.
By the way, you have to setLeading(float) to use newLine() meaningfuly.
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...
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.