Generating Multi-Page TIFF files.

Creating a multi-page TIFF file from several images is not a complex operation but it's confusing to get things in the right order. This article will clearly demonstrate that technique and provide a test application that creates multi-page TIFF files automatically when you drop images onto a form.

Rather than delve immediately into the code, take a moment to understand the process.

Images can be saved in a number of formats. To determine which one is used we can specify the encoder used to save the data. Image encoders can be complex and so the framework provides a bunch of parameters that can be used in the context of a certain encoders to alter the way images are saved.

Tiff files probably employ the most complex and diverse image formats so, not surprisingly, the encoders for TIFF files are similarly complex and diverse. A multiple page TIFF is effectively a bunch of images stored one-after-the-other in a single file. The files may be of different formats and even have different physical sizes. These individual images, or frames, may be accessed by selecting the frame to be viewed and drawing it as you would any other image. The process of creating such a file is controlled by using a single image as a master frame and adding other images to it in sequence.

The steps taken to create the multi-frame image are:

  1. Get an encoder for saving with

  2. Obtain the TIFF codec info.

  3. Create a parameter list. This needs 1 parameter in it.

  4. Place the MultiFrame encoder value in the parameter list

  5. Save the first frame using the encoder and parameters

  6. Change the encoder value in the list to FrameDimensionPage

  7. Use first of the master frame's overloaded SaveAdd methods to add subsequent images. Repeat this step for as many images as you want to add.

  8. Change the encoder value in the list to Flush

  9. Use the second of the master frames overloaded SaveAdd methods to flush, save and close the image.

Taking these steps in order, the code to make the process work looks something like this:

1.

      Encoder enc=Encoder.SaveFlag;

2.

      ImageCodecInfo info=null;

      foreach(ImageCodecInfo ice in ImageCodecInfo.GetImageEncoders())

        if(ice.MimeType=="image/tiff")

          info=ice;

3.

      EncoderParameters ep=new EncoderParameters(1);

4.

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

5.

      MasterBitmap.Save(myFileName,info,ep);

6.

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

7.

      MasterBitmap.SaveAdd(myExtraPage1,ep);

      MasterBitmap.SaveAdd(myExtraPage2,ep);

      MasterBitmap.SaveAdd(myExtraPage3,ep);

8.

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

9.

      MasterBitmap.SaveAdd(ep);

 

1.

    Dim enc As Encoder = Encoder.SaveFlag

2.

    Dim info As ImageCodecInfo = Nothing

    For Each ice As ImageCodecInfo In ImageCodecInfo.GetImageEncoders

     If ice.MimeType = "image/tiff" Then

       info = ice

     End If

    Next

3.

    Dim ep As EncoderParameters = New EncoderParameters(1)

4.

    ep.Param(0) = New EncoderParameter(enc, CType(EncoderValue.MultiFrame, Long))

5.

    MasterBitmap.Save(myFileName, info, ep)

6.

    ep.Param(0) = New EncoderParameter(enc, CType(EncoderValue.FrameDimensionPage, Long))

7.

    MasterBitmap.SaveAdd(myExtraPage1, ep)

    MasterBitmap.SaveAdd(myExtraPage2, ep)

    MasterBitmap.SaveAdd(myExtraPage3, ep)

8.

    ep.Param(0) = New EncoderParameter(enc, CType(EncoderValue.Flush, Long))

9.

    MasterBitmap.SaveAdd(ep)

To demonstrate this process the following Windows Forms application enables you to drag any number of image files onto the form. You will be asked for a filename and a multi-page TIFF with all the files dragged in will be saved.

 

using System;

using System.Drawing;

using System.Drawing.Imaging;

using System.Collections;

using System.ComponentModel;

using System.Windows.Forms;

using System.Data;

using System.IO;

 

namespace multipagetiff

{

  /// <summary>

  /// Summary description for Form1.

  /// </summary>

  public class Form1 : System.Windows.Forms.Form

  {

    /// <summary>

    /// Required designer variable.

    /// </summary>

    private System.ComponentModel.Container components = null;

 

    public Form1()

    {

      //

      // Required for Windows Form Designer support

      //

      InitializeComponent();

 

      //

      // TODO: Add any constructor code after InitializeComponent call

      //

 

      this.SetStyle(ControlStyles.ResizeRedraw,true);

    }

 

    /// <summary>

    /// Clean up any resources being used.

    /// </summary>

    protected override void Dispose( bool disposing )

    {

      if( disposing )

      {

        if (components != null)

        {

          components.Dispose();

        }

      }

      base.Dispose( disposing );

    }

 

    #region Windows Form Designer generated code

    /// <summary>

    /// Required method for Designer support - do not modify

    /// the contents of this method with the code editor.

    /// </summary>

    private void InitializeComponent()

    {

      //

      // Form1

      //

      this.AllowDrop = true;

      this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);

      this.ClientSize = new System.Drawing.Size(288, 173);

      this.Name = "Form1";

      this.Text = "Multi Page Tiff Generator";

      this.Paint += new System.Windows.Forms.PaintEventHandler(this.Form1_Paint);

 

    }

    #endregion

 

    /// <summary>

    /// The main entry point for the application.

    /// </summary>

    [STAThread]

    static void Main()

    {

      Application.Run(new Form1());

    }

 

    protected override void OnDragEnter(DragEventArgs e)

    {

      if(e.Data.GetDataPresent(DataFormats.FileDrop))

      {

        bool allow=true;

        foreach(string s in (string[])e.Data.GetData(DataFormats.FileDrop))

        {

          string ext= Path.GetExtension(s).ToLower();

          if(

            !(ext==".jpg" ||

            ext==".jpeg" ||

            ext==".tif" ||

            ext==".gif" ||

            ext==".bmp"))

            allow=false;

        }

        if(allow)

          e.Effect=DragDropEffects.Copy;

        else

          e.Effect=DragDropEffects.None;

      }

    }

 

 

    protected override void OnDragDrop(DragEventArgs e)

    {

      string[] sa=(string[])e.Data.GetData(DataFormats.FileDrop);

 

      SaveFileDialog dlg=new SaveFileDialog();

      dlg.DefaultExt=".tif";

      if(dlg.ShowDialog()!=DialogResult.OK)

        return;

 

 

      //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)

        {

          pages=(Bitmap)Image.FromFile(s);

          //save the first frame

          pages.Save(dlg.FileName,info,ep);

        }

        else

        {

          //save the intermediate frames

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

          Bitmap bm=(Bitmap)Image.FromFile(s);

          pages.SaveAdd(bm,ep);

        }

        

        if(frame==sa.Length-1)

        {

          //flush and close.

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

          pages.SaveAdd(ep);

        }

 

        frame++;

      }

 

    }

 

 

    private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)

    {

      StringFormat sf=(StringFormat)StringFormat.GenericTypographic.Clone();

      sf.Alignment=StringAlignment.Center;

      sf.LineAlignment=StringAlignment.Center;

      e.Graphics.DrawString("Drop images here to make a multi-page tiff",Font,Brushes.Black,new RectangleF(0,0,this.ClientSize.Width,this.ClientSize.Height),sf);

    }

  }

}

Imports System.IO

Imports System.Drawing.Imaging

 

Public Class Form1

    Inherits System.Windows.Forms.Form

    '/ <summary>

    '/ Required designer variable.

    '/ </summary>

    Private components As System.ComponentModel.Container = Nothing

 

    Private _tiffImage As Image

 

 

    Public Sub New()

        '

        ' Required for Windows Form Designer support

        '

        InitializeComponent()

 

        '

        ' TODO: Add any constructor code after InitializeComponent call

        '

        Me.SetStyle(ControlStyles.ResizeRedraw, True)

    End Sub 'New

 

 

    '/ <summary>

    '/ Clean up any resources being used.

    '/ </summary>

    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)

        If disposing Then

            If Not (components Is Nothing) Then

                components.Dispose()

            End If

        End If

        MyBase.Dispose(disposing)

    End Sub 'Dispose

 

#Region "Windows Form Designer generated code"

 

    '/ <summary>

    '/ Required method for Designer support - do not modify

    '/ the contents of this method with the code editor.

    '/ </summary>

    Private Sub InitializeComponent()

        '

        ' Form1

        '

        Me.AllowDrop = True

        Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)

        Me.ClientSize = New System.Drawing.Size(288, 173)

        Me.Name = "Form1"

        Me.Text = "Multi Page Tiff Generator"

    End Sub 'InitializeComponent

 

#End Region

 

 

    '/ <summary>

    '/ The main entry point for the application.

    '/ </summary>

    <STAThread()> _

    Shared Sub Main()

        Application.Run(New Form1)

    End Sub 'Main

 

 

    Protected Overrides Sub OnDragEnter(ByVal e As DragEventArgs)

        If e.Data.GetDataPresent(DataFormats.FileDrop) Then

            Dim allow As Boolean = True

            Dim s As String

            For Each s In CType(e.Data.GetData(DataFormats.FileDrop), String())

                Dim ext As String = Path.GetExtension(s).ToLower()

                If Not (ext = ".jpg" OrElse ext = ".jpeg" OrElse ext = ".tif" OrElse ext = ".gif" OrElse ext = ".bmp") Then

                    allow = False

                End If

            Next s

            If allow Then

                e.Effect = DragDropEffects.Copy

            Else

                e.Effect = DragDropEffects.None

            End If

        End If

    End Sub 'OnDragEnter

 

 

    Protected Overrides Sub OnDragDrop(ByVal e As DragEventArgs)

        Dim sa As String() = CType(e.Data.GetData(DataFormats.FileDrop), String())

 

        Dim dlg As New SaveFileDialog

        dlg.DefaultExt = ".tif"

        If dlg.ShowDialog() <> DialogResult.OK Then

            Return

        End If

 

        'get the codec for tiff files

        Dim info As ImageCodecInfo = Nothing

        Dim ice As ImageCodecInfo

        For Each ice In ImageCodecInfo.GetImageEncoders()

            If ice.MimeType = "image/tiff" Then

                info = ice

            End If

        Next ice 'use the save encoder

        Dim enc As Encoder = Encoder.SaveFlag

 

        Dim ep As New EncoderParameters(1)

        ep.Param(0) = New EncoderParameter(enc, CLng(EncoderValue.MultiFrame))

 

        Dim pages As Bitmap = Nothing

 

        Dim frame As Integer = 0

        Dim s As String

        For Each s In sa

            If frame = 0 Then

                pages = CType(Image.FromFile(s), Bitmap)

                'save the first frame

                pages.Save(dlg.FileName, info, ep)

            Else

                'save the intermediate frames

                ep.Param(0) = New EncoderParameter(enc, CLng(EncoderValue.FrameDimensionPage))

                Dim bm As Bitmap = CType(Image.FromFile(s), Bitmap)

                pages.SaveAdd(bm, ep)

            End If

 

            If frame = sa.Length - 1 Then

                'flush and close.

                ep.Param(0) = New EncoderParameter(enc, CLng(EncoderValue.Flush))

                pages.SaveAdd(ep)

            End If

 

            frame += 1

        Next s

    End Sub 'OnDragDrop

 

  

    Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint

        Dim sf As StringFormat = CType(StringFormat.GenericTypographic.Clone(), StringFormat)

        sf.Alignment = StringAlignment.Center

        sf.LineAlignment = StringAlignment.Center

        e.Graphics.DrawString("Drop images here to make a multi-page tiff", Font, Brushes.Black, New RectangleF(0, 0, Me.ClientSize.Width, Me.ClientSize.Height), sf)

    End Sub 'Form1_Paint

End Class 'Form1

Return to the GDI+ FAQ.

Copyright © Ramuseco Limited 2004-2005 All Rights Reserved.