4

I load a multiframe TIFF from a Stream in my C# application, and then save it using the Image.Save method. However, this only saves the TIFF with the first frame - how can I get it to save a multiframe tiff?

Yahia
  • 69,653
  • 9
  • 115
  • 144
Chris
  • 7,415
  • 21
  • 98
  • 190

2 Answers2

2

Since you don't provide any detailed information... just some general tips:

Multi-Frame TIFF are very complex files - for example every frame can have a different encoding... a single Bitmap/Image can't hold all frames with all relevant information (like encoding and similar) of such a file, only one at a time.

For loading you need to set parameter which tells the class which frame to load, otherwise it just loads the first... for some code see here.

Similar problems arise when saving multi-frame TIFFs - here you need to work with EncoderParameters and use SaveAdd etc. - for some working code see here.

Community
  • 1
  • 1
Yahia
  • 69,653
  • 9
  • 115
  • 144
0

Since the link to code provided by @Yahia is broken I have decided to post the code I ended up using.

In my case, the multi-frame TIFF already exists and all I need to do is to load the image, rotate by EXIF (if necessary) and save. I won't post the EXIF rotation code here, since it does not relate to this question.

using (Image img = System.Drawing.Image.FromStream(sourceStream))
{
  using (FileStream fileStream = System.IO.File.Create(filePath))
  {
    int pages = img.GetFrameCount(System.Drawing.Imaging.FrameDimension.Page);
    if (pages == 1)
    {
      img.Save(fileStream, img.RawFormat); // if there is just one page, just save the file
    }
    else
    {
      var encoder = System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders().First(x => x.MimeType == fileInfo.MediaType);
      var encoderParams = new System.Drawing.Imaging.EncoderParameters(1);

      encoderParams.Param[0] = new System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.SaveFlag, Convert.ToInt32(System.Drawing.Imaging.EncoderValue.MultiFrame));
      img.Save(fileStream, encoder, encoderParams); // save the first image with MultiFrame parameter

      for (int f = 1; f < pages; f++)
      {
        img.SelectActiveFrame(FrameDimension.Page, f); // select active page (System.Drawing.Image.FromStream loads the first one by default)

        encoderParams.Param[0] = new System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.SaveFlag, Convert.ToInt32(System.Drawing.Imaging.EncoderValue.FrameDimensionPage));
        img.SaveAdd(img, encoderParams); // save add with FrameDimensionPage parameter
      }
    }
  }
}
  • sourceStream is a System.IO.MemoryStream which holds the byte array of the file content
  • filePath is absolute path to cache directory (something like 'C:/Cache/multiframe.tiff')
  • fileInfo is a model holding the actual byte array, fileName, mediaType and other data