Friday, February 22, 2013

Creating a Multi Page PDF from a TIFF | TIFF to PDF Converter


I've been working on a project recently that had a requirement to do a tiff to pdf conversion on the fly, and serve these pdf's over the web. The added wrinkle was that these tiff files were stored in a database - so I wasn't going to reading or writing from the filesystem. This isn't a huge problem, but it did throw 90% of the examples out of the window!

I opted to use PdfSharp to do the conversion this - it's a really great open source library and did exactly what I needed.

So here we go:

snippet 1:
byte[] bytes = GetMyByteData();

using (MemoryStream memoryStream = new MemoryStream(bytes))
{
 memoryStream.Position = 0;
 memoryStream.Write(bytes, 0, bytes.Length);
 
 System.Drawing.Image image = System.Drawing.Image.FromStream(memoryStream, true, true);
 
 //This is where the next code goes!!
}


To start with I retrieved my data from the database into a byte array, wrote it into a memory stream object and finally created an Image object from the memory stream. Next onto creating the pdf document:

snippet 2:
PdfDocument doc = new PdfDocument();
XGraphics xgr;

PdfPage page = new PdfPage();
doc.Pages.Add(page);
xgr = XGraphics.FromPdfPage(page);

XImage ximg = XImage.FromGdiPlusImage(image);
xgr.DrawImage(ximg, 0, 0);


As you can see from the code, this is where PdfSharp comes into play (I opted for the GDI+ version) - creating a PdfDocument, XGraphics object, PdfPage and loading the image into page. I guess the real magic here when using the XImage.FromGdiPlusImage method to load the in memory image file into a pdf writeable object.

Finally was writing this back to the response stream (in ASP.NET obviously!):

snippet 3:
using (MemoryStream responseStream = new MemoryStream())
{
 doc.Save(responseStream, false);
 responseStream.Position = 0;

 context.Response.ClearContent();
 context.Response.ClearHeaders();
 context.Response.BufferOutput = true;
 context.Response.ContentType = "application/pdf";
 context.Response.AddHeader("content-disposition", "inline;filename=mypdf.pdf");

 responseStream.CopyTo(context.Response.OutputStream);

 context.Response.Flush();
 context.Response.Close();
 context.Response.End();
}

doc.Close();


I wont go into too much detail about this, its pretty straight forward stuff. For me the 2 things really worth mentioning is the doc.Save() method which saves the pdf to a new memory stream, and the responseStream.CopyTo method which copies one stream to another (new to .net 4 I think!).

This all worked fine but there was one further complication - the TIFFs might be multi-page. In those examples the pdf would only ever contain the first page. To overcome this I had to loop over the page frames and add a new pdf page for each one. This replaces snippet 2 with the following:

snippet 2(v2):
PdfDocument doc = new PdfDocument();
XGraphics xgr;

int count = image.GetFrameCount(FrameDimension.Page);
for (int pageNum = 0; pageNum < count; pageNum++) {  image.SelectActiveFrame(FrameDimension.Page, pageNum);   PdfPage page = new PdfPage();  doc.Pages.Add(page);  xgr = XGraphics.FromPdfPage(page);   XImage ximg = XImage.FromGdiPlusImage(image);  xgr.DrawImage(ximg, 0, 0); } 


I was pleasantly surprised with how straight forward this was to achieve, and in particular how quickly it all worked.

Matt

source : http://www.codenutz.com/2011/10/creating-multi-page-pdf-from-tiff-tiff.html