2

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?

Hack4Life
  • 563
  • 1
  • 11
  • 34
  • 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 Jan 05 '16 at 09:43
  • can you have a look at this link and give it a try. http://thenubbyadmin.com/2012/04/13/solving-the-error-the-file-is-damaged-and-could-not-be-repaired-when-opening-a-pdf-in-internet-explorer/ – Nad Jan 05 '16 at 09:46
  • @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 Jan 05 '16 at 09:52
  • if you think, that may be the issue then give it a try and check. you will get to know by yourself – Nad Jan 05 '16 at 09:56
  • 1
    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 Jan 05 '16 at 09:59
  • see basically.. u use `foreach` loop when there are more than one rows. So you don't need your `object.tolist()` for one row. may be that might be causing the issue. But i am not sure as I don't know the structure of your code and logic. – Nad Jan 05 '16 at 10:02
  • Yeah, I have 6 elements that are in the PDF file so I use the foreach loop to put every single element into the file. Without `.ToList()` I get this error message: `Collection was modified; enumeration operation may not execute.` – Hack4Life Jan 05 '16 at 10:13
  • oh ok. So did you got the point where you were mistaking and got the solution.right ? – Nad Jan 05 '16 at 10:14
  • I got the solution to figure out how I get the foreach loop working but not why the PDF file only has 15 bytes – Hack4Life Jan 05 '16 at 10:26

1 Answers1

6

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();
mkl
  • 90,588
  • 15
  • 125
  • 265
  • What a stupid mistake... thanks for this tip. It works now perfectly! Do you know how I can rotate every page for its own? e.g. page 1: Portrait, page 2: landscape – Hack4Life Jan 05 '16 at 11:43
  • *Do you know how I can rotate every page for its own?* - This is a new question and, therefore, should be asked as a separate stackoverflow question. A quick hint, though: Use `doc.SetPageSize(...)` before the new page is started by `doc.NewPage()` or otherwise. – mkl Jan 05 '16 at 11:49