大量にあるマルチTIFFファイルのページ数を取得しようとした場合、意外とページ数取得に苦労します。PowerShellで取得しようにもPDFファイルの様にオブジェクト情報の中にページ数が無く、簡単に取得することができない様です。
そこで、VBAのバイナリデータ読込みからTIFFファイルのヘッダ情報を確認して、ページ数を取得する方法をご紹介したいと思います。
マクロブックの作成
新たにマクロブックを作成し、Sheet1のA列、2行目以降に調べたいTIFFファイルのフルパスを入力していきます。マクロ実行した時にB列にページ数が入力されます。
VBA構文
まず最初にVBAの構文を載せます。解説は抜きにして、とりあえずVBAコードでページ数を取得したい方はこちらのコードをコピペして利用ください。Get_TiffPageの実行でページ数の入力が開始されます。
Option Explicit
Private fn
Type FileHeader
ByteOrder As String * 2
VersionNum(1) As Byte
End Type
Type Entry_IFD
TagType(0 To 1) As Byte
DataType(0 To 1) As Byte
DataCount(0 To 3) As Byte
Data(0 To 3) As Byte
End Type
Sub Get_TiffPage()
Dim TargetRow As Long, maxrow As Long
maxrow = Sheet1.Cells(Rows.Count, 1).End(xlUp).Row
For TargetRow = 2 To maxrow
Sheet1.Cells(TargetRow, 2) = GetPageNumber(Sheet1.Cells(TargetRow, 1))
Next TargetRow
End Sub
Function GetPageNumber(TiffFileName As String)
Dim header As FileHeader
fn = FreeFile
Open TiffFileName For Binary As fn
Get fn, , header
Select Case header.ByteOrder
Case "II"
Close fn
GetPageNumber = GetPageNumber_Intel(TiffFileName)
Case "MM"
Close fn
GetPageNumber = GetPageNumber_Motorola(TiffFileName)
Case Else
Close fn
Err.Raise 9999, , "Exception ByteOrder"
End Select
End Function
Function GetPageNumber_Intel(TiffFileName As String)
Dim header As FileHeader
Dim TagSize As Integer, Tag() As Entry_IFD, NextIFD As Long
Dim pagecount As Long
Dim j As Long
fn = FreeFile
Open TiffFileName For Binary As fn
Get fn, , header
If header.VersionNum(0) <> 42 Then
Close fn
Err.Raise 9999, , "This is not TiffFile"
Exit Function
End If
pagecount = 0
Do Until EOF(fn)
Get fn, , NextIFD
If NextIFD = 0 Then Exit Do
Seek #fn, NextIFD + 1
pagecount = pagecount + 1
Get fn, , TagSize
If TagSize > 0 Then
ReDim Tag(1 To TagSize)
Get fn, , Tag
End If
Loop
Close fn
GetPageNumber_Intel = pagecount
End Function
Function GetPageNumber_Motorola(TiffFileName As String)
Dim EntryCount_Byte(1) As Byte, EntryCount_10 As Long, EntryCount_16 As String, Tag() As Entry_IFD
Dim NextIFD_10 As Long, NextIFD_16 As String
Dim IFDByte(3) As Byte
Dim header As FileHeader
Dim j As Long
Dim pagecount As Long
fn = FreeFile
Open TiffFileName For Binary As fn
Get fn, , header
If header.VersionNum(1) <> 42 Then
Close fn
Err.Raise 9999, , "This is not TiffFile"
Exit Function
End If
pagecount = 0
Do Until EOF(fn)
Get fn, , IFDByte
NextIFD_16 = Hex(Format(IFDByte(0), "00")) & Hex(Format(IFDByte(1), "00")) & _
Hex(Format(IFDByte(2), "00")) & Hex(Format(IFDByte(3), "00"))
NextIFD_10 = Abs("&H" & NextIFD_16)
If NextIFD_10 = 0 Then Exit Do
Seek #fn, NextIFD_10 + 1
pagecount = pagecount + 1
Get fn, , EntryCount_Byte
EntryCount_16 = Hex(Format(EntryCount_Byte(0), "00")) & Hex(Format(EntryCount_Byte(1), "00"))
EntryCount_10 = Abs("&H" & EntryCount_16)
If EntryCount_10 > 0 Then
ReDim Tag(1 To EntryCount_10)
Get fn, , Tag
End If
Loop
Close fn
GetPageNumber_Motorola = pagecount
End Function
TIFFファイル仕様
コードを解説する前にTIFFファイルの仕様をある程度理解しておかなければ、VBAコードを読み取り、理解することができません。TIFFファイルの仕様については本も出ていますが、以下のサイトに日本語で網羅されております。わざわざ英語のTIFF仕様を読まずとも日本語で詳しく丁寧に解説されており、TIFFファイル仕様を知るには非常に役立つサイトだと思います。本当にこのサイトが存在してくれていたお陰でTIFF仕様を学ぶ機会を得ることができました。
以下で備忘記録のため、TIFFファイル仕様について解説していますが、参照元はほぼ我楽多頓陳館さんのホームページから自分なりに読み解き、TIFFの枚数をカウントするために解説している仕様解説内容となっております。なるべく誤解がない状態で解説しているつもりですが、私の解説で矛盾点があったり、よく分からない内容があれば、上記サイトでTIFF仕様を確認していただいても良いと思います。
バイナリエディタ
バイナリデータを閲覧するには、バイナリエディタが役立ちます。世の中、色々なバイナリエディタがある様ですが、私はBinary Editor BZを利用しています。Vectorや窓の杜で入手することができます。バイナリエディタでTIFFファイルを開くと以下のイメージになります。1コマに各々16進法でデータが表示されています。1コマ毎にAsciiに変換した文字列が右側に表示されており、バイトオーダ(後述)位でしたら、バイナリエディタで確認することができます。
TIFF仕様概要
TIFFのデータはバイナリデータに属しており、データは複数のブロックに役割が分かれています。
ファイルヘッダ |
IFD |
~ |
画像関連データ |
カラーマップ |
イメージデータ |
TIFFファイルのブロック構成を左記に載せておきます。
ファイルヘッダは必ずTIFFファイルの先頭に位置しています。それ以外のブロックは基本的にどこに位置しても良い仕様となっています。
TIFFファイルの枚数をカウントするためには、ヘッダ情報とIFD(Image File Directory)の情報取得する必要があります。
ファイルヘッダ
前述のとおり、ファイルヘッダは必ずTIFFファイルの先頭に位置しています。バイナリエディタでTIFFファイルを開くと、先頭8Byteの範囲でファイルヘッダの情報を確認することができます。1ファイルに複数ページをまとめることができるマルチTIFFでもファイルヘッダは一つしかありません。
ファイルヘッダ |
IFD |
~ |
画像関連データ |
カラーマップ |
イメージデータ |
内容 | バイト数 | 取得値 |
---|---|---|
バイトオーダー | 2 | "MM"(4D4DH)または"II"(4949H) |
バージョン番号 | 2 | 固定値42 |
IFDポインタ | 4 | 先頭IFDへのバイト単位のオフセット値 |
- バイトオーダー
-
TIFFファイルがMotorola型(リトルエンディアン)かIntel型(ビックエンディアン)かを示します。
・Motorola型 ⇒ "MM"(4D4DH)を表示
・Intel型 ⇒ "II"(4949H)を表示 - バージョン番号
-
TIFFファイル固有の値が表示されます。2AH(42)が固定値となっています。したがって、この数値が42以外の場合、そのファイルはTIFFファイルではない、ということになります。
- IFDポインタ
-
先頭IFDへのバイト単位のオフセット値が表示されます。表示されているByte位置に変遷し、IFD情報を取得していきます。
IFD(Image File Directory)
IFDの情報を取得することで、TIFFファイルのプロパティ情報(縦幅、横幅、圧縮方式等)を取得することができます。また、IFDポインタを読み取ることで、複数ページのマルチTIFFの情報を読み込むことができます。
ファイルヘッダ |
IFD |
~ |
画像関連データ |
カラーマップ |
イメージデータ |
内容 | バイト数 | 取得値 |
---|---|---|
エントリーカウント | 2 | 1-65535(取得値 = n) |
IFDエントリー(1番) | 12 | 1番目のIFDエントリ(プロパティ情報) |
IFDエントリー(2番) | 12 | 2番目のIFDエントリ(プロパティ情報) |
~中略~ | ||
IFDエントリー(n-1番) | 12 | n-1番目のIFDエントリ(プロパティ情報) |
IFDエントリー(n番) | 12 | n番目のIFDエントリ(プロパティ情報) |
IFDポインタ | 4 | 次のIFDへのバイト単位のオフセット値 |
- エントリーカウント
-
IFDに含まれるエントリー(プロパティ)数が表示されています。例えば、エントリー数を20で取得した場合、バイナリーエディタでエントリーカウントの次に表示されるIFDエントリー情報(12Byte)が20種類表示されます。エントリー数はそのままプロパティ数と読み替えても良いと思います。エントリー数の範囲は、1-65535(n番)となっています。いくつか試しにエントリー数を見てみたところ、20個以内に収まる程度のエントリー数が大半でした。
- IFDエントリー
-
TIFFに記録されているエントリー(プロパティ)情報を表示します。
内容 バイト数 取得値 タグコード 2 254以上の必須タグと選択タグのコード データ型 2 1~12のデータ型コード カウントフィールド 4 データフィールドに含まれる値の数 データフィールドまたはデータポインタ 4 データの値または、データオフセット値 - IFDポインタ
-
次のIFDへのバイト単位のオフセット値が表示されます。マルチTIFFで複数ページが1ファイルに存在する場合、1ページ目のIFD情報を取得後、このIFDポインタの情報で2ページ目のIFD情報へ変遷することができます。このポインタがあるお陰でページ数をカウントすることが可能になります。
次のIFDがない場合は0が表示されます。つまり、ページ数はこれ以上カウントできないため、ページ数のカウントを終了することができます。
バイナリデータ例(Motorola型)
Motorola型のバイナリデータ例を紹介します。Intel型は、Byteの並びが逆になりますのでご注意ください。
ファイルヘッダ
バイトオーダー | バージョン番号 | IFDポインタ | |||||
---|---|---|---|---|---|---|---|
4D | 4D | 00 | 2A | 00 | 00 | 00 | 08 |
MM | 42 | 08 |
IFD
- エントリーカウント
-
カウント数 00 0F 15 - IFDエントリー
-
タグ番号 データ型 カウントフィールド データフィールド IFDエントリー1 00 FE 00 04 00 00 00 01 00 00 00 00 NewSubfileType 254 04 01 00 IFDエントリー2 01 00 00 04 00 00 00 01 00 00 02 80 ImageWidth 256 04 01 640 IFDエントリー3 01 01 00 04 00 00 00 01 00 00 01 E0 ImageLength 257 04 01 480 IFDエントリー4 01 02 00 04 00 00 00 01 00 08 00 00 BitsPerSample 258 04 01 524288 IFDエントリー5 01 00 00 03 00 00 00 01 00 05 00 00 Compression 259 03 01 327680 IFDエントリー6 01 06 00 03 00 00 00 01 00 03 00 00 PhotometricInterpretation 262 03 01 196608 IFDエントリー7 01 11 00 04 00 00 00 14 00 00 00 D2 StripOffsets 273 04 20 210 IFDエントリー8 01 15 00 03 00 00 00 01 00 01 00 00 SamplesPerPixel 277 03 01 65536 IFDエントリー9 01 16 00 04 00 00 00 01 00 00 00 19 RowsPerStrip 278 04 01 25 IFDエントリー10 01 17 00 04 00 00 00 14 00 00 01 22 StripByteCounts 279 04 20 290 IFDエントリー11 01 1A 00 04 00 00 00 01 00 00 00 C2 Xresolusion 282 04 01 194 IFDエントリー12 01 1B 00 05 00 00 00 01 00 00 00 CA Yresolusion 283 05 01 202 IFDエントリー13 01 1C 00 05 00 00 00 01 00 01 00 00 PlanarConfiguration 284 05 01 65536 IFDエントリー14 01 28 00 05 00 00 00 01 00 02 00 00 ResolutionUnit 296 05 01 131072 IFDエントリー15 01 40 00 05 00 00 03 00 00 00 01 72 ColorMap 320 05 768 370 - IFDポインタ
-
オフセット値 00 00 00 00 00
コード解説
TIFFの仕様を踏まえて、VBA構文のコード解説をしていきます。
宣言文
宣言セクションで変数をいくつか設定します。特にユーザ定義型変数の設定は今回のコード実行の味噌になるキーワードになります。
Private fn
Type FileHeader
ByteOrder As String * 2
VersionNum(1) As Byte
End Type
Type Entry_IFD
TagType(0 To 1) As Byte
DataType(0 To 1) As Byte
DataCount(0 To 3) As Byte
Data(0 To 3) As Byte
End Type
- fn
-
freefileのファイルナンバーとして、各プロシージャでそのまま使うため宣言(引数で渡すのが面倒だった。。)
- FileHeader
-
TIFFのファイルヘッダ情報(計4Byte)をユーザ定義型で宣言
ByteOrder As String * 2 ⇐ * 2 で2文字(2Byte)を宣言
VersionNum(1) As Byte ⇐ 配列設定で2Byteを宣言ファイルヘッダ 内容 宣言文 Byte数 バイトオーダー "MM" or "II"が設定 ByteOrder As String * 2 2 バージョン番号 TIFFファイルは、固定値42 VersionNum(1) As Byte 2 IFDポインタ(別箇所で宣言) IFDへのオフセット値 4 - Entry_IFD
-
IFDエントリで使用されているByte数(計12Byte)をユーザ定義型で宣言
IFDエントリ内訳 内容 宣言文 Byte数 タグ TIFFファイルのプロパティ情報を示すタグコード TagType(0 To 1) As Byte 2 データの型 1~12のデータ型コード DataType(0 To 1) As Byte 2 カウントフィールド データフィールドに含まれる値の数 DataCount(0 To 3) As Byte 4 データフィールドまたはデータポインタ 各種データまたは
バイト単位のオフセット値Data(0 To 3) As Byte 4
Get_TiffPage
マクロ実行用のプロシージャです。シートA列に入力されたフルパスをGetPageNumber関数に引き渡します。
Sub Get_TiffPage()
Dim TargetRow As Long, maxrow As Long
maxrow = Sheet1.Cells(Rows.Count, 1).End(xlUp).Row
For TargetRow = 2 To maxrow
Sheet1.Cells(TargetRow, 2) = GetPageNumber(Sheet1.Cells(TargetRow, 1))
Next TargetRow
End Sub
GetPageNumber
対象のTIFFファイルがMotorola型(リトルエンディアン)かIntel型(ビックエンディアン)か判別し、型に応じて異なる計算実行用関数に引き渡します。
Function GetPageNumber(TiffFileName As String)
Dim header As FileHeader
fn = FreeFile
Open TiffFileName For Binary As fn
Get fn, , header
Select Case header.ByteOrder
Case "II"
Close fn
GetPageNumber = GetPageNumber_Intel(TiffFileName)
Case "MM"
Close fn
GetPageNumber = GetPageNumber_Motorola(TiffFileName)
Case Else
Close fn
Err.Raise 9999, , "Exception ByteOrder"
End Select
End Function
- 2行目
-
FileHeader型を宣言。4ByteをFileHeader型で取得できる様になります。
- 3行目
-
ファイルナンバー(fn)をFreeFile関数で取得。重複で開くことはしないので、1が入力される。
- 4行目
-
バイナリモードでTIFFファイルを開く
- 5行目
-
header変数にてTIFFファイル先頭の4Byte(ファイルヘッダ)を取得。
最初の2Byteは、バイトオーダ("MM" or "II")を取得。
次の2Byteは、TIFFバージョン番号(42)を取得。 - 7~17行目
-
取得したバイトオーダによって処理を条件分岐します。何れの処理でも一度ファイルを閉じます。バイトオーダがMotorola型かIntel型で計算実行用の関数の種類を分けます。(GetPageNumber_Intel or GetPageNumber_Motorola)
TIFFファイル以外のファイルが該当する場合はエラーを出し、一度処理をストップします。
GetPageNumber_Intel
GetPageNumber関数の条件分岐でバイトオーダが"II"(Intel型)だった場合、こちらの関数でページ数を計算実行します。ビックエンディアンの方が値取得をLong型でそのまま取得ができるので、計算は楽です。
Function GetPageNumber_Intel(TiffFileName As String)
Dim header As FileHeader
Dim EntryCount As Integer, Tag() As Entry_IFD, NextIFD As Long
Dim pagecount As Long
Dim j As Long
fn = FreeFile
Open TiffFileName For Binary As fn
Get fn, , header
If header.VersionNum(0) <> 42 Then
Close fn
Err.Raise 9999, , "This is not TiffFile"
Exit Function
End If
pagecount = 0
Do Until EOF(fn)
Get fn, , NextIFD
If NextIFD = 0 Then Exit Do
Seek #fn, NextIFD + 1
pagecount = pagecount + 1
Get fn, , EntryCount
If EntryCount > 0 Then
ReDim Tag(1 To EntryCount)
Get fn, , Tag
End If
Loop
Close fn
GetPageNumber_Intel = pagecount
End Function
- 2~4行目
-
この構文で重要な変数を宣言。詳細は以下テーブル参照
項目 宣言文 バイト数 宣言内容 ファイルヘッダ header As FileHeader 4 FileHeader型を宣言。4Byteを割当。 エントリーカウント EntryCount As Integer 2 IFDエントリーカウント用の変数宣言。Integer型のByte数である2Byteを割当。 IFDエントリー Tag() As Entry_IFD 12 Entry_IFD型の宣言。ユーザ定義しているIFDエントリ変数を宣言。計12Byteを割当。 IFDポインタ NextIFD As Long 4 最初の取得:ファイルヘッダのIFDポインタ
2回目以降:IFD情報内の最後にあるIFDポインタ
Long型のByte数である4Byteを割当。ページ数 pagecount As Long ページカウント用の変数。バイナリデータ参照用ではないため、Byte数は特に意識する必要なし。 - 7~9行目
-
fn変数にfreefile関数でファイルナンバーを入力(=1)
TIFFファイルをバイナリモードで開く。
ファイルヘッダ情報(先頭4Byte分)を取得。 - 11~15行目
-
TIFFファイルのバージョン番号(=42)を確認。TIFFファイルを示す固有値42以外の場合は、TIFFファイルではないので、エラー発生させ処理終了。
- 17~29行目
-
ページカウントの実行。IFDポインタを取得する度にページ数を1カウントしている。IFDポインタが0を取得すれば、これ以上ページ数がないため、処理終了。
- (19行目)
-
・ループ処理初回
既に9行目の処理で先頭4Byteは取得しているため、続いてIFDポインタ4Byte分を取得。バイナリデータを直前で取得した所からデータ取得ができるため、Seek関数を利用する必要はない。
・ループ処理2回目以降
IFDエントリーを全て取得後、最後に残っているIFDポインタ4Byte分を取得。ここで、0を取得した時にページカウントが終了する。(20行目処理) - (21行目)
-
Seek関数でIFDポインタで取得した「オフセット値+1」分のByte数をバイナリデータ上で移動する。この位置からIFD情報が取得できる。
- (23行目)
-
Seek関数で移動した先の先頭にあるエントリーカウント2Byte分を取得。
- (25行目)
-
取得したエントリーカウントでTag変数(動的配列)を再度宣言。
- (26行目)
-
IFDエントリーを「12Byte × エントリーカウント」分取得。
言葉だけでは説明が分かりにくい方は、以下のアコーディオンブロックでTIFF仕様まとめを載せておきますので、必要に応じでクリックで開いてByte数を比較しながら確認ください。
TIFF仕様まとめ
- ファイルヘッダ
-
スクロールできます
ファイルヘッダ IFD ~ 画像関連データ カラーマップ イメージデータ 内容 バイト数 取得値 バイトオーダー 2 "MM"(4D4DH)または"II"(4949H) バージョン番号 2 固定値42 IFDポインタ 4 先頭IFDへのバイト単位のオフセット値 - IFD
-
スクロールできます
ファイルヘッダ IFD ~ 画像関連データ カラーマップ イメージデータ 内容 バイト数 取得値 エントリーカウント 2 1-65535(取得値 = n) IFDエントリー(1番) 12 1番目のIFDエントリ(プロパティ情報) IFDエントリー(2番) 12 2番目のIFDエントリ(プロパティ情報) ~中略~ IFDエントリー(n-1番) 12 n-1番目のIFDエントリ(プロパティ情報) IFDエントリー(n番) 12 n番目のIFDエントリ(プロパティ情報) IFDポインタ 4 次のIFDへのバイト単位のオフセット値 - IFDエントリー
-
内容 バイト数 取得値 タグコード 2 254以上の必須タグと選択タグのコード データ型 2 1~12のデータ型コード カウントフィールド 4 データフィールドに含まれる値の数 データフィールドまたはデータポインタ 4 データの値または、データオフセット値
GetPageNumber_Motorola
GetPageNumber関数の条件分岐でバイトオーダが"MM"(Motorola型)だった場合、こちらの関数でページ数を計算実行します。リトルエンディアンの場合、値取得を一度Byte毎で取得後、配列を並び直しする必要があります。
Function GetPageNumber_Motorola(TiffFileName As String)
Dim EntryCount_Byte(1) As Byte, EntryCount_10 As Long, EntryCount_16 As String, Tag() As Entry_IFD
Dim NextIFD_10 As Long, NextIFD_16 As String
Dim IFDByte(3) As Byte
Dim header As FileHeader
Dim j As Long
Dim pagecount As Long
fn = FreeFile
Open TiffFileName For Binary As fn
Get fn, , header
If header.VersionNum(1) <> 42 Then
Close fn
Err.Raise 9999, , "This is not TiffFile"
Exit Function
End If
pagecount = 0
Do Until EOF(fn)
Get fn, , IFDByte
NextIFD_16 = Hex(Format(IFDByte(0), "00")) & Hex(Format(IFDByte(1), "00")) & _
Hex(Format(IFDByte(2), "00")) & Hex(Format(IFDByte(3), "00"))
NextIFD_10 = Abs("&H" & NextIFD_16)
If NextIFD_10 = 0 Then Exit Do
Seek #fn, NextIFD_10 + 1
pagecount = pagecount + 1
Get fn, , EntryCount_Byte
EntryCount_16 = Hex(Format(EntryCount_Byte(0), "00")) & Hex(Format(EntryCount_Byte(1), "00"))
EntryCount_10 = Abs("&H" & EntryCount_16)
If EntryCount_10 > 0 Then
ReDim Tag(1 To EntryCount_10)
Get fn, , Tag
End If
Loop
Close fn
GetPageNumber_Motorola = pagecount
End Function
- 2~7行目
-
この構文で重要な変数を宣言。詳細は以下テーブル参照
項目 宣言文 バイト数 宣言内容 ファイルヘッダ header As FileHeader 4 FileHeader型を宣言。4Byteを割当。 エントリーカウント(Byte) EntryCount_Byte(1) As Byte 2 IFDエントリーカウント用の変数宣言。1Byteずつ配列に代入できる様にして2Byteを割当。
EntryCount_Byte⇒EntryCount_16(16進法)⇒EntryCount_10(10進法)の順に値を変換エントリーカウント(10進法) EntryCount_10 As Long EntryCount_16で表示した16進法の取得値を10進法に表示させるための変数。バイナリデータからの値取得は、EntryCount_Byteで取得するため、バイト数は意識する必要なし。 エントリーカウント(16進法) EntryCount_16 As String EntryCount_Byteで取得したByteデータをつなぎ合わせ、16進法表示させるための変数。バイナリデータからの値取得は、EntryCount_Byteで取得するため、バイト数は意識する必要なし。 IFDエントリー Tag() As Entry_IFD 12 Entry_IFD型の宣言。ユーザ定義しているIFDエントリ変数を宣言。計12Byteを割当。 IFDポインタ(Byte) IFDByte(3) As Byte 4 最初の取得:ファイルヘッダのIFDポインタ
2回目以降:IFD情報内の最後にあるIFDポインタ
配列で4要素分を確保して、4Byteを割当。IFDポインタ(16進法) NextIFD_16 As String IFDByteで取得したByteデータをつなぎ合わせ、16進法表示させるための変数。バイナリデータからの値取得は、IFDByteで取得するため、バイト数は意識する必要なし。 IFDポインタ(10進法) NextIFD_10 As Long NextIFD_16で表示した16進法の取得値を10進法に表示させるための変数。バイナリデータからの値取得は、IFDByteで取得するため、バイト数は意識する必要なし。 ページ数 pagecount As Long ページカウント用の変数。バイナリデータ参照用ではないため、Byte数は特に意識する必要なし。 - 9~11行目
-
fn変数にfreefile関数でファイルナンバーを入力(=1)
TIFFファイルをバイナリモードで開く。
ファイルヘッダ情報(先頭4Byte分)を取得。 - 13~17行目
-
TIFFファイルのバージョン番号(=42)を確認。TIFFファイルを示す固有値42以外の場合は、TIFFファイルではないので、エラー発生させ処理終了。
- 19~36行目
-
ページカウントの実行。IFDポインタを取得する度にページ数を1カウントしている。IFDポインタが0を取得すれば、これ以上ページ数がないため、処理終了。
- (21行目)
-
・ループ処理初回
既に9行目の処理で先頭4Byteは取得しているため、続いてIFDポインタ4Byte分を取得。バイナリデータを直前で取得した所からデータ取得ができるため、Seek関数を利用する必要はない。
・ループ処理2回目以降
IFDエントリーを全て取得後、最後に残っているIFDポインタ4Byte分を取得。ここで、0を取得した時にページカウントが終了する。(20行目処理) - (22~24行目)
-
IFDをByte単位で取得⇒16進法の値に変換⇒10進法の値に変換する。
Seek関数にて10進法表示のIFDポインタで取得した「オフセット値+1」分のByte数をバイナリデータ上で移動する。この位置からIFD情報が取得できる。 - (29行目)
-
Seek関数で移動した先の先頭にあるエントリーカウント2Byte分を取得。
- (33行目)
-
取得したエントリーカウントでTag変数(動的配列)を再度宣言。
- (34行目)
-
IFDエントリーを「12Byte × エントリーカウント」分取得。
言葉だけでは説明が分かりにくい方は、以下のアコーディオンブロックでTIFF仕様まとめを載せておきますので、必要に応じでクリックで開いてByte数を比較しながら確認ください。
TIFF仕様まとめ
- ファイルヘッダ
-
スクロールできます
ファイルヘッダ IFD ~ 画像関連データ カラーマップ イメージデータ 内容 バイト数 取得値 バイトオーダー 2 "MM"(4D4DH)または"II"(4949H) バージョン番号 2 固定値42 IFDポインタ 4 先頭IFDへのバイト単位のオフセット値 - IFD
-
スクロールできます
ファイルヘッダ IFD ~ 画像関連データ カラーマップ イメージデータ 内容 バイト数 取得値 エントリーカウント 2 1-65535(取得値 = n) IFDエントリー(1番) 12 1番目のIFDエントリ(プロパティ情報) IFDエントリー(2番) 12 2番目のIFDエントリ(プロパティ情報) ~中略~ IFDエントリー(n-1番) 12 n-1番目のIFDエントリ(プロパティ情報) IFDエントリー(n番) 12 n番目のIFDエントリ(プロパティ情報) IFDポインタ 4 次のIFDへのバイト単位のオフセット値 - IFDエントリー
-
内容 バイト数 取得値 タグコード 2 254以上の必須タグと選択タグのコード データ型 2 1~12のデータ型コード カウントフィールド 4 データフィールドに含まれる値の数 データフィールドまたはデータポインタ 4 データの値または、データオフセット値