Merge multiple multi-page tiff images to a single tiff C#
Asked Answered
H

2

8

In my scenario I have 3 or more multi-page tiff images which I need to merge into a single tiff image.

Below is the the code I have tried. It merges in to a single tiff image but only with first page of all tiff images.

private static void MergeTiff(string[] sourceFiles)
{
    string[] sa = sourceFiles;
    //get the codec for tiff files
    ImageCodecInfo info = null;
    foreach (ImageCodecInfo ice in ImageCodecInfo.GetImageEncoders())
        if (ice.MimeType == "image/tiff")
            info = ice;

    //use the save encoder
    Encoder enc = Encoder.SaveFlag;

    EncoderParameters ep = new EncoderParameters(1);
    ep.Param[0] = new EncoderParameter(enc, (long)EncoderValue.MultiFrame);

    Bitmap pages = null;

    int frame = 0;

    foreach (string s in sa)
    {
        if (frame == 0)
        {
            MemoryStream ms = new MemoryStream(File.ReadAllBytes(Path.Combine(Environment.CurrentDirectory, @"C:\Data_Warehouse\SVNRepository\CD.BNS.W5555.LT45555C.D180306.T113850.Z0101\", s)));
            pages = (Bitmap)Image.FromStream(ms);

            var appDataPath = @"C:\Data_Warehouse\SVNRepository\Tiffiles\";
            var filePath = Path.Combine(appDataPath, Path.GetRandomFileName() + ".tif");

            //save the first frame
            pages.Save(filePath, info, ep);
        }
        else
        {
            //save the intermediate frames
            ep.Param[0] = new EncoderParameter(enc, (long)EncoderValue.FrameDimensionPage);

            try
            {
                MemoryStream mss = new MemoryStream(File.ReadAllBytes(Path.Combine(Environment.CurrentDirectory, @"C:\Data_Warehouse\SVNRepository\CD.BNS.W5555.LT45555C.D180306.T113850.Z0101\", s)));
                Bitmap bm = (Bitmap)Image.FromStream(mss);
                pages.SaveAdd(bm, ep);
            }
            catch (Exception e)
            {
                //LogError(e, s);
            }
        }

        if (frame == sa.Length - 1)
        {
            //flush and close.
            ep.Param[0] = new EncoderParameter(enc, (long)EncoderValue.Flush);
            pages.SaveAdd(ep);

        }

        frame++;
    }

}

I need to join multiple tiff images with all pages from each tiff image. Please advise!

Thanks

EDIT: Updated from below answer

if (frame == 0)
            {
                MemoryStream ms = new MemoryStream(File.ReadAllBytes(Path.Combine(Environment.CurrentDirectory, @"C:\OMTest\Working\", s)));
                pages = (Bitmap)Image.FromStream(ms);

                var appDataPath = @"C:\Data_Warehouse\SVNRepository\Tiffiles\";
                var filePath = Path.Combine(appDataPath, Path.GetRandomFileName() + ".tif");

                //save the first frame
                pages.Save(filePath, info, ep);

                //Save the second frame if any
                int frameCount1 = pages.GetFrameCount(FrameDimension.Page);
                if (frameCount1 > 1)
                {
                    for (int i = 1; i < frameCount1; i++)
                    {
                        ep.Param[0] = new EncoderParameter(enc, (long)EncoderValue.FrameDimensionPage);
                        pages.SelectActiveFrame(FrameDimension.Page, i);
                        pages.SaveAdd(pages, ep);
                    }
                }
            }
            else
            {
                //save the intermediate frames
                ep.Param[0] = new EncoderParameter(enc, (long)EncoderValue.FrameDimensionPage);
                try
                {
                    MemoryStream mss = new MemoryStream(File.ReadAllBytes(Path.Combine(Environment.CurrentDirectory, @"C:\OMTest\Working\", s)));
                    Bitmap bm = (Bitmap)Image.FromStream(mss);
                    int frameCount = bm.GetFrameCount(FrameDimension.Page);
                    for (int i = 0; i < frameCount; i++)
                    {
                        bm.SelectActiveFrame(FrameDimension.Page, i);
                        pages.SaveAdd(bm, ep);
                    }
                }
                catch (Exception e)
                {
                    //LogError(e, s);
                }
            }
Heder answered 21/1, 2019 at 6:17 Comment(0)
S
9

You need to select the active frame to ensure you are getting all pages on the TIFF. In your code you need to get the count of frames and loop through these.

The code in your else block might look something like this:

MemoryStream mss = new MemoryStream(File.ReadAllBytes(Path.Combine(Environment.CurrentDirectory, @"C:\Data_Warehouse\SVNRepository\CD.BNS.W5555.LT45555C.D180306.T113850.Z0101\", s)));
Bitmap bm = (Bitmap)Image.FromStream(mss);
int frameCount = bm.GetFrameCount(FrameDimension.Page);
for(int i=0;i<frameCount;i++){
    bm.SelectActiveFrame(FrameDimension.Page, i);
    pages.SaveAdd(bm, ep);
}

You may have to tweak it as I haven't tested it.

Sammie answered 21/1, 2019 at 6:58 Comment(1)
Thank you very much. Your code worked perfectly fine although I had to tweak a little. Added a changed code in edit section for anyone's reference.Heder
M
1

The given code works great to merge single-page TIFF files into a single multi-page TIFF, however, if there are multi-page TIFF files as sources, it will only merge their first page in the resulting TIFF file: the other ones will be discarded.

Since we couldn't find any working samples that could work around this issue, we ended up coding a small C# helper class, which later became a full-fledged multi-platform console application written in .NET Core 2 and C#. We called the project MergeTIFF and we released the whole source code on GitHub under GNU v3 license, so that everyone else can use it as well; we also released the binaries for Windows and Linux (32-bit and 64-bit).

Here's the relevant excerpt of the C# code:

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;

namespace MergeTiff.NET
{
    /// <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;
        }
    }
}

For additional info and/or to download it, you can take a look at the following resources that we published to better document the whole project:

Mclellan answered 31/7, 2019 at 14:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.