I'm creating a PDF using ITextSharp which is composed of a single PdfTable. Unfortunately for a particular data set, I'm getting an Out of memory Exception due to the large number PdfPCells that are created (I've profiled the memory usage - I've got nearly 1/2 a million cells !)
Is there any way to reduce the memory usage in such a case?
I've tried flushing at various points (after each row) and full compression
The PdfWriter is based on a FileStream
Code looks a pretty much like this:
Document document = Document();
FileStream stream = new FileStream(fileName,FileMode.Create);
pdfWriter = PdfWriter.GetInstance(document, stream);
document.Open();
PdfPTable table = new PdfPTable(nbColumnToDisplay);
foreach (GridViewRow row in gridView.Rows)
{
j = 0;
for (int i = 0; i < gridView.HeaderRow.Cells.Count; i++)
{
PdfPCell cell = new PdfPCell( new Phrase( text) );
table.AddCell(cell);
}
}
document.Add(table);
document.Close();
iTextSharp has a very cool interface called ILargeElement
that the PdfPTable
implements. According to the documentation:
/**
* Interface implemented by Element objects that can potentially consume
* a lot of memory. Objects implementing the LargeElement interface can
* be added to a Document more than once. If you have invoked setCompleted(false),
* they will be added partially and the content that was added will be
* removed until you've invoked setCompleted(true);
* @since iText 2.0.8
*/
So all you need to do is after you create your PdfPTable
, set the Complete
property to false. In your inner loop do some form of counter that every once in a while adds the table and thus clears the memory. Then at the end of the loop set Complete
to true and add it one more time.
Below is sample code that shows this off. Without the counter check this code uses about 500MB of RAM on my machine. With the counter check every 1,000 items it goes down to 16MB of RAM. You'll need to find your own sweet spot for the counter and that will depend on how much text you're adding to each cell on average.
string fileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "table.pdf");
Document document = new Document();
FileStream stream = new FileStream(fileName, FileMode.Create);
var pdfWriter = PdfWriter.GetInstance(document, stream);
document.Open();
PdfPTable table = new PdfPTable(4);
table.Complete = false;
for (int i = 0; i < 1000000; i++) {
PdfPCell cell = new PdfPCell(new Phrase(i.ToString()));
table.AddCell(cell);
if (i > 0 && i % 1000 == 0) {
Console.WriteLine(i);
document.Add(table);
}
}
table.Complete = true;
document.Add(table);
document.Close();
PdfPTable pdftbale = new PdfPTable(gridview.HeaderRow.Cells.Count);
foreach (TableCell tabhead in gridview.HeaderRow.Cells)
{
PdfPCell pdfcell1 = new PdfPCell(new Phrase(tabhead.Text));
pdftbale.AddCell(pdfcell1);
}
foreach (GridViewRow gd in gridview.Rows)
{
foreach (TableCell tab in gd.Cells)
{
PdfPCell pdfcell = new PdfPCell(new Phrase(tab.Text));
pdftbale.AddCell(pdfcell);
}
}
iTextSharp.text.Document pdfDocument = new iTextSharp.text.Document(PageSize.A4, 10f, 10f, 10f, 10f);
PdfWriter.GetInstance(pdfDocument, new FileStream(Server.MapPath("~/pdf/" + DateTime.Now.ToString("ddMMyyyyhhmmss") + ".pdf"), FileMode.Create));
pdfDocument.Open();
pdfDocument.Add(pdftbale);
pdfDocument.Close();