iTextSharp: "The document is not open" error - when it actually is - itext

I have this code:
private static byte[] ConvertPdfDocument(Document document, PdfPTable headerTable, PdfPTable affidavitsTable)
{
byte[] b;
using (MemoryStream ms = new MemoryStream())
{
PdfWriter writer = PdfWriter.GetInstance(document, ms);
if (document.IsOpen() == false)
{
document.Open();
}
document.Add(headerTable);
document.Add(affidavitsTable);
document.Close();
writer.Close();
b = ms.ToArray();
}
return b;
}
The "document" object is opened (using document.Open() outside of this method then passed in.
The condition document.IsOpen() evaluates to True. I've further confirmed the document is actually open by looking at the private properties of the "document" object in the debugger; it shows that "Open" is "true".
Accordingly, execution moves on to the document.Add(headerTable) line.
And at that point an exception is thrown: "The document is not open."
And while the debugger is stopped (due to that exception being thrown), using the same two ways described above, I can still see the document is open.
How could that be?
I've been Googling for a while but can't find anything, other than the same question posted here with no answer...
Any help would be greatly appreciated.
Thanks much,
Eliezer

The document must be opened after being used in PdfWriter.GetInstance() otherwise there no writer associated and it does nothing.

create document out of the for loop
Document document = new Document();
PdfWriter.getInstance(document, new FileOutputStream("D:\\addLife271118\\src\\assets\\finalbill.pdf"));
document.open();
try {
document.add(new Paragraph(" "));
String[] names= {"james","siva"};
for(int i= 0; i< names.length;i++)
{
document.add(new Paragraph(names[i]));
document.add(Chunk.NEWLINE);
}
} catch (DocumentException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
document.close();

Related

iText7: Error at file pointer when merging two pdfs

We are in the last steps of evaluating iText7. We use iText 7.1.0 and html2pdf 2.0.0.
What we do: we send a json_encoded collection with pdf-data (which includes html for header, body and footer) to our Java app. There we iterate over the collection, create a byteArrayOutputStream for each pdf-data element and merge them together. We then send the results to a script which echoes it to e.g. a browser. Although the pdf is displayed correctly, we encounter errors while creating it:
com.itextpdf.io.IOException: Error at file pointer 226,416.
...
Caused by: com.itextpdf.io.IOException: xref subsection not found.
... 73 common frames omitted
If we create only one part of the collection, no error is thrown.
Iterate over collection and merge:
#RequestMapping(value = "/pdf", method = RequestMethod.POST, produces = MediaType.APPLICATION_PDF_VALUE)
public byte[] index(#RequestBody PDFDataModelCollection elements, Model model) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
PdfWriter writer = new PdfWriter(byteArrayOutputStream);
try (PdfDocument resultDoc = new PdfDocument(writer)) {
for (PDFDataModel pdfDataModel : elements.getElements()) {
PdfReader reader = new PdfReader(new ByteArrayInputStream(creationService.createDatasheet(pdfDataModel)));
try (PdfDocument sourceDoc = new PdfDocument(reader)) {
int n = sourceDoc.getNumberOfPages(); //<-- IOException on second iteration
for (int i = 1; i <= n; i++) {
PdfPage page = sourceDoc.getPage(i).copyTo(resultDoc);
resultDoc.addPage(page);
}
}
}
}
return byteArrayOutputStream.toByteArray(); //outputs the final pdf
}
Creation of part:
public byte[] createDatasheet(PDFDataModel pdfDataModel) throws IOException {
PdfWriter writer = new PdfWriter(byteArrayOutputStream);
//Initialize PDF document
PdfDocument pdfDoc = new PdfDocument(writer);
try (
Document document = new Document(pdfDoc)
) {
//header, footer, etc
//body
for (IElement element : HtmlConverter.convertToElements(pdfDataModel.getBody(), this.props)) {
document.add((IBlockElement) element);
}
footer.writeTotalNumberOnPages(pdfDoc);
}
return byteArrayOutputStream.toByteArray();
}
We are grateful for any suggestion.
In createDatasheet you appear to re-use some byteArrayOutputStream without clearing it first.
In the first iteration, therefore, everything works as desired, at the end of createDatasheet you have a single PDF file in it.
In the second iteration, though, you have two PDF files in that byteArrayOutputStream, one after the other. This concatenation does not form a valid single PDF.
Thus, byteArrayOutputStream.toByteArray() returns something broken.
To fix this, either make the byteArrayOutputStream local to createDatasheet and create a new instance every time or alternatively reset byteArrayOutputStream at the start of createDatasheet:
public byte[] createDatasheet(PDFDataModel pdfDataModel) throws IOException {
byteArrayOutputStream.reset();
PdfWriter writer = new PdfWriter(byteArrayOutputStream);
[...]

how to change code so it works with itext 7

The following code works nicely with iText 5:
LEVEL = PdfAConformanceLevel.PDF_A_3A
writer = PdfAWriter.getInstance(document, baos, LEVEL)
What is the correct syntax for iText 7?
Where can I find examples and documentation about iText 7?
why so negative? Seems like you want to put extra pressure on me to write documentation. That's kind of frustrating. I think that encouragement works better. Nevertheless, your claim that there's no documentation is wrong.
See Chapter 7: Creating PDF/UA and PDF/A documents of the iText 7: Jump-Start Tutorial
You overlooked the UnitedStates_PDFA_3a example in which we have a CSV file that we convert to a PDF/A-3 document adding that CSV file as attachment.
public void createPdf(String dest) throws IOException, XMPException {
PdfADocument pdf = new PdfADocument(new PdfWriter(dest),
PdfAConformanceLevel.PDF_A_3A,
new PdfOutputIntent("Custom", "", "http://www.color.org",
"sRGB IEC61966-2.1", new FileInputStream(INTENT)));
Document document = new Document(pdf, PageSize.A4.rotate());
document.setMargins(20, 20, 20, 20);
//Setting some required parameters
pdf.setTagged();
pdf.getCatalog().setLang(new PdfString("en-US"));
pdf.getCatalog().setViewerPreferences(
new PdfViewerPreferences().setDisplayDocTitle(true));
PdfDocumentInfo info = pdf.getDocumentInfo();
info.setTitle("iText7 PDF/A-3 example");
//Add attachment
PdfDictionary parameters = new PdfDictionary();
parameters.put(PdfName.ModDate, new PdfDate().getPdfObject());
PdfFileSpec fileSpec = PdfFileSpec.createEmbeddedFileSpec(
pdf, Files.readAllBytes(Paths.get(DATA)), "united_states.csv",
"united_states.csv", new PdfName("text/csv"), parameters,
PdfName.Data, false);
fileSpec.put(new PdfName("AFRelationship"), new PdfName("Data"));
pdf.addFileAttachment("united_states.csv", fileSpec);
PdfArray array = new PdfArray();
array.add(fileSpec.getPdfObject().getIndirectReference());
pdf.getCatalog().put(new PdfName("AF"), array);
//Embed fonts
PdfFont font = PdfFontFactory.createFont(FONT, true);
PdfFont bold = PdfFontFactory.createFont(BOLD_FONT, true);
// Create content
Table table = new Table(new float[]{4, 1, 3, 4, 3, 3, 3, 3, 1});
table.setWidthPercent(100);
BufferedReader br = new BufferedReader(new FileReader(DATA));
String line = br.readLine();
process(table, line, bold, true);
while ((line = br.readLine()) != null) {
process(table, line, font, false);
}
br.close();
document.add(table);
//Close document
document.close();
}
public void process(Table table, String line, PdfFont font, boolean isHeader) {
StringTokenizer tokenizer = new StringTokenizer(line, ";");
while (tokenizer.hasMoreTokens()) {
if (isHeader) {
table.addHeaderCell(new Cell().setHorizontalAlignment(HorizontalAlignment.CENTER).add(new Paragraph(tokenizer.nextToken()).setHorizontalAlignment(HorizontalAlignment.CENTER).setFont(font)));
} else {
table.addCell(new Cell().setHorizontalAlignment(HorizontalAlignment.CENTER).add(new Paragraph(tokenizer.nextToken()).setHorizontalAlignment(HorizontalAlignment.CENTER).setFont(font)));
}
}
}

C# - System.ObectDisposedException in MemoryStream for Capacity, Length, and Position Properties

When executing the code to render PDF file from Html Stream, code seems to be executing fine, but PDF is not generated.
When debugging through the code, it seems that everything works just fine until I do not start looking into MemoryStream object properties and notice the following under MemoryStream object:
This is the code:
public partial class WriteNotes : System.Web.UI.Page
{
...
protected override void Render(System.Web.UI.HtmlTextWriter writer)
{
...
using (System.IO.MemoryStream printStream = new System.IO.MemoryStream())
using (System.IO.StreamWriter printStreamWriter = new System.IO.StreamWriter(printStream))
using (System.Web.UI.HtmlTextWriter printWriter = new System.Web.UI.HtmlTextWriter(printStreamWriter))
{
base.Render(printWriter);
printWriter.Flush();
using (System.IO.StreamReader myStreamReader = new System.IO.StreamReader(printStream))
{
myStreamReader.BaseStream.Position = 0;
Document pdfDocument = pdfConverter.GetPdfDocumentObjectFromHtmlStream(myStreamReader.BaseStream, System.Text.Encoding.Default, HttpContext.Current.Request.Url.ToString().Replace(HttpContext.Current.Request.Url.PathAndQuery, "/"));
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.ContentType = "application/pdf";
pdfDocument.Save(HttpContext.Current.Response.OutputStream);
HttpContext.Current.Response.Flush();
HttpContext.Current.Response.End();
}
}
}
...
}
Executing the following line of code produces the described exception for MemoryStream.
Document pdfDocument = pdfConverter.GetPdfDocumentObjectFromHtmlStream(myStreamReader.BaseStream, System.Text.Encoding.Default, HttpContext.Current.Request.Url.ToString().Replace(HttpContext.Current.Request.Url.PathAndQuery, "/"));
The same kind of exception happens if I do not use Disposable Pattern.
The same code is in production and works fine.
What can be the reason?
Sure enough, found it. Read the documentation here:
PdfConverter.GetPdfDocumentObjectFromHtmlStream(htmlStream, streamEncoding)
In a nutshell it says to close the document object which you are not doing in your code above.
PdfDocument.Close()
States it here too, always call method close on the document object once you are done with it. Try this updated code.
Also add the library you are using next time if you happen to know it. Some answers can be found right in the documentation (not all the time of course).
public partial class WriteNotes : System.Web.UI.Page
{
...
protected override void Render(System.Web.UI.HtmlTextWriter writer)
{
...
using (System.IO.MemoryStream printStream = new System.IO.MemoryStream())
using (System.IO.StreamWriter printStreamWriter = new System.IO.StreamWriter(printStream))
using (System.Web.UI.HtmlTextWriter printWriter = new System.Web.UI.HtmlTextWriter(printStreamWriter))
{
base.Render(printWriter);
printWriter.Flush();
using (System.IO.StreamReader myStreamReader = new System.IO.StreamReader(printStream))
{
myStreamReader.BaseStream.Position = 0;
Document pdfDocument = pdfConverter.GetPdfDocumentObjectFromHtmlStream(myStreamReader.BaseStream, System.Text.Encoding.Default, HttpContext.Current.Request.Url.ToString().Replace(HttpContext.Current.Request.Url.PathAndQuery, "/"));
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.ContentType = "application/pdf";
pdfDocument.Save(HttpContext.Current.Response.OutputStream);
pdfDocument.Close(); // add this line and see what happens
HttpContext.Current.Response.Flush();
HttpContext.Current.Response.End();
}
}
}
...
}

itextsharp 5.4.4 CopyAcroForm no longer there

In version 5.4.2 of itextsharp I was able to use: (fragment in VB)
Dim pdfWriter As iTextSharp.text.pdf.PdfCopy
pdfwriter = New iTextSharp.text.pdf.PdfCopy(outputPDFDocument, New FileStream(destfname, FileMode.Create))
pdfWriter.CopyAcroForm(reader)
to copy a form from one document to another.
In 5.4.4 CopyAcroForm is no longer there under PdfCopy or anywhere else - what is the alternative?
Please read the release notes for iText 5.4.4. It is now possible to use PdfCopy to merge PDFs containing AcroForm forms by using the addDocument() method. This method is much better than the copyAcroForm() method as it also preserves the structured tree root. This is important if your forms are made accessible (cf Section 508 or the PDF/UA standard).
AddDocument() method is cool. Here is my code that read and merge multiple PDFs from SQL server in asp.net . document.Close() is required to flush the content to memory stream.
enter code here
Document document = new Document();
MemoryStream output = new MemoryStream();
PdfCopy writer = new PdfCopy(document, output); // Initialize pdf writer
writer.SetMergeFields();
document.Open();
SqlDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
PdfReader reader = new PdfReader((Byte[])dr["ImageFile"]);
writer.AddDocument(reader);
}
dr.Close();
document.Close();
It looks like you also need to call .SetMergeFields() or it won't work:
reader = new PdfReader(path);
using (var document = new Document(reader.GetPageSizeWithRotation(1))) {
using (var outputStream = new FileStream(...)) {
using (var writer = new PdfCopy(document, outputStream)) {
writer.SetMergeFields();
document.Open();
//all pages:
writer.AddDocument(reader);
//Particular Pages:
//writer.AddDocument(reader, new List<int> { pageNumber });
}
}
}

Creating a PDF back page using Itext

I am currently using iText (Java) to create a PDF document.
This PDf document is meant to be a Businesscard to be printed.
This is part of my code:
public void write() throws DocumentException, FileNotFoundException, IOException {
String extension = ".pdf";
String file = "testerPDF";
String filename = file + extension;
Document doku = new Document(PageSize.A4, 10,20,50,150);
PdfWriter writer = PdfWriter.getInstance(doku, new FileOutputStream(new File(filename)));
doku.open();
Phrase textblock = new Phrase();
// jetzt durch den Vector iterarieren
for(int i = 0; i < vector.size(); i++) {
Chunk chunk=new Chunk((String)vector.get(i));
textblock.add(chunk);
}
doku.add(new Paragraph(textblock));
doku.close();
writer.close();
}
So I need now a way to also write a Back Page for this created PDF. In such a way that the document would look like a Business card on Paper.