I would like to open an existing pdf, add some text and then output as content disposition using itext sharp. I have the following code. Where it falls down it is that i want to output as memory stream but need to filestream to open the original file.
Here’s what i have. Obviously defining PdfWriter twice won’t work.
public static void Create(string path)
{
var Response = HttpContext.Current.Response;
Response.Clear();
Response.ContentType = "application/pdf";
System.IO.MemoryStream m = new System.IO.MemoryStream();
Document document = new Document();
PdfWriter wri = PdfWriter.GetInstance(document, new FileStream(path, FileMode.Create));
PdfWriter.GetInstance(document, m);
document.Open();
document.Add(new Paragraph(DateTime.Now.ToString()));
document.NewPage();
document.Add(new Paragraph("Hello World"));
document.Close();
Response.OutputStream.Write(m.GetBuffer(), 0, m.GetBuffer().Length);
Response.OutputStream.Flush();
Response.OutputStream.Close();
Response.End();
}
You’ve got a couple of problems that I’ll try to walk you through.
First, the
Documentobject is only for working with new PDFs, not modifying existing ones. Basically theDocumentobject is a bunch of wrapper classes that abstract away the underlying parts of the PDF spec and allow you to work with higher level things like paragraphs and reflowable content. These abstractions turn what you think of “paragraphs” into raw commands that write the paragraph one line at a time with no relationship between lines. When working with an existing document there’s no safe way to say how to reflow text so these abstractions aren’t used.Instead you want to use the
PdfStamperobject. When working with this object you have two choices for how to work with potentially overlapping content, either your new text gets written on top of existing content or your text gets written below it. The two methodsGetOverContent()orGetUnderContent()of an instantiatedPdfStamperobject will return aPdfContentByteobject that you can then write text with.There’s two main ways to write text, either manually or through a
ColumnTextobject. If you’ve done HTML you can think of theColumnTextobject as using a big fixed-position single row, single column<TABLE>. The advantage of theColumnTextis that you can use the higher level abstractions such asParagraph.Below is a full working C# 2010 WinForms app targeting iTextSharp 5.1.2.0 that show off the above. See the code comments for any questions. It should be pretty easy to convert this to ASP.Net.
As to your second problem about the
FileStreamvsMemoryStream, if you look at the method signature for almost every (actually all as far as I know) method within iTextSharp you’ll see that they all take aStreamobject and not just aFileStreamobject. Any time you see this, even outside of iTextSharp, this means that you can pass in any subclass ofStreamwhich includes theMemoryStreamobject, everything else stays the same.The code below is a slightly modified version of the one above. I’ve removed most of the comments to make it shorter. The main change is that we’re using a
MemoryStreaminstead of aFileStream. Also, when we’re done with the PDF when need to close thePdfStamperobject before accessing the raw binary data. (Theusingstatment will do this for us automatically later but it also closes the stream so we need to manually do it here.)One other thing, never, ever use the
GetBuffer()method of theMemoryStream. It sounds like what you want (and I have mistakenly used it, too) but instead you want to useToArray().GetBuffer()includes uninitialized bytes which usually produces corrupt PDFs. Also, instead of writing to the HTTP Response stream I’m saving the bytes to array first. From a debugging perspective this allows me to finish all of my iTextSharp andSystem.IOcode and make sure that it is correct, then do whatever I want with the raw byte array. In my case I don’t have a web server handy so I’m writing them to disk but you could just as easily callResponse.BinaryWrite(bytes)