I want to generate a PDF of questions and their options using iText. I am able to generate the PDF but the problem is sometimes questions get printed at the end of a page and options go to the next page.
How can I determine that a question and its option will not fit in the same page?
This means that if question and options will not fit in the same page then that they must be placed on the next page.
UPDATED
com.itextpdf.text.Document document = new com.itextpdf.text.Document(PageSize.A4,50,50,15,15);
ByteArrayOutputStream OutputStream = new ByteArrayOutputStream();
PdfWriter writer = PdfWriter.getInstance(document, OutputStream);
document.open();
Paragraph paragraph = new Paragraph("Paper Name Here",new Font(FontFamily.TIMES_ROMAN,15,Font.BOLD));
paragraph.setAlignment(Element.ALIGN_CENTER);
document.add(paragraph);
document.addTitle("Paper Name Here");
document.addAuthor("corp");
com.itextpdf.text.List list = new com.itextpdf.text.List(true);
for (long i = 1; i <= 20 ; i++)
{
List<MultipleChoiceSingleCorrect> multipleChoiceSingleCorrects = new MultipleChoiceSingleCorrectServicesImpl().getItemDetailsByItemID(i);
for (MultipleChoiceSingleCorrect multipleChoiceSingleCorrect : multipleChoiceSingleCorrects) {
list.add(multipleChoiceSingleCorrect.getItemText());
RomanList oplist = new RomanList();
oplist.setIndentationLeft(20);
for (OptionSingleCorrect optionSingleCorrect : multipleChoiceSingleCorrect.getOptionList()) {
oplist.add(optionSingleCorrect.getOptionText());
}
list.add(oplist);
}
}
document.add(list);
document.close();
after this I m getting abnormal page brakes means some times question is at end of page and option jumps to next page.(AS shown in image below)
What you are interested in are the setKeepTogether(boolean) methods :
for Paragraph
or for PdfPTable
This will keep the object in one page, forcing the creation of a new page if the content doesn't fit in the remaining page.
with the help of Alexis Pigeon I done with this code. So special thanks to him.
I have added question text to Paragraph after that all options kept in an list.
Option list opList added in paragraph, this paragraph add to an ListItem and this ListItem
added to an master list.
This way question splitting on two pages is resolved but I m not getting question numbers.. I already set master list as numbered=true com.itextpdf.text.List list = new com.itextpdf.text.List(true);
Code:-
try {
String Filename="PaperName.pdf";
com.itextpdf.text.Document document = new com.itextpdf.text.Document(PageSize.A4,50,50,15,15);
ByteArrayOutputStream OutputStream = new ByteArrayOutputStream();
PdfWriter writer = PdfWriter.getInstance(document, OutputStream);
document.open();
Paragraph paragraph = new Paragraph("Paper Name Here",new Font(FontFamily.TIMES_ROMAN,15,Font.BOLD));
paragraph.setAlignment(Element.ALIGN_CENTER);
paragraph.setSpacingAfter(20);
document.add(paragraph);
document.addTitle("Paper Name Here");
document.addAuthor("crop");
document.addCreator("crop");
com.itextpdf.text.List list = new com.itextpdf.text.List(true);
for (long i = 1; i <= 20 ; i++)
{
List<MultipleChoiceSingleCorrect> multipleChoiceSingleCorrects = new MultipleChoiceSingleCorrectServicesImpl().getItemDetailsByItemID(i);
for (MultipleChoiceSingleCorrect multipleChoiceSingleCorrect : multipleChoiceSingleCorrects) {
Paragraph paragraph2 =new Paragraph();
paragraph2.setKeepTogether(true);
paragraph2.add(multipleChoiceSingleCorrect.getItemText());
paragraph2.add(Chunk.NEWLINE);
RomanList oplist = new RomanList();
oplist.setIndentationLeft(20);
for (OptionSingleCorrect optionSingleCorrect : multipleChoiceSingleCorrect.getOptionList()) {
oplist.add(optionSingleCorrect.getOptionText());
}
paragraph2.add(oplist);
paragraph2.setSpacingBefore(20);
ListItem listItem =new ListItem();
listItem.setKeepTogether(true);
listItem.add(paragraph2);
list.add(listItem);
}
}
document.add(list);
document.close();
response.setContentLength(OutputStream.size());
response.setContentType("application/pdf");
response.setHeader("Content-disposition", "attachment; filename=" + Filename);
ServletOutputStream out = response.getOutputStream();
OutputStream.writeTo(out);
out.flush();
}
catch (Exception e)
{
e.printStackTrace();
}
Related
hey guys sorry for long post and bad language and if there is unnecessary details
i created multiple 1page pdfs from one pdf template using excel document
i have now
something like this
tempfile0.pdf
tempfile1.pdf
tempfile2.pdf
...
im trying to merge all files in one single pdf using itext5
but it semmes that the pages in the resulted pdf are not in the order i wanted
per exemple
tempfile0.pdf in the first page
tempfile1. int the 2000 page
here is the code im using.
the procedure im using is:
1 filling a from from a hashmap
2 saving the filled form as one pdf
3 merging all the files in one single pdf
public void fillPdfitext(int debut,int fin) throws IOException, DocumentException {
for (int i =debut; i < fin; i++) {
HashMap<String, String> currentData = dataextracted[i];
// textArea.appendText("\n"+pdfoutputname +" en cours de preparation\n ");
PdfReader reader = new PdfReader(this.sourcePdfTemplateFile.toURI().getPath());
String outputfolder = this.destinationOutputFolder.toURI().getPath();
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(outputfolder+"\\"+"tempcontrat"+debut+"-" +i+ "_.pdf"));
// get the document catalog
AcroFields acroForm = stamper.getAcroFields();
// as there might not be an AcroForm entry a null check is necessary
if (acroForm != null) {
for (String key : currentData.keySet()) {
try {
String fieldvalue=currentData.get(key);
if (key=="ADRESSE1"){
fieldvalue = currentData.get("ADRESSE1")+" "+currentData.get("ADRESSE2") ;
acroForm.setField("ADRESSE", fieldvalue);
}
if (key == "IMEI"){
acroForm.setField("NUM_SERIE_PACK", fieldvalue);
}
acroForm.setField(key, fieldvalue);
// textArea.appendText(key + ": "+fieldvalue+"\t\t");
} catch (Exception e) {
// e.printStackTrace();
}
}
stamper.setFormFlattening(true);
}
stamper.close();
}
}
this is the code for merging
public void Merge() throws IOException, DocumentException
{
File[] documentPaths = Main.objetapp.destinationOutputFolder.listFiles((dir, name) -> name.matches( "tempcontrat.*\\.pdf" ));
Arrays.sort(documentPaths, NameFileComparator.NAME_INSENSITIVE_COMPARATOR);
byte[] mergedDocument;
try (ByteArrayOutputStream memoryStream = new ByteArrayOutputStream())
{
Document document = new Document();
PdfSmartCopy pdfSmartCopy = new PdfSmartCopy(document, memoryStream);
document.open();
for (File docPath : documentPaths)
{
PdfReader reader = new PdfReader(docPath.toURI().getPath());
try
{
reader.consolidateNamedDestinations();
PdfImportedPage pdfImportedPage = pdfSmartCopy.getImportedPage(reader, 1);
pdfSmartCopy.addPage(pdfImportedPage);
}
finally
{
pdfSmartCopy.freeReader(reader);
reader.close();
}
}
document.close();
mergedDocument = memoryStream.toByteArray();
}
FileOutputStream stream = new FileOutputStream(this.destinationOutputFolder.toURI().getPath()+"\\"+
this.sourceDataFile.getName().replaceFirst("[.][^.]+$", "")+".pdf");
try {
stream.write(mergedDocument);
} finally {
stream.close();
}
documentPaths=null;
Runtime r = Runtime.getRuntime();
r.gc();
}
my question is how to keep the order of the files the same in the resulting pdf
It is because of naming of files. Your code
new FileOutputStream(outputfolder + "\\" + "tempcontrat" + debut + "-" + i + "_.pdf")
will produce:
tempcontrat0-0_.pdf
tempcontrat0-1_.pdf
...
tempcontrat0-10_.pdf
tempcontrat0-11_.pdf
...
tempcontrat0-1000_.pdf
Where tempcontrat0-1000_.pdf will be placed before tempcontrat0-11_.pdf, because you are sorting it alphabetically before merge.
It will be better to left pad file number with 0 character using leftPad() method of org.apache.commons.lang.StringUtils or java.text.DecimalFormat and have it like this tempcontrat0-000000.pdf, tempcontrat0-000001.pdf, ... tempcontrat0-9999999.pdf.
And you can also do it much simpler and skip writing into file and then reading from file steps and merge documents right after the form fill and it will be faster. But it depends how many and how big documents you are merging and how much memory do you have.
So you can save the filled document into ByteArrayOutputStream and after stamper.close() create new PdfReader for bytes from that stream and call pdfSmartCopy.getImportedPage() for that reader. In short cut it can look like:
// initialize
PdfSmartCopy pdfSmartCopy = new PdfSmartCopy(document, memoryStream);
for (int i = debut; i < fin; i++) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
// fill in the form here
stamper.close();
PdfReader reader = new PdfReader(out.toByteArray());
reader.consolidateNamedDestinations();
PdfImportedPage pdfImportedPage = pdfSmartCopy.getImportedPage(reader, 1);
pdfSmartCopy.addPage(pdfImportedPage);
// other actions ...
}
This is my code:
try {
dozen = magazijn.getFfd().vraagDozenOp();
for (int i = 0; i < dozen.size(); i++) {
PdfWriter.getInstance(doc, new FileOutputStream("Order" + x + ".pdf"));
System.out.println("Writer instance created");
doc.open();
System.out.println("doc open");
Paragraph ordernummer = new Paragraph(order.getOrdernummer());
doc.add(ordernummer);
doc.add( Chunk.NEWLINE );
for (String t : text) {
Paragraph klant = new Paragraph(t);
doc.add(klant);
}
doc.add( Chunk.NEWLINE );
Paragraph datum = new Paragraph (order.getDatum());
doc.add(datum);
doc.add( Chunk.NEWLINE );
artikelen = magazijn.getFfd().vraagArtikelenOp(i);
for (Artikel a : artikelen){
artikelnr.add(a.getArtikelNaam());
}
for (String nr: artikelnr){
Paragraph Artikelnr = new Paragraph(nr);
doc.add(Artikelnr);
}
doc.close();
artikelnr.clear();
x++;
System.out.println("doc closed");
}
} catch (Exception e) {
System.out.println(e);
}
I get this exception: com.itextpdf.text.DocumentException: The document has been closed. You can't add any Elements.
can someone help me fix this so that the other pdf can be created and paragrphs added?
Alright, your intent is not very clear from your code and question so I'm going to operate under the following assumptions:
You are creating a report for each box you're processing
Each report needs to be a separate PDF file
You're getting a DocumentException on the second iteration of the loop, you're trying to add content to a Document that has been closed in the previous iteration via doc.close();. 'doc.close' will finalize the Document and write everything still pending to any linked PdfWriter.
If you wish to create separate pdfs for each box, you need to create a seperate Document in your loop statement as well, since creating a new PdfWriter via PdfWriter.getInstance(doc, new FileOutputStream("Order" + x + ".pdf")); will not create a new Document on its own.
If I'm wrong with assumption 2 and you wish to add everything to a single PDF, move doc.close(); outside of the loop and create only a single PdfWriter
You can try something like this using Apache PDFBox
File outputFile = new File(path);
outputFile.createNewFile();
PDDocument newDoc = new PDDocument();
then create a PDPage and write what you wanna write in that page. After your page is ready, add it to the newDoc and in the end save it and close it
newDoc.save(outputFile);
newDoc.close()
repeat this dozen.size() times and keep changing the file's name in path for every new document.
I have been breaking my head from past 1 hour i am not able to solve this issue...i know its easy to write the PDF in java but my outputstream size is zero,... here is my code..
Document document = new Document();
try
{
ByteArrayOutputStream dsf = new ByteArrayOutputStream();
PdfWriter writer = PdfWriter.getInstance(document, dsf);
document.open();
document.add(new Paragraph("Some content here"));
// Set attributes here
document.addAuthor("Lokesh Gupta");
document.addCreationDate();
document.addCreator("HowToDoInJava.com");
document.addTitle("Set Attribute Example");
document.addSubject("An example to show how attributes can be added to pdf files.");
if (frontPageMap != null && !frontPageMap.isEmpty()) {
PdfPTable table = new PdfPTable(frontPageMap.size()); // creating
// columns.
table.setWidthPercentage(100); // Width 100%
table.setSpacingBefore(10f); // Space before table
table.setSpacingAfter(10f); // Space after table
for (Map.Entry<String, Object> entry : frontPageMap.entrySet()) {
PdfPCell tempCell = new PdfPCell(new Paragraph(entry.getKey()));
tempCell.setBorderColor(BaseColor.BLUE);
tempCell.setPaddingLeft(10);
tempCell.setHorizontalAlignment(Element.ALIGN_CENTER);
tempCell.setVerticalAlignment(Element.ALIGN_MIDDLE);
table.addCell(tempCell);
}
document.add(table);
}
System.out.println("Size Of Byte Array is "+dsf.size());
ByteArrayInputStream bInput = new ByteArrayInputStream(dsf.toByteArray());
file = new DefaultStreamedContent(bInput, "pdf", fileName);
document.close();
writer.close();
NOTE:I am able to print map key values also but When i download PDF the size is zero.
Maybe you should finish creating the PDF (with document.close() and writer.close()), before you try to access the contents:
//Finish writing the PDF
document.close();
writer.close();
//now check what's been written:
System.out.println("Size Of Byte Array is "+dsf.size());
ByteArrayInputStream bInput = new ByteArrayInputStream(dsf.toByteArray());
file = new DefaultStreamedContent(bInput, "pdf", fileName);
document.close();
writer.close();
ByteArrayInputStream bInput = new ByteArrayInputStream(dsf.toByteArray());
file = new DefaultStreamedContent(bInput, "pdf", fileName);
System.out.println("Size Of Byte Array is "+dsf.size());
Add this code. Here you finish writing the pdf file and then you can print the size of the file. The size my be zero according to the content , but the pdf file generated should have all the records written in it ... Cheers :)
i'm using iText 5.5.5 with Java5.
I'm trying to merge some PDF/A. when I got a "PdfAConformanceException: PDF array is out of bounds".
Trying to find error I find the "bad PDF" that cause the error and when I try to copy just it exception throw again. This error don't appear always, it appear just when this PDF/A is in the "job chain"; I tried with some other files and it's all fine. I cant share with you source PDF 'couse it's restricted.
That's my piece of code:
_log.info("Start Document Merge");
// Output pdf
ByteArrayOutputStream bos = new ByteArrayOutputStream();
com.itextpdf.text.Document document = new com.itextpdf.text.Document();
PdfCopy copy = new PdfACopy(document, bos, PdfAConformanceLevel.PDF_A_1B);
PageStamp stamp = null;
PdfReader reader = null;
PdfContentByte content = null;
int outPdfPageCount = 0;
BaseFont baseFont = BaseFont.createFont("Arial", BaseFont.WINANSI, BaseFont.EMBEDDED);
copyOutputIntents(reader, copy);
// Loop over the pages in that document
try {
int numberOfPages = reader.getNumberOfPages();
for (int i = 1; i <= numberOfPages; i++) {
PdfImportedPage pagecontent = copy.getImportedPage(reader, i);
_log.debug("Handling page numbering [" + i + "]");
stamp = copy.createPageStamp(pagecontent);
content = stamp.getUnderContent();
content.beginText();
content.setFontAndSize(baseFont, Configuration.NumPagSize);
content.showTextAligned(PdfContentByte.ALIGN_CENTER, String.format("%s %s ", Configuration.NumPagPrefix, i), Configuration.NumPagX, Configuration.NumPagY, 0);
content.endText();
stamp.alterContents();
copy.addPage(pagecontent);
outPdfPageCount++;
if (outPdfPageCount > Configuration.MaxPages) {
_log.error("Pdf Page Count > MaxPages");
throw new PackageException(Constants.ERROR_104_TEXT, Constants.ERROR_104);
}
}
copy.freeReader(reader);
reader.close();
copy.createXmpMetadata();
document.close();
} catch (Exception e) {
_log.error("Error during mergin Document, skip");
_log.debug(MiscUtil.stackToString(e));
}
return bos.toByteArray();
That's the full stacktrace:
com.itextpdf.text.pdf.PdfAConformanceException: PDF array is out of bounds.
at com.itextpdf.text.pdf.internal.PdfA1Checker.checkPdfObject(PdfA1Checker.java:269)
at com.itextpdf.text.pdf.internal.PdfAChecker.checkPdfAConformance(PdfAChecker.java:208)
at com.itextpdf.text.pdf.internal.PdfAConformanceImp.checkPdfIsoConformance(PdfAConformanceImp.java:71)
at com.itextpdf.text.pdf.PdfWriter.checkPdfIsoConformance(PdfWriter.java:3480)
at com.itextpdf.text.pdf.PdfWriter.checkPdfIsoConformance(PdfWriter.java:3476)
at com.itextpdf.text.pdf.PdfArray.toPdf(PdfArray.java:165)
at com.itextpdf.text.pdf.PdfDictionary.toPdf(PdfDictionary.java:149)
at com.itextpdf.text.pdf.PdfArray.toPdf(PdfArray.java:175)
at com.itextpdf.text.pdf.PdfDictionary.toPdf(PdfDictionary.java:149)
at com.itextpdf.text.pdf.PdfIndirectObject.writeTo(PdfIndirectObject.java:158)
at com.itextpdf.text.pdf.PdfWriter$PdfBody.write(PdfWriter.java:420)
at com.itextpdf.text.pdf.PdfWriter$PdfBody.add(PdfWriter.java:398)
at com.itextpdf.text.pdf.PdfWriter$PdfBody.add(PdfWriter.java:373)
at com.itextpdf.text.pdf.PdfWriter$PdfBody.add(PdfWriter.java:369)
at com.itextpdf.text.pdf.PdfWriter.addToBody(PdfWriter.java:843)
at com.itextpdf.text.pdf.PdfCopy.addToBody(PdfCopy.java:839)
at com.itextpdf.text.pdf.PdfCopy.addToBody(PdfCopy.java:821)
at com.itextpdf.text.pdf.PdfCopy.copyIndirect(PdfCopy.java:426)
at com.itextpdf.text.pdf.PdfCopy.copyIndirect(PdfCopy.java:446)
at com.itextpdf.text.pdf.PdfCopy.copyObject(PdfCopy.java:577)
at com.itextpdf.text.pdf.PdfCopy.copyDictionary(PdfCopy.java:503)
at com.itextpdf.text.pdf.PdfCopy.copyObject(PdfCopy.java:573)
at com.itextpdf.text.pdf.PdfCopy.copyDictionary(PdfCopy.java:503)
at com.itextpdf.text.pdf.PdfCopy.copyObject(PdfCopy.java:573)
at com.itextpdf.text.pdf.PdfCopy.copyDictionary(PdfCopy.java:493)
at com.itextpdf.text.pdf.PdfCopy.copyDictionary(PdfCopy.java:519)
at com.itextpdf.text.pdf.PdfCopy.addPage(PdfCopy.java:663)
at com.itextpdf.text.pdf.PdfACopy.addPage(PdfACopy.java:115)
at it.m2sc.engageone.documentpackage.generator.PackageGenerator.mergePDF(PackageGenerator.java:256)
In that specific case, the problem depends by a specific Font ( Gulim ) that is too big to be embedded in PDF/A-1 file. When that font was removed, everything war run fine.
Everything I have read regarding iText says you should be able to set the page size and then create a new page. But for some reason when I try this my first page isn't rotated. But my second is. Any ideas?
response.setContentType("application/pdf");
Document document = new Document();
try{
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
PdfWriter.getInstance(document, buffer);
document.open();
//Start a new page
document.setPageSize(PageSize.LETTER.rotate()); // 11" x 8.5" new Rectangle(792f, 612f)
document.newPage();
Paragraph topText = new Paragraph();
// add some content here...
document.close();
DataOutput dataOutput = new DataOutputStream(response.getOutputStream());
byte[] bytes = buffer.toByteArray();
response.setContentLength(bytes.length);
for(int i = 0; i < bytes.length; i++) {
dataOutput.writeByte(bytes[i]);
}
} catch (DocumentException e) {
e.printStackTrace();
}
document.newPage() really means "finish the current page and open a new one". This implies that after you open() a document, you already have a blank page (with whatever size the document had set before) ready.
You should set your page size before opening the document:
document.setPageSize(PageSize.LETTER.rotate());
document.open();