PDFsharp & MigraDoc Forum

PDFsharp - A .NET library for processing PDF & MigraDoc - Creating documents on the fly
It is currently Wed Nov 05, 2025 5:02 am

All times are UTC


Forum rules


Please read this before posting on this forum: Forum Rules

Also see our new Tailored Support & Services site.



Post new topic Reply to topic  [ 5 posts ] 
Author Message
PostPosted: Wed May 16, 2012 5:45 pm 
Offline

Joined: Wed May 16, 2012 5:02 pm
Posts: 2
Hello,
as you can probably guess i'm using MigraDoc to render some pdf's. Basicly i'm trying to render some (~300 - 500) reports that contains couple of tables each. Every table can have from 1 to let's say 5 rows (in avarage), besides tables there is of course some text.

My problem is that when i'm trying to render over 100 reports in one pdf document the stack overflow exception occures. I tried to find some reletive thread but I've ended up with finding only this one click. There is not answer but I assume that someone struggled with similar problem.

Ok, let's get to the point. The exception is thrown when method RenderDocument() is called. Last line in the snipped of code

Code:
Document document = CreateDocument(caseRepository.GetCasesReportInfo(clientId, caseStages));
document.UseCmykColor = true;

PdfDocumentRenderer renderer = new PdfDocumentRenderer(true, PdfSharp.Pdf.PdfFontEmbedding.Always);
renderer.Document = document;
renderer.RenderDocument();


It is thrown in random places, but mainly when enumerating something corelated with tables. Last time it stopped at this point (line 447 in PdfReferenceTable.cs)

Code:
if (pdfObject is PdfDictionary)


I don't know if it will help someone with judgment about my issue but anyway i will enclose this information. The call stack is full of this kind of entries.

Code:
PdfSharp.DLL!PdfSharp.Pdf.PdfReferenceTable.TransitiveClosureImplementation(System.Collections.Generic.Dictionary<PdfSharp.Pdf.PdfItem,object> objects = Count = Cannot evaluate expression because the current thread is in a stack overflow state., PdfSharp.Pdf.PdfObject pdfObject = (pairs=Cannot evaluate expression because the current thread is in a stack overflow state.), ref int depth = 29217) Line 502 + 0x11 bytes   C#


Document is created pretty much like this

Code:
Document document = new Document();
            document.Info.Title = string.Format("Raport sprawy");
            document.Info.Author = "System zarządzania sprawami kancelarii Rhetor";

            Section section = document.AddSection();

            section.PageSetup.OddAndEvenPagesHeaderFooter = true;
            section.PageSetup.StartingNumber = 1;

            HeaderFooter header = section.Headers.Primary;
            header.AddParagraph(string.Format("{0}: {1}", "Data wygenerowania raportu",
                                                          DateTime.Now.ToString("dd-MM-yyyy")));

            // Create a paragraph with centered page number. See definition of style "Footer".
            Paragraph paragraph = new Paragraph();
            paragraph.AddTab();
            paragraph.AddPageField();

            // Add paragraph to footer for odd pages.
            section.Footers.Primary.Add(paragraph);
            // Add clone of paragraph to footer for odd pages. Cloning is necessary because an object must
            // not belong to more than one other object. If you forget cloning an exception is thrown.
            section.Footers.EvenPage.Add(paragraph.Clone());
           
            foreach (CasesReportGeneral cr in casesReports.general)
            {
                section.AddPageBreak();

                // Name & Lastname
                paragraph = section.AddParagraph(string.Format("Imię i nazwisko: {0} {1}", cr.debtorName,
                                                                                           cr.debtorLastname));
                paragraph.Format.Font.Size = 12;
                paragraph.Format.Font.Bold = false;
                paragraph.Format.SpaceAfter = 15;
                paragraph.Format.OutlineLevel = OutlineLevel.Level1;

                // Company
                paragraph = section.AddParagraph(string.Format("Nazwa firma: {0}", cr.debtorCompanyName));
                paragraph.Format.Font.Size = 12;
                paragraph.Format.Font.Bold = false;
                paragraph.Format.SpaceAfter = 15;
                paragraph.Format.OutlineLevel = OutlineLevel.Level1;
               
                // SAP
                paragraph = section.AddParagraph(string.Format("SAP: {0}", cr.debtorSap));
                paragraph.Format.Font.Size = 12;
                paragraph.Format.Font.Bold = false;
                paragraph.Format.SpaceAfter = 15;
                paragraph.Format.OutlineLevel = OutlineLevel.Level1;

                // Stage
                paragraph.AddTab();
                paragraph.AddTab();
                paragraph.AddText(string.Format("Etap: {0}", cr.caseStage.GetDescriptionAttributeValue()));

                // There are some comments in this type of proceeding
                if (cr.casesComments.Any(cc => cc.type == CommentTypes.Friendly) && ProceedingIsOk(cr, CommentTypes.Friendly))
                {
                    paragraph = section.AddParagraph(CommentTypes.Friendly.GetDescriptionAttributeValue(), "Heading1");

                    Table table = CreateCommentTable(cr.casesComments.Where(c => c.type == CommentTypes.Friendly).ToArray());
                    document.LastSection.Add(table);
                    document.LastSection.AddParagraph();
                }

            }

        // Many times looped
        private Table CreateCommentTable(CasesReportComments[] comments)
        {
            Table table = new Table();
            Column column = new Column();

            table.Borders.Width = 0.75;

            column = table.AddColumn(Unit.FromCentimeter(1)); // Lp
            column.Format.Alignment = ParagraphAlignment.Center;

            column = table.AddColumn(Unit.FromCentimeter(10)); // Content
            column.Format.Alignment = ParagraphAlignment.Center;

            column = table.AddColumn(Unit.FromCentimeter(5)); // Date
            column.Format.Alignment = ParagraphAlignment.Center;

            Row row = table.AddRow();

            Cell cell = row.Cells[0];
            cell.AddParagraph("Lp.");

            cell = row.Cells[1];
            cell.AddParagraph("Komentarz");

            cell = row.Cells[2];
            cell.AddParagraph("Data");

            int lp = 1;
            bool addRow = true;
            foreach (CasesReportComments crc in comments)
            {
                //if (isClient)
                //    if (!crm.hidden)
                //        addRow = false;
                if (addRow)
                {
                    row = table.AddRow();
                    row.Shading.Color = Colors.PaleGoldenrod;

                    cell = row.Cells[0];
                    cell.AddParagraph(lp.ToString());

                    cell = row.Cells[1];
                    cell.AddParagraph(crc.content);

                    cell = row.Cells[2];
                    cell.AddParagraph(crc.date.ToString("dd-MM-yyyy"));

                    lp++;
                }
            }
            return table;
        }


I'll provide any other info if you need one. Thanks in advance for any help.


Top
 Profile  
Reply with quote  
PostPosted: Thu May 17, 2012 5:07 pm 
Offline
PDFsharp Expert
User avatar

Joined: Wed Dec 09, 2009 8:59 am
Posts: 355
Hi!

Did I get this correctly: you create a single MigraDoc document with 500+ pages and 500+ tables?
Should work (theoretically).

You could change your code to reduce memory usage using the technique shown for page 2 of this sample:
http://www.pdfsharp.net/wiki/MixMigraDo ... ample.ashx

What I mean: create a MigraDoc document for a single report (e.g. 2 pages), then add those two pages two a PDF file created with PDFsharp and then dispose the MigraDoc document and create the next one for the next report and also add those pages.

Otherwise you can switch between GDI+ build and WPF build (this could make a difference).
If you're using a 32-bit application, you could try a 64-bit version for a test (if you have a 64-bit computer with more than 4 GB for the test).

_________________
Öhmesh Volta ("() => true")
PDFsharp Team Holiday Substitute


Top
 Profile  
Reply with quote  
PostPosted: Fri May 18, 2012 7:15 am 
Offline

Joined: Fri Apr 13, 2012 6:33 am
Posts: 10
I don't know if you will be able to fix it without changing the PdfSharp source code.

I think the offending code is called from PDfDocument.PrepareForSave(), that calls PdfReferenceTable.Compact() that calls PdfReferenceTable.TransitiveClosure() that walks the reference table using recursion.

So if your reference table gets too large you will hit a stack overflow.

The best solution would be to replace the recursive code with a non-recursive implementation, it would be faster too. This part of the PdfSharp code seems to be somewhat experimental...

A quick fix could be to suppress the compact() call in PrepareForSave() by changing "#if true" to "#if false" and hope for the best:

around line 391:

Code:
#if true  // replace by #if false ???
      // Remove all unreachable objects (e.g. from deleted pages)
      int removed = this.irefTable.Compact();
      if (removed != 0)
        Debug.WriteLine("PrepareForSave: Number of deleted unreachable objects: " + removed);
      this.irefTable.Renumber();
#endif


Top
 Profile  
Reply with quote  
PostPosted: Sun May 20, 2012 2:32 pm 
Offline

Joined: Wed May 16, 2012 5:02 pm
Posts: 2
First of all, I want to say thank you to both of you guys.

Secondly I would like to apologies for my stupidity, cause I didn't check correctly where precisly exception occures. It turns out (when I was fighting today with this problem) that it doesn't shows when RenderDocument() is called but when Save() on the rendered document is performed. Snipped of code

Code:
PdfDocumentRenderer renderer = new PdfDocumentRenderer(true, PdfSharp.Pdf.PdfFontEmbedding.Always);
            renderer.Document = document;
            renderer.RenderDocument();

            using (MemoryStream ms = new MemoryStream())
            {
                renderer.PdfDocument.Save(ms, false); <-- HERE IT FAILS
                byte[] buffer = new byte[ms.Length];
                ms.Seek(0, SeekOrigin.Begin);
                ms.Flush();
                ms.Read(buffer, 0, (int)ms.Length);

                Response.Clear();
                Response.AddHeader("Content-disposition", "attachment; filename=" + string.Format("Raport z dnia {0}.pdf", DateTime.Now.ToString("dd-MM-yyyy")));
                Response.ContentType = "application/octet-stream";
                Response.BinaryWrite(ms.ToArray());
                Response.End();
            }


I was able to track this exception as deep as I could in the PdfSharp library and I've reached some recursive code that is the cause (I can tell because some breakpoints that I've putted were never reached).

Code:
void TransitiveClosureImplementation(Dictionary<PdfItem, object> objects, PdfObject pdfObject, ref int depth)
    {
      if (depth-- == 0)
        return;
      try
      {
        nestingLevel++;
        if (nestingLevel >= 1000)
        {
          //Debug.WriteLine(String.Format("Nestinglevel={0}", nestingLevel));
          //GetType();
          if (!this.overflow.ContainsKey(pdfObject))
            this.overflow.Add(pdfObject, null);
          return;
        }
#if DEBUG_
        //enterCount++;
        if (enterCount == 5400)
          GetType();
        //if (!Object.ReferenceEquals(pdfObject.Owner, this.document))
        //  GetType();
        //////Debug.Assert(Object.ReferenceEquals(pdfObject27.Document, this.document));
        //      if (item is PdfObject && ((PdfObject)item).ObjectID.ObjectNumber == 5)
        //        Debug.WriteLine("items: " + ((PdfObject)item).ObjectID.ToString());
        //if (pdfObject.ObjectNumber == 5)
        //  GetType();
#endif

        IEnumerable enumerable = null; //(IEnumerator)pdfObject;
        if (pdfObject is PdfDictionary)
          enumerable = ((PdfDictionary)pdfObject).Elements.Values;
        else if (pdfObject is PdfArray)
          enumerable = ((PdfArray)pdfObject).Elements;
        if (enumerable != null)
        {
          foreach (PdfItem item in enumerable)
          {
            PdfReference iref = item as PdfReference;
            if (iref != null)
            {
              // Is this an indirect reference to an object that not exists?
              //if (iref.Document == null)
              //{
              //  Debug.WriteLine("Dead object dedected: " + iref.ObjectID.ToString());
              //  PdfReference dead = DeadObject;
              //  iref.ObjectID = dead.ObjectID;
              //  iref.Document = this.document;
              //  iref.SetObject(dead.Value);
              //  PdfDictionary dict = (PdfDictionary)dead.Value;
              //
              //  dict.Elements["/DeadObjectCount"] =
              //    new PdfInteger(dict.Elements.GetInteger("/DeadObjectCount") + 1);
              //
              //  iref = dead;
              //}

              if (!Object.ReferenceEquals(iref.Document, this.document))
              {
                GetType();
                Debug.WriteLine(String.Format("Bad iref: {0}", iref.ObjectID.ToString()));
              }
              Debug.Assert(Object.ReferenceEquals(iref.Document, this.document) || iref.Document == null, "External object detected!");
#if DEBUG
              if (iref.ObjectID.ObjectNumber == 23)
                GetType();
#endif
              if (!objects.ContainsKey(iref))
              {
                PdfObject value = iref.Value;

                // Ignore unreachable objets
                if (iref.Document != null)
                {
                  // ... from trailer hack
                  if (value == null)
                  {
                    iref = this.objectTable[iref.ObjectID];
                    Debug.Assert(iref.Value != null);
                    value = iref.Value;
                  }
                  Debug.Assert(Object.ReferenceEquals(iref.Document, this.document));
                  objects.Add(iref, null);
                  //Debug.WriteLine(String.Format("objects.Add('{0}', null);", iref.ObjectID.ToString()));
                  if (value is PdfArray || value is PdfDictionary)
                    TransitiveClosureImplementation(objects, value, ref depth);  <-- RECURSIVE
                }
                //else
                //{
                //  objects2.Add(this[iref.ObjectID], null);
                //}
              }
            }
            else
            {
              PdfObject pdfObject28 = item as PdfObject;
              //if (pdfObject28 != null)
              //  Debug.Assert(Object.ReferenceEquals(pdfObject28.Document, this.document));
              if (pdfObject28 != null && (pdfObject28 is PdfDictionary || pdfObject28 is PdfArray))
                TransitiveClosureImplementation(objects, pdfObject28, ref depth); <-- RECURSIVE
            }
          }
        }
      }
      finally
      {
        nestingLevel--;
      }
    }


I've followed dheijl advice and..IT WORKED! THANK YOU! I've changed like you said true to false and now it's working lika a charm. No recursion, no problem :). Thank you once again.


Top
 Profile  
Reply with quote  
PostPosted: Tue Jan 22, 2013 3:49 pm 
Offline

Joined: Tue Jan 22, 2013 3:40 pm
Posts: 1
I wanted to state that dheijl solution resolved my problem also.

My code generate a 1000+ page PDF file and got the stack overflow error on the PdfDocument.Save() command.

Call Stack showed hundreds of these
PdfSharp.dll!PdfSharp.Pdf.PdfReferenceTable.TransitiveClosureImplementation(System.Collections.Generic.Dictionary<PdfSharp.Pdf.PdfItem,object> objects, PdfSharp.Pdf.PdfObject pdfObject, ref int depth) Line 502 + 0x11 bytes C#


Changing PdfDocument.cs as dheijl resolved the problem.

-rwg


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 5 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 180 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Privacy Policy, Data Protection Declaration, Impressum
Powered by phpBB® Forum Software © phpBB Group