マルチTIFFを作成する方法は、「Generating multi-page TIFF files」や「Save images into a multi-page TIFF file or add images to an existing TIFF file - CodeProject」で紹介されています。
これらを参考にさせていただいて、以下のようなコードを書いてみました。このサンプルのメソッドでは3番目のパラメータに圧縮方法としてEncoderValue列挙体の値を指定できます。指定できる値は、CompressionCCITT3(CCITT3、Group 3 Fax Encoding)、CompressionCCITT4(CCITT4、Group 4 Fax Encoding)、CompressionLZW(LZW)、CompressionNone(圧縮なし)、CompressionRle(PackBits)のいずれかです。ただし、圧縮方法にCompressionCCITT3、CompressionCCITT4、CompressionRleを指定すると、「使用されたパラメータが有効ではありません。」という例外ArgumentExceptionがスローされることがあります(私が試した限りでは、Windows XP SP3では例外がスローされましたが、Windows 7ではされませんでした)。そのような場合は、TIFFに追加する画像をあらかじめ白黒2値の画像に変換しておきます。その方法は、「2値化して、1bppの白黒画像を作成する」で説明しています。
補足:圧縮方法を指定しないで(EncoderParametersにEncoder.SaveFlagのみを追加して)作成することも出来ますが、その場合はLZWで圧縮されるようです。ただ、EncoderValue.CompressionLZWを指定した時とは同じになりません(私が試した限りでは、何も指定しない方がサイズが小さくなりました)。
'Imports System.Drawing 'Imports System.Drawing.Imaging ''' <summary> ''' 複数の画像をマルチTIFFで保存する ''' </summary> ''' <param name="fileName">保存先のTIFFファイルのパス</param> ''' <param name="baseImages">TIFFに追加する画像の配列</param> ''' <param name="compressionScheme">圧縮方法</param> Public Shared Sub SaveMultiTiff(fileName As String, _ baseImages As Bitmap(), _ compressionScheme As EncoderValue) If fileName Is Nothing OrElse fileName.Length = 0 Then Throw New ArgumentException("fileName") End If If baseImages Is Nothing OrElse baseImages.Length = 0 Then Throw New ArgumentException("baseImages") End If If compressionScheme <> EncoderValue.CompressionCCITT3 AndAlso _ compressionScheme <> EncoderValue.CompressionCCITT4 AndAlso _ compressionScheme <> EncoderValue.CompressionLZW AndAlso _ compressionScheme <> EncoderValue.CompressionNone AndAlso _ compressionScheme <> EncoderValue.CompressionRle Then Throw New ArgumentException("compressionScheme") End If 'TIFFのImageCodecInfoを取得する Dim ici As ImageCodecInfo = GetEncoderInfo("image/tiff") If ici Is Nothing Then Return End If Dim imagesCount As Integer = baseImages.Length Dim tiffImage As Bitmap = baseImages(0) Dim ep As EncoderParameters = Nothing If imagesCount = 1 Then 'マルチTIFFではなく、1枚だけ保存する '圧縮方法を指定する ep = New EncoderParameters(1) ep.Param(0) = New EncoderParameter( _ Encoder.Compression, CLng(compressionScheme)) tiffImage.Save(fileName, ici, ep) ep.Dispose() Return End If Dim i As Integer For i = 0 To imagesCount - 1 If i = 0 Then ep = New EncoderParameters(2) 'はじめのフレームはMultiFrameで保存する ep.Param(0) = New EncoderParameter( _ Encoder.SaveFlag, CLng(EncoderValue.MultiFrame)) '圧縮方法を指定する ep.Param(1) = New EncoderParameter( _ Encoder.Compression, CLng(compressionScheme)) tiffImage.Save(fileName, ici, ep) ep.Dispose() Else ep = New EncoderParameters(2) '2枚目からはFrameDimensionPageで追加する ep.Param(0) = New EncoderParameter( _ Encoder.SaveFlag, CLng(EncoderValue.FrameDimensionPage)) '圧縮方法を指定する ep.Param(1) = New EncoderParameter( _ Encoder.Compression, CLng(compressionScheme)) tiffImage.SaveAdd(baseImages(i), ep) ep.Dispose() End If If i = imagesCount - 1 Then ep = New EncoderParameters(1) '最後にFlushで閉じる ep.Param(0) = New EncoderParameter( _ Encoder.SaveFlag, CLng(EncoderValue.Flush)) tiffImage.SaveAdd(ep) ep.Dispose() End If Next End Sub 'MimeTypeで指定されたImageCodecInfoを探して返す Private Shared Function GetEncoderInfo(mineType As String) _ As System.Drawing.Imaging.ImageCodecInfo 'GDI+ に組み込まれたイメージ エンコーダに関する情報をすべて取得 Dim encs As System.Drawing.Imaging.ImageCodecInfo() = _ System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders() '指定されたMimeTypeを探して見つかれば返す Dim enc As System.Drawing.Imaging.ImageCodecInfo For Each enc In encs If enc.MimeType = mineType Then Return enc End If Next Return Nothing End Function 'ImageFormatで指定されたImageCodecInfoを探して返す Private Shared Function GetEncoderInfo(f As System.Drawing.Imaging.ImageFormat) _ As System.Drawing.Imaging.ImageCodecInfo Dim encs As System.Drawing.Imaging.ImageCodecInfo() = _ System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders() Dim enc As System.Drawing.Imaging.ImageCodecInfo For Each enc In encs If enc.FormatID = f.Guid Then Return enc End If Next Return Nothing End Function
//using System.Drawing; //using System.Drawing.Imaging; /// <summary> /// 複数の画像をマルチTIFFで保存する /// </summary> /// <param name="fileName">保存先のTIFFファイルのパス</param> /// <param name="baseImages">TIFFに追加する画像の配列</param> /// <param name="compressionScheme">圧縮方法</param> public static void SaveMultiTiff(string fileName, Bitmap[] baseImages, EncoderValue compressionScheme) { if (fileName == null || fileName.Length == 0) { throw new ArgumentException("fileName"); } if (baseImages == null || baseImages.Length == 0) { throw new ArgumentException("baseImages"); } if (compressionScheme != EncoderValue.CompressionCCITT3 && compressionScheme != EncoderValue.CompressionCCITT4 && compressionScheme != EncoderValue.CompressionLZW && compressionScheme != EncoderValue.CompressionNone && compressionScheme != EncoderValue.CompressionRle) { throw new ArgumentException("compressionScheme"); } //TIFFのImageCodecInfoを取得する ImageCodecInfo ici = GetEncoderInfo("image/tiff"); if (ici == null) return; int imagesCount = baseImages.Length; Bitmap tiffImage = baseImages[0]; EncoderParameters ep = null; if (imagesCount == 1) { //マルチTIFFではなく、1枚だけ保存する //圧縮方法を指定する ep = new EncoderParameters(1); ep.Param[0] = new EncoderParameter( Encoder.Compression, (long)compressionScheme); tiffImage.Save(fileName, ici, ep); ep.Dispose(); return; } for (int i = 0; i < imagesCount; i++) { if (i == 0) { ep = new EncoderParameters(2); //はじめのフレームはMultiFrameで保存する ep.Param[0] = new EncoderParameter( Encoder.SaveFlag, (long)EncoderValue.MultiFrame); //圧縮方法を指定する ep.Param[1] = new EncoderParameter( Encoder.Compression, (long)compressionScheme); tiffImage.Save(fileName, ici, ep); ep.Dispose(); } else { ep = new EncoderParameters(2); //2枚目からはFrameDimensionPageで追加する ep.Param[0] = new EncoderParameter( Encoder.SaveFlag, (long)EncoderValue.FrameDimensionPage); //圧縮方法を指定する ep.Param[1] = new EncoderParameter( Encoder.Compression, (long)compressionScheme); tiffImage.SaveAdd(baseImages[i], ep); ep.Dispose(); } if (i == imagesCount - 1) { ep = new EncoderParameters(1); //最後にFlushで閉じる ep.Param[0] = new EncoderParameter( Encoder.SaveFlag, (long)EncoderValue.Flush); tiffImage.SaveAdd(ep); ep.Dispose(); } } } //MimeTypeで指定されたImageCodecInfoを探して返す private static System.Drawing.Imaging.ImageCodecInfo GetEncoderInfo(string mineType) { //GDI+ に組み込まれたイメージ エンコーダに関する情報をすべて取得 System.Drawing.Imaging.ImageCodecInfo[] encs = System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders(); //指定されたMimeTypeを探して見つかれば返す foreach (System.Drawing.Imaging.ImageCodecInfo enc in encs) { if (enc.MimeType == mineType) { return enc; } } return null; } //ImageFormatで指定されたImageCodecInfoを探して返す private static System.Drawing.Imaging.ImageCodecInfo GetEncoderInfo(System.Drawing.Imaging.ImageFormat f) { System.Drawing.Imaging.ImageCodecInfo[] encs = System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders(); foreach (System.Drawing.Imaging.ImageCodecInfo enc in encs) { if (enc.FormatID == f.Guid) { return enc; } } return null; }
.NET Framework 3.0以降では、WPFの機能であるTiffBitmapEncoderクラスを使って作成することもできます。この方法は「GIFアニメーションを作成する」で紹介している「GifBitmapEncoderを使う方法」とほぼ同じですが、TiffBitmapEncoderはCompressionプロパティで圧縮方法を指定できます。Compressionプロパティに指定できるTiffCompressOption列挙体の値には以下のようなものがあります(MSDNからの引用です)。
メンバ名 | 説明 |
---|---|
Default | TiffBitmapEncoder エンコーダーは、利用可能な最適な圧縮スキーマでビットマップの保存を試みます。 |
None | Tagged Image File Format (TIFF) イメージは圧縮されません。 |
Ccitt3 | CCITT3 圧縮スキーマが使用されます。 |
Ccitt4 | CCITT4 圧縮スキーマが使用されます。 |
Lzw | LZW 圧縮スキーマが使用されます。 |
Rle | RLE 圧縮スキーマが使用されます。 |
Zip | Zip 圧縮スキーマが使用されます。 |
MSDNによると、Ccitt3、Ccitt4、Rleでは画像のFormatがBlackWhiteでないと(つまり白黒2値でないと)CompressionプロパティがDefaultにリセットされるということです。ただ、Windows XP SP3と7で私が試した所では、そのようなことはありませんでした。
以下に例を示します。PresentationCoreとWindowsBase、さらにVB.NETの場合はSystem.Xamlを参照設定に追加する必要があります。
'Imports System.Windows.Media.Imaging 'Imports System.IO ''' <summary> ''' 複数の画像をマルチTIFFで保存する ''' </summary> ''' <param name="savePath">保存先のTIFFファイルのパス</param> ''' <param name="imageFiles">TIFFに追加する画像の配列</param> Public Shared Sub CreateMultiTiff(ByVal savePath As String, _ ByVal imageFiles As String(), _ ByVal compressOption As TiffCompressOption) 'TiffBitmapEncoderを作成する Dim encoder As New TiffBitmapEncoder() '圧縮方法を変更する encoder.Compression = compressOption For Each f As String In imageFiles '画像ファイルからBitmapFrameを作成する Dim bmpFrame As BitmapFrame = _ BitmapFrame.Create(New Uri(f, UriKind.RelativeOrAbsolute)) 'フレームに追加する encoder.Frames.Add(bmpFrame) Next '書き込むファイルを開く Dim outputFileStrm As New FileStream(savePath, _ FileMode.Create, FileAccess.Write, FileShare.None) '保存する encoder.Save(outputFileStrm) '閉じる outputFileStrm.Close() End Sub
//using System.Windows.Media.Imaging; //using System.IO; /// <summary> /// 複数の画像をマルチTIFFで保存する /// </summary> /// <param name="savePath">保存先のTIFFファイルのパス</param> /// <param name="imageFiles">TIFFに追加する画像の配列</param> public static void CreateMultiTiff(string savePath, string[] imageFiles, TiffCompressOption compressOption) { //TiffBitmapEncoderを作成する TiffBitmapEncoder encoder = new TiffBitmapEncoder(); //圧縮方法を変更する encoder.Compression = compressOption; foreach (string f in imageFiles) { //画像ファイルからBitmapFrameを作成する BitmapFrame bmpFrame = BitmapFrame.Create(new Uri(f, UriKind.RelativeOrAbsolute)); //フレームに追加する encoder.Frames.Add(bmpFrame); } //書き込むファイルを開く FileStream outputFileStrm = new FileStream(savePath, FileMode.Create, FileAccess.Write, FileShare.None); //保存する encoder.Save(outputFileStrm); //閉じる outputFileStrm.Close(); }
注意:この記事では、基本的な事柄の説明が省略されているかもしれません。初心者の方は、特に以下の点にご注意ください。