Multipage TIFFs are awesome, aren't them? Well, actually not so much, especially considering the existance of better alternatives such as PDF files. That's precisely why we published a post some months ago explaining how to merge image files of any kind into a single PDF file in ASP.NET C# using the iTextSharp open-source library: if you need a single generic container to store your TIFFs and you can deal with PDFs, we strongly suggest to look no further than that post.
However, there are some specific scenarios where you cannot use PDFs and/or you need to stick to TIFFs. That happened to me some days ago, when I had to re-factor a web service who was serving TIFF files to an old program that could only handle TIFF files.
Since I couldn't use the above PDF-container class, I resorted to code the following helper class, which I'm publishing here hoping that it will help other developers who need to do the same.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
using System; using System.Drawing; using System.Drawing.Imaging; using System.IO; namespace Ryadel.Components.Media { /// <summary> /// A small helper class to handle TIFF files /// </summary> public static class TiffHelper { /// <summary> /// Merges multiple TIFF files (including multipage TIFFs) into a single multipage TIFF file. /// </summary> public static byte[] MergeTiff(params byte[][] tiffFiles) { byte[] tiffMerge = null; using (var msMerge = new MemoryStream()) { //get the codec for tiff files ImageCodecInfo ici = null; foreach (ImageCodecInfo i in ImageCodecInfo.GetImageEncoders()) if (i.MimeType == "image/tiff") ici = i; Encoder enc = Encoder.SaveFlag; EncoderParameters ep = new EncoderParameters(1); Bitmap pages = null; int frame = 0; foreach (var tiffFile in tiffFiles) { using (var imageStream = new MemoryStream(tiffFile)) { using (Image tiffImage = Image.FromStream(imageStream)) { foreach (Guid guid in tiffImage.FrameDimensionsList) { //create the frame dimension FrameDimension dimension = new FrameDimension(guid); //Gets the total number of frames in the .tiff file int noOfPages = tiffImage.GetFrameCount(dimension); for (int index = 0; index < noOfPages; index++) { FrameDimension currentFrame = new FrameDimension(guid); tiffImage.SelectActiveFrame(currentFrame, index); using (MemoryStream tempImg = new MemoryStream()) { tiffImage.Save(tempImg, ImageFormat.Tiff); { if (frame == 0) { //save the first frame pages = (Bitmap)Image.FromStream(tempImg); ep.Param[0] = new EncoderParameter(enc, (long)EncoderValue.MultiFrame); pages.Save(msMerge, ici, ep); } else { //save the intermediate frames ep.Param[0] = new EncoderParameter(enc, (long)EncoderValue.FrameDimensionPage); pages.SaveAdd((Bitmap)Image.FromStream(tempImg), ep); } } frame++; } } } } } } if (frame > 0) { //flush and close. ep.Param[0] = new EncoderParameter(enc, (long)EncoderValue.Flush); pages.SaveAdd(ep); } msMerge.Position = 0; tiffMerge = msMerge.ToArray(); } return tiffMerge; } } } |
That's about it: the comments are quite self-explanatory, hence there's not much to add here.
In case you find this class useful, don't forget to give us a like!