Concatenating several PDF documents in MemoryStreams


#1

I’m attempting to concatenate several PDF documents that are saved into MemoryStream’s and placed into an array. However, Concatenate only seems to get through about half of the bytes in the MemoryStream’s, which basically corrupts the output memory stream to be used to create a byte array to output to a browser using BinaryWrite. I cannot use FileStreams since I do not want these files written anywhere ever. Here’s the code I have now. I have attempted to take examples from this forum and use them for my purposes.

private void GeneratePDF(string TranIDs)

{

byte[] bytPDF;

System.IO.FileInfo f;

int intTotalBytes = 0;

f = new FileInfo(Server.MapPath("./PDFForms/f8283.pdf"));

if (f.Exists)

{

try

{

MemoryStream[] cs;

MemoryStream os;

PdfFileEditor pdfEditor = new PdfFileEditor();

DataTable dtb = GetData(TranIDs);

ArrayList arrStreams = new ArrayList();

int i = 0;

//Loop through each transaction to create a single PDF document

foreach (DataRow row in dtb.Rows)

{

MemoryStream s = new MemoryStream();

Form docPDF = new Form(f.FullName, s);

docPDF.FillField(“f1-1”, (string)row[“sname”]); //Donor Name

docPDF.FlattenAllFields();

docPDF.Save();

s.Position = 0;

arrStreams.Add(s);

intTotalBytes += (int)s.Length;

i++;

}

cs = new MemoryStream[dtb.Rows.Count];

arrStreams.CopyTo(cs, 0);

os = new MemoryStream();

pdfEditor.Concatenate(cs, os);

os.Position = 0;

bytPDF = new byte[intTotalBytes];

os.Read(bytPDF, 0, intTotalBytes);

os.Close();

//Write file to browser

Response.Clear();

Response.AddHeader(“Content-disposition”, “attachment; filename=” + f.Name);

Response.ContentType = “Application/pdf”;

Response.BinaryWrite(bytPDF);

Response.End();

}

catch (Exception ex)

{

lblErr.Text= ex.Message + “

” + ex.StackTrace + “

”;

}

}

}


#2

Dear msumerano,

Thanks for considering Aspose.Pdf.Kit.

I have read your code carefully and found that the problem may be at the following lines:

bytPDF = new byte[intTotalBytes];
os.Read(bytPDF, 0, intTotalBytes);

Because the “intTotalBytes” is not the length of the “os” stream, but the sum of the length of many pdfs before merged. These two value is not the same generally.

There are three ways to fix this:
1) Change the two lines to:
bytPDF = new byte[os.Length];
os.Read(bytPDF, 0, os.Length);

2)Directly use Response.OutputStream as the merged stream just like this(then the “os” is not useful now.):

pdfEditor.Concatenate(cs, Response.OutputStream);

The new code is simple and has better performance.

3)Directly use the “AutoFiller” class. There is a complete demo in the install directory. And it is very like yours. That is the simplest way to implement your requirements.

Any more questions are welcome.
Best regards.


#3

I actually went the AutoFiller route and this works. However, now I’m struggling with aliasing the column names in the query to match the fields in the form. Of course, these are IRS forms I’m trying to auto fill and their field names are cryptic (i.e. f1-1, f2-2). Should I be aliasing the field names at the query level or at the datatable level?


#4

Dear msumerano,

You only need to set the name of the DataRow as the same as the field name. Just like the example in the demo or this help doc.

Just like the following lines:
DataTable mDataTable = new DataTable("MailMerge");
DataColumnCollection columns = mDataTable.Columns;

columns.Add("CompanyName",typeof(string));
columns.Add("ContactName",typeof(string));
columns.Add("Address",typeof(string));


Best regards.