2
votes

I generate a PDF file using iTextSharp in ASP.NET C#.

I try to generate a heading + table for several element. After every element I want to start a new page. I do this with doc.NewPage() but when I generate my PDF file I get the following error when opening the file:

Error loading the PDF document

I get this error when I try to open the PDF file in the latest version of Google Chrome. When I try to open the file in the Adobe Reader I get the following error message:

There was an error opening this document. The file is damaged and could not be repaired.

The size of the PDF file is also only 1kb...

Here is the code how I generate the file:

//Create a byte array that will eventually hold our final PDF
//must be outside of the foreach loop (and everything else), because we store every single generated table in here for the final pdf!!
Byte[] bytes;

List<TableObject> myTables = getTables();
TableObject currentTable = new TableObject();

//Boilerplate iTextSharp setup here
//Create a stream that we can write to, in this case a MemoryStream
using (MemoryStream ms = new MemoryStream())
{
    //Create an iTextSharp Document which is an abstraction of a PDF but **NOT** a PDF
    using (Document doc = new Document(PageSize.A4, 10f, 10f, 10f, 0f))
    {
        //Create a writer that's bound to our PDF abstraction and our stream
        PdfWriter writer = PdfWriter.GetInstance(doc, ms);

        //Open the document for writing
        doc.Open();

        //writer.CloseStream = false;
        //loop all tableobjects inside the document & the instance of PDFWriter itself! 
        foreach (TableObject to in myTables.ToList())
        {
            //Get the data from database corresponding to the current tableobject and fill all the stuff we need!
            DataTable dt = getDTFromID(to._tableID);
            Object[] genObjects = new Object[5];
            genObjects = gen.generateTable(dt, currentTable._tableName, currentTable._tableID.ToString(), currentTable, true);

            StringBuilder sb = (StringBuilder)genObjects[1];
            String tableName = sb.ToString();
            Table myGenTable = (Table)genObjects[0];
            //String table contains a valid html string, which works in the generate function for a single page document
            String table = genObjects[2].ToString();

            using (StringReader srHtml = new StringReader(table))
            {
                //Parse the HTML
                iTextSharp.tool.xml.XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, srHtml);
            }

            //this will probably render a whole new page at the end of the file!! need to be fixed later!!!
            //doc.NewPage();
        }

        //After all of the PDF "stuff" above is done and closed but **before** we
        //close the MemoryStream, grab all of the active bytes from the stream
        bytes = ms.ToArray();

        doc.Close();
    } 
}

//Now we just need to do something with those bytes.
Response.ContentType = "application/pdf";
Response.AppendHeader("Content-Disposition", "attachment; filename=ShiftReport_complete.pdf");
Response.BinaryWrite(bytes);

How can I solve this problem so that I get rid of the error message when opening the PDF file?

1
I tried it with Google Chrome v 47.0.2526.106 but also with Adobe Reader. Adobe Reader gives the following error message: There was an error opening this document. The file is damaged and could not be repaired. - Hack4Life
can you have a look at this link and give it a try. thenubbyadmin.com/2012/04/13/… - hud
@coder I think that the problem is in the generating method because the saved file only has a few bytes.. (it has only 15 bytes). - Hack4Life
if you think, that may be the issue then give it a try and check. you will get to know by yourself - hud
I use the exact same code without the foreach loop when generating only one table into a pdf file and it works fine, thats confusing. Is it possible that myTables.ToList() causes the problem? - Hack4Life

1 Answers

6
votes

Your code finishes creating the PDF like this:

    bytes = ms.ToArray();

    doc.Close();

This is the wrong order! During doc.Close() pending PDF objects and the PDF trailer are written. As you grab the byte[] before that, your result PDF is missing these pieces.

Simply do it the other way around:

    doc.Close();
    bytes = ms.ToArray();