Getting "An error exists on this page. Acrobat may not display the page correctly." using ITextSharp WriteSelectedRows

StackOverflow https://stackoverflow.com/questions/18335501

Question

I am having an issue using ITextSharp to create some tables and images that push to an MVC browser application. I think I have narrowed it down to being within adding the tables using WriteRowsSelected.

Here is my code:

PDFEngine.cs

  private byte[] BuildDocument(MemoryStream documentStream, IEnumerable<CustomPdfData> documents, bool addVoid, float defaultMagnification)
    {

       using (var stream = new MemoryStream())
        {
        var finishedDocument = new Document(new Rectangle(612f, 792f));

        var writer = PdfWriter.GetInstance(finishedDocument, stream);
        writer.ViewerPreferences = PdfWriter.HideWindowUI;
        writer.ViewerPreferences = PdfWriter.HideMenubar;

        // Open the Document for writing
        finishedDocument.Open();


        var zoomer = PdfAction.GotoLocalPage(1, new PdfDestination(PdfDestination.XYZ, -1, -1, defaultMagnification), writer);

        writer.SetOpenAction(zoomer);



        foreach (var document in documents)
        {


            if (document.IsNewPage)
            {
                finishedDocument.NewPage();
            }

            var results = TableEngine.BuildDocument(document);

            // Build Canvas for Table
            //PdfContentByte canvas = writer.DirectContent;
            //canvas.SetTextMatrix(50, 50);

            // Add each table to the canvas at specified coordinates
            for (int tableCounter = 0; tableCounter < results.ITextTables.Count; tableCounter++)
            {
                PdfContentByte canvas = writer.DirectContent;
                canvas.SetTextMatrix(50, 50);

                var xAxis = results.PdfTables[tableCounter].XPosition;
                var yAxis = results.PdfTables[tableCounter].YPosition;
                results.ITextTables[tableCounter].WriteSelectedRows(0, results.PdfTables[tableCounter].ColumnSize, xAxis, yAxis, writer.DirectContent);
            }




        }

        finishedDocument.Close();
        documentStream.Close();
        return stream.ToArray();
    }

CheckBuilder.cs

  /// <summary>
    /// Used to create the fake checks needed for printing to a client
    /// </summary>
    /// <param name="checks">Checks to push to Builder</param>
    /// <returns></returns>
    public byte[] GetFakeChecks(List<HandsCheck> checks)
    {

        var doc = BuildCheck(checks, true, true);
        return CreatePdf(doc, 0.5f, false);
    }

DisplayChecks.cshtml

 <object id="WebBrowser1"  width="615" height="790"  data= "@Url.Action("GetPdfData")" type="application/pdf" />

HomeController.cs

    public FileContentResult GetPdfData()
    {
        int numberofChecks = int.Parse(Workspace.Get<string>("numberofChecks"));

     var pdfCreator = new CheckBuilder();

            var checks = GetAllChecks();
            var newList = new List<Check>();

            for (int counter = 0; counter < numberofChecks; counter++)
            {
                newList.Add(checks[counter]);
            }

            var rawData = pdfCreator.GetFakeChecks(newList);

            return File(rawData, "application/pdf");


        return null;
    }

The weird thing is that it seems to only happen when I add more than 1 table. Does anyone know if there are any limits per canvas? Does anyone know of any way to further debug what might be causing this issue?

Was it helpful?

Solution

You're introducing a PDF syntax error here:

PdfContentByte canvas = writer.DirectContent;
canvas.SetTextMatrix(50, 50);

With DirectContent, you grab an object that allows you to write PDF syntax directly to the content stream. Immediately after that, you introduce a text state operator. This is illegal PDF syntax:

  1. A text state operator is only valid inside a text object; that is: between BT (BeginText()) and ET (EndText) operators).
  2. Why do you need to set the text matrix? That line doesn't make sense, because you're defining the position of the table in the writeSelectedRows() method.

Long story short: remove canvas.SetTextMatrix(50, 50); and you'll have at least one syntax error less in your PDF.

I just checked the iText codebase, and normally your code should throw an "unbalanced text state" exception. If it doesn't, either the "sanity checks" no longer work, or you're using an obsolete version of iTextSharp.

Update

Comment 1:

ISO-32000-1 defines text state as a subset of graphics state. In graphics state, you can change the line width, stroke color, fill color, the 'current transformation matrix' for all graphical objects, etc... You can draw lines, shapes,... in graphics state, but no text.

Text state is reserved for text: you change the text matrix, define the leading, font,... and you 'show' text. It is illegal to use text state operators outside a BT and ET block; for instance: changing the text matrix in graphics state only doesn't make sense as there is no text outside a BT/ET sequence. It's also illegal to nest BT and ET objects.

Comment 2:

Personally, I use Adobe Acrobat (the Preflight functionality) to check the syntax of a broken PDF. This is the easiest way, but that doesn't mean it's easy. Although I know ISO-32000-1 pretty well, even I don't always understand the error messages.

Sometimes Acrobat can't open a PDF file, the error is 'unknown', or Acrobat is 'unable to analyze the PDF syntax'. See for instance When stamping document - Danish characters disappear and PDF becomes invalid which is a question I answered a couple of days ago. In such a case, I try using iText RUPS and I examine the PDF from the inside. In the worst case, you need to examine the PDF in a plain text editor (for instance because even RUPS can't open the file).

Comment 3:

When you use writeSelectedRows(), iText(Sharp) adds a BT and ET operator automatically. Some versions may omit the BT if a BT was already present; some versions of iTextSharp may add a BT when using setTextMatrix() if a BT was missing.

Long story short: iText(Sharp) sometimes tries to fix problems due to programming errors. These fixes aren't full proof, because iText(Sharp) can't always guess the intentions of a developer. As a result, the fix often fails. Morale: one should make sure not to introduce PDF syntax errors.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top