iTextSharp - Merging a Batch of PDF Byte Arrays - c#

I am using iTextSharp to fill a few fields on a pdf. I need to be able to combine a series of these pdfs into one single batch pdf file. Below I am looping through a SQL result set, filling the fields of the pdf with values corresponding to the current record, storing that as a byte array, and consolidating all of those into a list of byte arrays. I am then attempting to merge each byte array in that list into a single byte array, and serve that as a pdf to the user.
It seems to work, generating a single file containing presumably as many individual pages as were in my result set, but with all the fields blank on each page. It works as expected when using FillForm() to serve a single pdf. What am I doing wrong?
byte[] pdfByteArray = new byte[0];
List<byte[]> pdfByteArrayList = new List<byte[]>();
byte[] pdfByteArrayItem = new byte[0];
foreach (DataRow row in results.Rows)
{
certNum = row[1].ToString();
certName = row[2].ToString();
certDate = row[3].ToString();
pdfByteArrayItem = FillForm(certType, certName, certNum, certDate);
pdfByteArrayList.Add(pdfByteArrayItem);
}
using (var ms = new MemoryStream()) {
using (var doc = new Document()) {
using (var copy = new PdfSmartCopy(doc, ms)) {
doc.Open();
//Loop through each byte array
foreach (var p in pdfByteArrayList) {
//Create a PdfReader bound to that byte array
using (var reader = new PdfReader(p)) {
//Add the entire document instead of page-by-page
copy.AddDocument(reader);
}
}
doc.Close();
}
}
pdfByteArray = ms.ToArray();
context.Response.ContentType = "application/pdf";
context.Response.BinaryWrite(pdfByteArray);
context.Response.Flush();
context.Response.End();
private byte[] FillForm(string certType, string certName, string certNum, string certDate)
{
string pdfTemplate = string.Format(#"\\filePath\{0}.pdf", certType);
PdfReader pdfReader = new PdfReader(pdfTemplate);
MemoryStream stream = new MemoryStream();
PdfStamper pdfStamper = new PdfStamper(pdfReader, stream);
AcroFields pdfFormFields = pdfStamper.AcroFields;
// set form pdfFormFields
pdfFormFields.SetField("CertName", certName);
pdfFormFields.SetField("CertNum", certNum);
pdfFormFields.SetField("CertDate", certDate);
// flatten the form to remove editting options, set it to false
// to leave the form open to subsequent manual edits
pdfStamper.FormFlattening = false;
// close the pdf
pdfStamper.Close();
stream.Flush();
stream.Close();
byte[] pdfByte = stream.ToArray();
return pdfByte;
}

Adding the line below after setting the value for the fields seems to have fixed it:
pdfFormFields.GenerateAppearances = true;

Related

How to save PDF using ITextSharp?

I working with PDF annotations using ITextSharp. I was able to add annotations pretty smoothly.
But now I'm trying to edit them. It looks like my PdfReader object is actually updated. But for some reason I can't save it. As shown in the snippet below, I try to get the byte array from using a stamper. The byte array is only 1 byte longer than the previous version no matter how long is the annotation. And when I open the PDF saved on the file system, I still have the old annotation...
private void UpdatePDFAnnotation(string title, string body)
{
byte[] newBuffer;
using (PdfReader pdfReader = new PdfReader(dataBuffer))
{
int pageIndex = 1;
int annotIndex = 0;
PdfDictionary pageDict = pdfReader.GetPageN(pageIndex);
var annots = pageDict.GetAsArray(PdfName.ANNOTS);
if (annots != null)
{
PdfDictionary annot = annots.GetAsDict(annotIndex);
annot.Put(PdfName.T, new PdfString(title));
annot.Put(PdfName.CONTENTS, new PdfString(body));
}
// ********************************
// this line shows the new annotation is in here. Just have to save it somehow !!
var updatedBody = pdfReader.GetPageN(pageIndex).GetAsArray(PdfName.ANNOTS).GetAsDict(0).GetAsString(PdfName.CONTENTS);
Debug.Assert(newBody == updatedBody.ToString(), "Annotation body should be equal");
using (MemoryStream outStream = new MemoryStream())
{
using (PdfStamper stamp = new PdfStamper(pdfReader, outStream, '\0', true))
{
newBuffer = outStream.ToArray();
}
}
}
File.WriteAllBytes( #"Assets\Documents\AnnotedPdf.pdf", newBuffer);
}
Any idea what's wrong with my code?
PdfStamper does much of the writing at the time it is being closed. This implicitly happens at the end of its using block. But you retrieve the MemoryStream contents already in that block. Thus, the PDF is not yet written to the retrieved byte[].
Instead either explicitly close the PdfStamper instance before retrieving the byte[]:
using (PdfStamper stamp = new PdfStamper(pdfReader, outStream, '\0', true))
{
stamp.Close();
newBuffer = outStream.ToArray();
}
or retrieve the byte[] after that using block:
using (PdfStamper stamp = new PdfStamper(pdfReader, outStream, '\0', true))
{
}
newBuffer = outStream.ToArray();
Allright, I finally got it to work. The trick was the two last parameter in the PdfStamper instantiation. I tried it before with only 2 parameters and ended up with a corrupted file. Then I tried again and now it works... here's the snippet
private void UpdatePDFAnnotation(string title, string body)
{
using (PdfReader pdfReader = new PdfReader(dataBuffer))
{
PdfDictionary pageDict = pdfReader.GetPageN(pageIndex);
var annots = pageDict.GetAsArray(PdfName.ANNOTS);
PdfDictionary annot = annots.GetAsDict(annotIndex);
annot.Put(PdfName.T, new PdfString(title));
annot.Put(PdfName.CONTENTS, new PdfString(body));
using (MemoryStream ms = new MemoryStream())
{
PdfStamper stamp = new PdfStamper(pdfReader, ms);
stamp.Dispose();
dataBuffer = ms.ToArray();
}
}
}

Adding text to existing multipage PDF document in memorystream using iTextSharp

I am trying to add text to an existing PDF file using iTextSharp. I have been reading many posts, including the popular thread here.
I have some differences:
My PDF are X pages long
I want to keep everything in memory, and never have a file stored on my filesystem
So I tried to modify the code, so it takes in a byte array and returns a byte array. I have come this far:
The code compiles and runs
My out byte array has a different length than my in byte array
My problem:
I cannot see my added text when i later store the modified byte array and open it in my PDF reader
I don't get why. From every StackOverflow post I have seen, I do the same. using the DirectContent, I use BeginText and write a text. However, i cannot see it, no matter how I move the position around.
Any idea what is missing from my code?
public static byte[] WriteIdOnPdf(byte[] inPDF, string str)
{
byte[] finalBytes;
// open the reader
using (PdfReader reader = new PdfReader(inPDF))
{
Rectangle size = reader.GetPageSizeWithRotation(1);
using (Document document = new Document(size))
{
// open the writer
using (MemoryStream ms = new MemoryStream())
{
using (PdfWriter writer = PdfWriter.GetInstance(document, ms))
{
document.Open();
for (var i = 1; i <= reader.NumberOfPages; i++)
{
document.NewPage();
var baseFont = BaseFont.CreateFont(BaseFont.HELVETICA_BOLD, BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
var importedPage = writer.GetImportedPage(reader, i);
var contentByte = writer.DirectContent;
contentByte.BeginText();
contentByte.SetFontAndSize(baseFont, 18);
var multiLineString = "Hello,\r\nWorld!";
contentByte.ShowTextAligned(PdfContentByte.ALIGN_LEFT, multiLineString,100, 200, 0);
contentByte.EndText();
contentByte.AddTemplate(importedPage, 0, 0);
}
document.Close();
ms.Close();
writer.Close();
reader.Close();
}
finalBytes = ms.ToArray();
}
}
}
return finalBytes;
}
The code below shows off a full-working example of creating a PDF in memory and then performing a second pass, also in memory. It does what #mkl says and closes all iText parts before trying to grab the raw bytes from the stream. It also uses GetOverContent() to draw "on top" of the previous pdf. See the code comments for more details.
//Bytes will hold our final PDFs
byte[] bytes;
//Create an in-memory PDF
using (var ms = new MemoryStream()) {
using (var doc = new Document()) {
using (var writer = PdfWriter.GetInstance(doc, ms)) {
doc.Open();
//Create a bunch of pages and add text, nothing special here
for (var i = 1; i <= 10; i++) {
doc.NewPage();
doc.Add(new Paragraph(String.Format("First Pass - Page {0}", i)));
}
doc.Close();
}
}
//Right before disposing of the MemoryStream grab all of the bytes
bytes = ms.ToArray();
}
//Another in-memory PDF
using (var ms = new MemoryStream()) {
//Bind a reader to the bytes that we created above
using (var reader = new PdfReader(bytes)) {
//Store our page count
var pageCount = reader.NumberOfPages;
//Bind a stamper to our reader
using (var stamper = new PdfStamper(reader, ms)) {
//Setup a font to use
var baseFont = BaseFont.CreateFont(BaseFont.HELVETICA_BOLD, BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
//Loop through each page
for (var i = 1; i <= pageCount; i++) {
//Get the raw PDF stream "on top" of the existing content
var cb = stamper.GetOverContent(i);
//Draw some text
cb.BeginText();
cb.SetFontAndSize(baseFont, 18);
cb.ShowText(String.Format("Second Pass - Page {0}", i));
cb.EndText();
}
}
}
//Once again, grab the bytes before closing things out
bytes = ms.ToArray();
}
//Just to see the final results I'm writing these bytes to disk but you could do whatever
var testFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "test.pdf");
System.IO.File.WriteAllBytes(testFile, bytes);

How to add multiple fpages to fixed document in xps?

My requirement is to create xps document which has 10 pages (say). I am using the following code to create a xps document. Please take a look.
// Create the new document
XpsDocument xd = new XpsDocument("D:\\9780545325653.xps", FileAccess.ReadWrite);
IXpsFixedDocumentSequenceWriter xdSW = xd.AddFixedDocumentSequence();
IXpsFixedDocumentWriter xdW = xdSW.AddFixedDocument();
IXpsFixedPageWriter xpW = xdW.AddFixedPage();
fontURI = AddFontResourceToFixedPage(xpW, #"D:\arial.ttf");
image = AddJpegImageResourceToFixedPage(xpW, #"D:\Single content\20_1.jpg");
StringBuilder pageContents = new StringBuilder();
pageContents.Append(ReadFile(#"D:\Single content\20.fpage\20.fpage", i));
xmlWriter = xpW.XmlWriter;
xmlWriter.WriteRaw(pageContents.ToString());
}
xmlWriter.Close();
xpW.Commit();
// Commit the fixed document
xdW.Commit();
// Commite the fixed document sequence writer
xdSW.Commit();
// Commit the XPS document itself
xd.Close();
}
private static string AddFontResourceToFixedPage(IXpsFixedPageWriter pageWriter, String fontFileName)
{
string fontUri = "";
using (XpsFont font = pageWriter.AddFont(false))
{
using (Stream dstFontStream = font.GetStream())
using (Stream srcFontStream = File.OpenRead(fontFileName))
{
CopyStream(srcFontStream, dstFontStream);
// commit font resource to the package file
font.Commit();
}
fontUri = font.Uri.ToString();
}
return fontUri;
}
private static Int32 CopyStream(Stream srcStream, Stream dstStream)
{
const int size = 64 * 1024; // copy using 64K buffers
byte[] localBuffer = new byte[size];
int bytesRead;
Int32 bytesMoved = 0;
// reset stream pointers
srcStream.Seek(0, SeekOrigin.Begin);
dstStream.Seek(0, SeekOrigin.Begin);
// stream position is advanced automatically by stream object
while ((bytesRead = srcStream.Read(localBuffer, 0, size)) > 0)
{
dstStream.Write(localBuffer, 0, bytesRead);
bytesMoved += bytesRead;
}
return bytesMoved;
}
private static string ReadFile(string filePath,int i)
{
FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.ReadWrite);
StringBuilder sb = new StringBuilder();
using (StreamReader sr = new StreamReader(fs))
{
String line;
// Read and display lines from the file until the end of
// the file is reached.
while ((line = sr.ReadLine()) != null)
{
sb.AppendLine(line);
}
}
string allines = sb.ToString();
//allines = allines.Replace("FontUri=\"/Resources/f7728e4c-2606-4fcb-b963-d2d3f52b013b.odttf\"", "FontUri=\"" + fontURI + "\" ");
//XmlReader xmlReader = XmlReader.Create(fs, new XmlReaderSettings() { IgnoreComments = true });
XMLSerializer serializer = new XMLSerializer();
FixedPage fp = (FixedPage)serializer.DeSerialize(allines, typeof(FixedPage));
foreach (Glyphs glyph in fp.lstGlyphs)
{
glyph.FontUri = fontURI;
}
fp.Path.PathFill.ImageBrush.ImageSource = image;
fs.Close();
string fpageString = serializer.Serialize(fp);
return fpageString;
}
private static string AddJpegImageResourceToFixedPage(IXpsFixedPageWriter pageWriter, String imgFileName)
{
XpsImage image = pageWriter.AddImage("image/jpeg");
using (Stream dstImageStream = image.GetStream())
using (Stream srcImageStream = File.OpenRead(imgFileName))
{
CopyStream(srcImageStream, dstImageStream); // commit image resource to the package file
//image.Commit();
}
return image.Uri.ToString();
}
If you see it, i would have passed single image and single fpage to create a xps document. I want to pass multiple fpages list and image list to create a xps document which has multiple pages..?
You are doing this in the most excruciatingly difficult manner possible. I'd suggest taking the lazy man's route.
Realize that an XpsDocument is just a wrapper on a FixedDocumentSequence, which contains zero or more FixedDocuments, which contains zero or more FixedPages. All these types can be created, manipulated and combined without writing XML.
All you really need to do is create a FixedPage with whatever content on it you need. Here's an example:
static FixedPage CreateFixedPage(Uri imageSource)
{
FixedPage fp = new FixedPage();
fp.Width = 320;
fp.Height = 240;
Grid g = new Grid();
g.HorizontalAlignment = System.Windows.HorizontalAlignment.Center;
g.VerticalAlignment = System.Windows.VerticalAlignment.Center;
fp.Children.Add(g);
Image img = new Image
{
UriSource = imageSource,
};
g.Children.Add(image);
return fp;
}
This is all WPF. I'm creating a FixedPage that has as its root a Grid, which contains an Image that is loaded from the given Uri. The image will be stretched to fill the available space of the Grid. Or, you could do whatever you want. Create a template as a UserControl, send it text to place within itself, whatever.
Next, you just need to add a bunch of fixed pages to an XpsDocument. It's incredibly hard, so read carefully:
public void WriteAllPages(XpsDocument document, IEnumerable<FixedPage> pages)
{
var writer = XpsDocument.CreateXpsDocumentWriter(document);
foreach(var page in pages)
writer.Write(page);
}
And that's all you need to do. Create your pages, add them to your document. Done.

How to flatten already filled out PDF form using iTextSharp

I'm using iTextSharp to merge a number of pdf files together into a single file.
I'm using method described in iTextSharp official tutorials, specifically here, which merges files page by page via PdfWriter and PdfImportedPage.
Turns out some of the files I need to merge are filled out PDF Forms and using this method of merging form data is lost.
I've see several examples of using PdfStamper to fill out forms and flatten them.
What I can't find, is a way to flatten already filled out PDF Form and hopefully merge it with the other files without saving it flattened out version first.
Thanks
Just setting .FormFlattening on PdfStamper wasn't quite enough...I ended up using a PdfReader with byte array of file contents that i used to stamp/flatten the data to get the byte array of that to put in a new PdfReader. Below is how i did it. works great now.
private void AppendPdfFile(FileDTO file, PdfContentByte cb, iTextSharp.text.Document printDocument, PdfWriter iwriter)
{
var reader = new PdfReader(file.FileContents);
if (reader.AcroForm != null)
reader = new PdfReader(FlattenPdfFormToBytes(reader,file.FileID));
AppendFilePages(reader, printDocument, iwriter, cb);
}
private byte[] FlattenPdfFormToBytes(PdfReader reader, Guid fileID)
{
var memStream = new MemoryStream();
var stamper = new PdfStamper(reader, memStream) {FormFlattening = true};
stamper.Close();
return memStream.ToArray();
}
When creating the files to be merged, I changed this setting:
pdfStamper.FormFlattening = true;
Works Great.
I think this problem is same with this one: AcroForm values missing after flattening
Based on the answer, this should do the trick:
pdfStamper.FormFlattening = true;
pdfStamper.AcroFields.GenerateAppearances = true;
This is the same answer as the accepted one but without any unused variables:
private byte[] GetUnEditablePdf(byte[] fileContents)
{
byte[] newFileContents = null;
var reader = new PdfReader(fileContents);
if (reader.AcroForm != null)
newFileContents = FlattenPdfFormToBytes(reader);
else newFileContents = fileContents;
return newFileContents;
}
private byte[] FlattenPdfFormToBytes(PdfReader reader)
{
var memStream = new MemoryStream();
var stamper = new PdfStamper(reader, memStream) { FormFlattening = true };
stamper.Close();
return memStream.ToArray();
}

Combine two (or more) PDF's

Background: I need to provide a weekly report package for my sales staff. This package contains several (5-10) crystal reports.
Problem:
I would like to allow a user to run all reports and also just run a single report. I was thinking I could do this by creating the reports and then doing:
List<ReportClass> reports = new List<ReportClass>();
reports.Add(new WeeklyReport1());
reports.Add(new WeeklyReport2());
reports.Add(new WeeklyReport3());
<snip>
foreach (ReportClass report in reports)
{
report.ExportToDisk(ExportFormatType.PortableDocFormat, #"c:\reports\" + report.ResourceName + ".pdf");
}
This would provide me a folder full of the reports, but I would like to email everyone a single PDF with all the weekly reports. So I need to combine them.
Is there an easy way to do this without install any more third party controls? I already have DevExpress & CrystalReports and I'd prefer not to add too many more.
Would it be best to combine them in the foreach loop or in a seperate loop? (or an alternate way)
I had to solve a similar problem and what I ended up doing was creating a small pdfmerge utility that uses the PDFSharp project which is essentially MIT licensed.
The code is dead simple, I needed a cmdline utility so I have more code dedicated to parsing the arguments than I do for the PDF merging:
using (PdfDocument one = PdfReader.Open("file1.pdf", PdfDocumentOpenMode.Import))
using (PdfDocument two = PdfReader.Open("file2.pdf", PdfDocumentOpenMode.Import))
using (PdfDocument outPdf = new PdfDocument())
{
CopyPages(one, outPdf);
CopyPages(two, outPdf);
outPdf.Save("file1and2.pdf");
}
void CopyPages(PdfDocument from, PdfDocument to)
{
for (int i = 0; i < from.PageCount; i++)
{
to.AddPage(from.Pages[i]);
}
}
Here is a single function that will merge X amount of PDFs using PDFSharp
using PdfSharp;
using PdfSharp.Pdf;
using PdfSharp.Pdf.IO;
public static void MergePDFs(string targetPath, params string[] pdfs) {
using(var targetDoc = new PdfDocument()){
foreach (var pdf in pdfs) {
using (var pdfDoc = PdfReader.Open(pdf, PdfDocumentOpenMode.Import)) {
for (var i = 0; i < pdfDoc.PageCount; i++)
targetDoc.AddPage(pdfDoc.Pages[i]);
}
}
targetDoc.Save(targetPath);
}
}
This is something that I figured out, and wanted to share with you, using PdfSharp.
Here you can join multiple Pdfs in one, without the need of an output directory (following the input list order)
public static byte[] MergePdf(List<byte[]> pdfs)
{
List<PdfSharp.Pdf.PdfDocument> lstDocuments = new List<PdfSharp.Pdf.PdfDocument>();
foreach (var pdf in pdfs)
{
lstDocuments.Add(PdfReader.Open(new MemoryStream(pdf), PdfDocumentOpenMode.Import));
}
using (PdfSharp.Pdf.PdfDocument outPdf = new PdfSharp.Pdf.PdfDocument())
{
for(int i = 1; i<= lstDocuments.Count; i++)
{
foreach(PdfSharp.Pdf.PdfPage page in lstDocuments[i-1].Pages)
{
outPdf.AddPage(page);
}
}
MemoryStream stream = new MemoryStream();
outPdf.Save(stream, false);
byte[] bytes = stream.ToArray();
return bytes;
}
}
I used iTextsharp with c# to combine pdf files. This is the code I used.
string[] lstFiles=new string[3];
lstFiles[0]=#"C:/pdf/1.pdf";
lstFiles[1]=#"C:/pdf/2.pdf";
lstFiles[2]=#"C:/pdf/3.pdf";
PdfReader reader = null;
Document sourceDocument = null;
PdfCopy pdfCopyProvider = null;
PdfImportedPage importedPage;
string outputPdfPath=#"C:/pdf/new.pdf";
sourceDocument = new Document();
pdfCopyProvider = new PdfCopy(sourceDocument, new System.IO.FileStream(outputPdfPath, System.IO.FileMode.Create));
//Open the output file
sourceDocument.Open();
try
{
//Loop through the files list
for (int f = 0; f < lstFiles.Length-1; f++)
{
int pages =get_pageCcount(lstFiles[f]);
reader = new PdfReader(lstFiles[f]);
//Add pages of current file
for (int i = 1; i <= pages; i++)
{
importedPage = pdfCopyProvider.GetImportedPage(reader, i);
pdfCopyProvider.AddPage(importedPage);
}
reader.Close();
}
//At the end save the output file
sourceDocument.Close();
}
catch (Exception ex)
{
throw ex;
}
private int get_pageCcount(string file)
{
using (StreamReader sr = new StreamReader(File.OpenRead(file)))
{
Regex regex = new Regex(#"/Type\s*/Page[^s]");
MatchCollection matches = regex.Matches(sr.ReadToEnd());
return matches.Count;
}
}
Here is a example using iTextSharp
public static void MergePdf(Stream outputPdfStream, IEnumerable<string> pdfFilePaths)
{
using (var document = new Document())
using (var pdfCopy = new PdfCopy(document, outputPdfStream))
{
pdfCopy.CloseStream = false;
try
{
document.Open();
foreach (var pdfFilePath in pdfFilePaths)
{
using (var pdfReader = new PdfReader(pdfFilePath))
{
pdfCopy.AddDocument(pdfReader);
pdfReader.Close();
}
}
}
finally
{
document?.Close();
}
}
}
The PdfReader constructor has many overloads. It's possible to replace the parameter type IEnumerable<string> with IEnumerable<Stream> and it should work as well. Please notice that the method does not close the OutputStream, it delegates that task to the Stream creator.
PDFsharp seems to allow merging multiple PDF documents into one.
And the same is also possible with ITextSharp.
Combining two byte[] using iTextSharp up to version 5.x:
internal static MemoryStream mergePdfs(byte[] pdf1, byte[] pdf2)
{
MemoryStream outStream = new MemoryStream();
using (Document document = new Document())
using (PdfCopy copy = new PdfCopy(document, outStream))
{
document.Open();
copy.AddDocument(new PdfReader(pdf1));
copy.AddDocument(new PdfReader(pdf2));
}
return outStream;
}
Instead of the byte[]'s it's possible to pass also Stream's
There's some good answers here already, but I thought I might mention that pdftk might be useful for this task. Instead of producing one PDF directly, you could produce each PDF you need and then combine them together as a post-process with pdftk. This could even be done from within your program using a system() or ShellExecute() call.
You could try pdf-shuffler gtk-apps.org
I know a lot of people have recommended PDF Sharp, however it doesn't look like that project has been updated since june of 2008. Further, source isn't available.
Personally, I've been playing with iTextSharp which has been pretty easy to work with.
I combined the two above, because I needed to merge 3 pdfbytes and return a byte
internal static byte[] mergePdfs(byte[] pdf1, byte[] pdf2,byte[] pdf3)
{
MemoryStream outStream = new MemoryStream();
using (Document document = new Document())
using (PdfCopy copy = new PdfCopy(document, outStream))
{
document.Open();
copy.AddDocument(new PdfReader(pdf1));
copy.AddDocument(new PdfReader(pdf2));
copy.AddDocument(new PdfReader(pdf3));
}
return outStream.ToArray();
}
Following method gets a List of byte array which is PDF byte array and then returns a byte array.
using ...;
using PdfSharp.Pdf;
using PdfSharp.Pdf.IO;
public static class PdfHelper
{
public static byte[] PdfConcat(List<byte[]> lstPdfBytes)
{
byte[] res;
using (var outPdf = new PdfDocument())
{
foreach (var pdf in lstPdfBytes)
{
using (var pdfStream = new MemoryStream(pdf))
using (var pdfDoc = PdfReader.Open(pdfStream, PdfDocumentOpenMode.Import))
for (var i = 0; i < pdfDoc.PageCount; i++)
outPdf.AddPage(pdfDoc.Pages[i]);
}
using (var memoryStreamOut = new MemoryStream())
{
outPdf.Save(memoryStreamOut, false);
res = Stream2Bytes(memoryStreamOut);
}
}
return res;
}
public static void DownloadAsPdfFile(string fileName, byte[] content)
{
var ms = new MemoryStream(content);
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.ContentType = "application/pdf";
HttpContext.Current.Response.AddHeader("content-disposition", $"attachment;filename={fileName}.pdf");
HttpContext.Current.Response.Buffer = true;
ms.WriteTo(HttpContext.Current.Response.OutputStream);
HttpContext.Current.Response.End();
}
private static byte[] Stream2Bytes(Stream input)
{
var buffer = new byte[input.Length];
using (var ms = new MemoryStream())
{
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
ms.Write(buffer, 0, read);
return ms.ToArray();
}
}
}
So, the result of PdfHelper.PdfConcat method is passed to PdfHelper.DownloadAsPdfFile method.
PS: A NuGet package named [PdfSharp][1] need to be installed. So in the Package Manage Console window type:
Install-Package PdfSharp
Following method merges two pdfs( f1 and f2) using iTextSharp. The second pdf is appended after a specific index of f1.
string f1 = "D:\\a.pdf";
string f2 = "D:\\Iso.pdf";
string outfile = "D:\\c.pdf";
appendPagesFromPdf(f1, f2, outfile, 3);
public static void appendPagesFromPdf(String f1,string f2, String destinationFile, int startingindex)
{
PdfReader p1 = new PdfReader(f1);
PdfReader p2 = new PdfReader(f2);
int l1 = p1.NumberOfPages, l2 = p2.NumberOfPages;
//Create our destination file
using (FileStream fs = new FileStream(destinationFile, FileMode.Create, FileAccess.Write, FileShare.None))
{
Document doc = new Document();
PdfWriter w = PdfWriter.GetInstance(doc, fs);
doc.Open();
for (int page = 1; page <= startingindex; page++)
{
doc.NewPage();
w.DirectContent.AddTemplate(w.GetImportedPage(p1, page), 0, 0);
//Used to pull individual pages from our source
}// copied pages from first pdf till startingIndex
for (int i = 1; i <= l2;i++)
{
doc.NewPage();
w.DirectContent.AddTemplate(w.GetImportedPage(p2, i), 0, 0);
}// merges second pdf after startingIndex
for (int i = startingindex+1; i <= l1;i++)
{
doc.NewPage();
w.DirectContent.AddTemplate(w.GetImportedPage(p1, i), 0, 0);
}// continuing from where we left in pdf1
doc.Close();
p1.Close();
p2.Close();
}
}
To solve a similar problem i used iTextSharp like this:
//Create the document which will contain the combined PDF's
Document document = new Document();
//Create a writer for de document
PdfCopy writer = new PdfCopy(document, new FileStream(OutPutFilePath, FileMode.Create));
if (writer == null)
{
return;
}
//Open the document
document.Open();
//Get the files you want to combine
string[] filePaths = Directory.GetFiles(DirectoryPathWhereYouHaveYourFiles);
foreach (string filePath in filePaths)
{
//Read the PDF file
using (PdfReader reader = new PdfReader(vls_FilePath))
{
//Add the file to the combined one
writer.AddDocument(reader);
}
}
//Finally close the document and writer
writer.Close();
document.Close();
Here is a link to an example using PDFSharp and ConcatenateDocuments
Here the solution http://www.wacdesigns.com/2008/10/03/merge-pdf-files-using-c
It use free open source iTextSharp library http://sourceforge.net/projects/itextsharp
I've done this with PDFBox. I suppose it works similarly to iTextSharp.

Categories