| PDFsharp & MigraDoc Forum https://forum.pdfsharp.net/ |
|
| StackOverflow exception when RenderDocument() https://forum.pdfsharp.net/viewtopic.php?f=2&t=2021 |
Page 1 of 1 |
| Author: | Ale_lipa [ Wed May 16, 2012 5:45 pm ] |
| Post subject: | StackOverflow exception when RenderDocument() |
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. |
|
| Author: | () => true [ Thu May 17, 2012 5:07 pm ] |
| Post subject: | Re: StackOverflow exception when RenderDocument() |
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). |
|
| Author: | dheijl [ Fri May 18, 2012 7:15 am ] |
| Post subject: | Re: StackOverflow exception when RenderDocument() |
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 |
|
| Author: | Ale_lipa [ Sun May 20, 2012 2:32 pm ] |
| Post subject: | Re: StackOverflow exception when RenderDocument() |
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 |
|
| Author: | rwg [ Tue Jan 22, 2013 3:49 pm ] |
| Post subject: | Re: StackOverflow exception when RenderDocument() |
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 |
|
| Page 1 of 1 | All times are UTC |
| Powered by phpBB® Forum Software © phpBB Group https://www.phpbb.com/ |
|