how to generate a large pdf report using itextsharp c# library - c#

How to generate a large PDF report using itextsharp C#? Say for e.g. i wanted to create a PDF file which contains around 5000+ pages? Without Memory exception?
Document pdfDoc = new Document(PageSize.A3.Rotate(), 0, 0, 10, 10);
FileStream stream = new FileStream(fileName, FileMode.Create);
var writer = PdfWriter.GetInstance(pdfDoc, stream);
pdfDoc.Open();
iTextSharp.text.pdf.ByteBuffer.HIGH_PRECISION = true;
PdfPTable PdfTable = new PdfPTable(1);
PdfTable.SpacingBefore = 30f;
if (headerContent != null)
{
foreach (PDFHeaderItem item in headerContent.items)
{
PdfTable.AddCell(CreateTitlePDFCell(Lang, item.ItemHeader, fontHeaderFontAR, headerContent));
PdfTable.SpacingBefore = 10f;
}
}
//Columns headerCellFormats
for (int i = 0; i < 500000000 ; i++)
{
PdfTable.AddCell(CreatePDFCell("TEXT", cell.KeyName, yourFont, cellFormats));
}
PdfTable.Complete = true;
pdfDoc.Add(PdfTable);
pdfDoc.Close();

We can have the pdf table added to pdf document for every x no of records so that it free up the system memory, please refer the below code
for (int i = 0; i < 500000; i++)
{
PdfTable.AddCell(CreatePDFCell("TEXT", cell.KeyName, yourFont, cellFormats));
if (i > 0 && i % 5000 == 0)
{
pdfDoc.Add(PdfTable);
}
}

Related

Merge pdf files page size

I merge pdf files using itext7 PdfMerger,
but page size is copied from the source file. - so each page has different size - according to the original size.
I would like the page size to be equal across the merged output file. (i.e. A4 rotate)
using(var ms = new MemoryStream()) {
var pdfCombined = new PdfDocument(new PdfWriter(ms));
var merger = new PdfMerger(pdfCombined);
using(var pdfStream = file.OpenReadStream()) {
var pdfReader = new PdfDocument(new PdfReader(pdfStream));
merger.Merge(pdfReader, 1, pdfReader.GetNumberOfPages());
pdfReader.Close();
}
}
private void Resize(Stream original, Stream stream)
{
original.Position = 0;
stream.Position = 0;
var orig = new PdfDocument(new PdfReader(original));
var pdf = new PdfDocument(new PdfWriter(stream));
pdf.GetWriter().SetCloseStream(false);
var doc = new Document(pdf, PageSize);
var pageSize = orig.GetPage(1).GetPageSizeWithRotation();
var pageWidth = pageSize.GetWidth();
var destWidth = PageSize.GetWidth();
if (pageWidth > destWidth)
{
var transformationMatrix = AffineTransform.GetScaleInstance(
pageWidth / destWidth / 2,
pageSize.GetHeight() / PageSize.GetHeight() / 2);
for (int i = 1; i <= orig.GetNumberOfPages(); i++)
{
var page = orig.GetPage(i);
var formXObject = page.CopyAsFormXObject(pdf);
var canvas = new PdfCanvas(pdf.AddNewPage(PageSize));
canvas.ConcatMatrix(transformationMatrix);
canvas.AddXObjectAt(formXObject, 0, 0);
}
doc.Close();
}
}

Set layer for markup (FreeText) PDF using itext7 .NET

How to set layer for the existing markup (FreeText) PDF using itext7 .NET? I use the code below but it does not work. Please help. Thanks.
public void SetLayerMarkup()
{
string inPDF = #"C:\in PDF.pdf";
string outPDF = #"C:\out PDF.pdf";
PdfDocument pdfDoc = new PdfDocument(new PdfReader(inPDF), new PdfWriter(outPDF));
PdfLayer notPrint = new PdfLayer("Non Print", pdfDoc);
int numberOfPages = pdfDoc.GetNumberOfPages();
for (int i = 1; i <= numberOfPages; i++)
{
PdfDictionary page = pdfDoc.GetPage(i).GetPdfObject();
PdfArray annotArray = page.GetAsArray(PdfName.Annots);
if (annotArray == null)
{
continue;
}
int size = annotArray.Size();
for (int x = 0; x < size; x++)
{
PdfDictionary curAnnot = annotArray.GetAsDictionary(x);
if (curAnnot.GetAsString(PdfName.Contents) != null)
{
string contents = curAnnot.GetAsString(PdfName.Contents).ToString();
if (contents != "" && contents.Contains("old content")) //set layer for a FreeText with this content
{
PdfDictionary layer = new PdfDictionary();
layer.Put(PdfName.Type, PdfName.OCG);
layer.Put(PdfName.Name, new PdfString("Non Print"));
curAnnot.Put(PdfName.OC, layer);
}
}
}
}
pdfDoc.Close();
}
Or how to fix the code above to match this image (in iText RUPS 5.5.9)?:
Attached source PDF file: here
So your original document does not have any layers:
First off, we need to create one with the helper API:
PdfLayer layer = new PdfLayer("Non Print", pdfDocument);
The code can now be made a bit simpler (my sample is in Java but conversion to C# should be very straighforward):
PdfDocument pdfDocument = new PdfDocument(new PdfReader("in PDF.pdf"),
new PdfWriter("out PDF.pdf"));
PdfLayer layer = new PdfLayer("Non Print", pdfDocument);
int numberOfPages = pdfDocument.getNumberOfPages();
for (int i = 1; i <= numberOfPages; i++) {
PdfDictionary page = pdfDocument.getPage(i).getPdfObject();
PdfArray annotArray = page.getAsArray(PdfName.Annots);
if (annotArray == null) {
continue;
}
int size = annotArray.size();
for (int x = 0; x < size; x++) {
PdfDictionary curAnnot = annotArray.getAsDictionary(x);
if (curAnnot.getAsString(PdfName.Contents) != null) {
String contents = curAnnot.getAsString(PdfName.Contents).toString();
if (!contents.isEmpty() && contents.contains("old content")) //set layer for a FreeText with this content
{
curAnnot.put(PdfName.OC, layer.getPdfObject());
}
}
}
}
pdfDocument.close();
As a result, you get a document with a layer:
If you click on the eye icon next to the layer name, the content of the layer becomes hidden:
Based on your code, I changed my code as below and it works well, thank you.
PdfDictionary layer = new PdfDictionary();
layer.Put(PdfName.Type, PdfName.OCG);
layer.Put(PdfName.Name, new PdfString("Non Print"));
curAnnot.Put(PdfName.OC, layer);
to:
curAnnot.Put(PdfName.OC, notPrint.GetPdfObject());

How to concatenate two byte arrays

i use this method to merge existing pdf documents and add new pdf documents to it (in memory not physical)
the problem i have 2 memory stream one for merged pdf and one to the new document then convert it to byte array, i want to concat these tow arrays
public static byte[] merge(List<String> pdf)
{
MemoryStream copystream;
MemoryStream ms;
using (ms = new MemoryStream())
{
Document document;
using (document = new Document())
{
using (PdfWriter wri = PdfWriter.GetInstance(document, ms))
{
wri.CloseStream = false;
document.Open();
document.SetPageSize(iTextSharp.text.PageSize.A4); // for vertical layout
document.Add(new Paragraph("Hello"));
document.Close();
copystream = new MemoryStream();
Document doc = new Document();
using (PdfCopy copy = new PdfCopy(doc, copystream))
{
copy.CloseStream = false;
copy.Open();
doc.Open();
// copy.AddPage(PageSize.A4, 0);
for (int i = 0; i < pdf.Count; ++i)
{
PdfReader reader = new PdfReader(pdf[i]);
// loop over the pages in that document
int n = reader.NumberOfPages;
for (int page = 0; page < n;)
{
copy.AddPage(copy.GetImportedPage(reader, ++page));
}
}
copy.Close();
copystream.CopyToAsync(ms);
copystream.Close();
}
}
}
byte[] mergedPdf2 = copystream.ToArray();
byte[] mergedPdf3 = ms.ToArray();
byte[] result = new byte[mergedPdf2.Length + mergedPdf3.Length];
mergedPdf2.CopyTo(result, 0);
mergedPdf3.CopyTo(result, mergedPdf2.Length);
return result;
}
}
There's a LINQ method, in byte[], that allows concatenation.
a.Concat(b).ToArray();
You have to add using System.Linq;first. If you don't want to do that you can create a method, somthing like:
static byte[] Concat(byte[] a, byte[] b)
{
byte[] output = new byte[a.Length + b.Length];
for (int i = 0; i < a.Length; i++)
output[i] = a[i];
for (int j = 0; j < b.Length; j++)
output[a.Length+j] = b[j];
return output;
}

how to use a streamreader with button.Image

Edit: the map[][] is filled with buttons
The main issue is that an .image seems not to be able to save .
i want to make a load that when i load it in every map[i][j] regains its previous state. everything seems to work exept for the .image
FileStream file = new FileStream(#""+AppDomain.CurrentDomain.BaseDirectory+ "\\objects\\savegame"+spacing+".sav", FileMode.Create, FileAccess.ReadWrite);
StreamWriter sw = new StreamWriter(file);
for (Int32 i = 0; i <columns; i++)
{
for (Int32 j = 0; j < columns; j++)
{
sw.WriteLine(map[i][j].Enabled);
sw.WriteLine(map[i][j].Enabled);
sw.WriteLine(map[i][j].Image);
sw.WriteLine(map[i][j].Tag);
sw.WriteLine(map[i][j].Text);
sw.WriteLine(map[i][j].Name);
sw.WriteLine( map[i][j].Height);
sw.WriteLine(map[i][j].Width);
}
}
FileStream file = new FileStream(#"" + AppDomain.CurrentDomain.BaseDirectory + "\\objects\\savegame" + spacing + ".sav", FileMode.Create, FileAccess.ReadWrite);
StreamReader sr = new StreamReader(file);
for (Int32 i = 0; i < columns; i++)
{
for (Int32 j = 0; j < columns; j++)
{
map[i][j].Enabled = Convert.ToBoolean(sr.ReadLine());
map[i][j].Image = Convert.ToString(sr.ReadLine());// this is the problem
map[i][j].Tag = Convert.ToString(sr.ReadLine());
map[i][j].Text = Convert.ToString(sr.ReadLine());
map[i][j].Name = Convert.ToString(sr.ReadLine());
map[i][j].Height = Convert.ToInt32(sr.ReadLine());
map[i][j].Width = Convert.ToInt32(sr.ReadLine());
}
}
sr.Close();
}
//Sample location for the image --->map[i][j].Image = Image.FromFile(AppDomain.CurrentDomain.BaseDirectory + "objects\\map\\mapgrass" + spacing + ".png");
I don't understand much your question, but I can see one error: Please don't forget to Close your stream after writing, and put your code into using block.
using(StreamWriter sw = new StreamWriter(file))
{
for (Int32 i = 0; i <columns; i++)
{
.....
}
sw.Close();
}
Update:
If you use WriteLine(map[i][j].Image), the system actually calls WriteLine(map[i][j].Image.ToString()) which returns name of the Image class. If you want to save any useful information, you must put there map[i][j].Image.something or map[i][j].whatever_useful. Image is a binary object - usually a bitmap picture, you cannot save it to a text file as a whole and load it back from it.

Convert Datatable to PDF

Can I get a code for converting datatable to pdf in Asp.net Web application. I want to have functionality to export datatable into PDF. I found this article but it is using gridview for exporting
Using iTextSharp,you can do it.It can be download from internet and it is free.
Please, find the code below,
public void ExportToPdf(DataTable dt,string strFilePath)
{
Document document = new Document();
PdfWriter writer = PdfWriter.GetInstance(document, new FileStream(strFilePath, FileMode.Create));
document.Open();
iTextSharp.text.Font font5 = iTextSharp.text.FontFactory.GetFont(FontFactory.HELVETICA, 5);
PdfPTable table = new PdfPTable(dt.Columns.Count);
PdfPRow row = null;
float[] widths = new float[dt.Columns.Count];
for (int i = 0; i < dt.Columns.Count; i++)
widths[i] = 4f;
table.SetWidths(widths);
table.WidthPercentage = 100;
int iCol = 0;
string colname = "";
PdfPCell cell = new PdfPCell(new Phrase("Products"));
cell.Colspan = dt.Columns.Count;
foreach (DataColumn c in dt.Columns)
{
table.AddCell(new Phrase(c.ColumnName, font5));
}
foreach (DataRow r in dt.Rows)
{
if (dt.Rows.Count > 0)
{
for (int h = 0; h < dt.Columns.Count; h++)
{
table.AddCell(new Phrase(r[h].ToString(), font5));
}
}
}
document.Add(table);
document.Close();
}
You can't "convert" a DataTable to a PDF Document. But you can insert data into it as normal content.
This would have to be done through a data control, like the GridView or ListView; just like in a normal webpage. Which is why the article you have linked to does that. GridView is probably the closest and easiest way to make it aesthetically appear the same as a DataTable. As it will just be stored as a normal table in the PDF Document.
Note that the GridView is created in memory - you don't create or need to have one in your HTML page. Try and experiment with the code to understand this better.
So I recommend following the article.

Categories