TIFFメタデータ形式の仕様と使用上の注意

イメージを読む イメージを書く
ネイティブ・ストリーム・メタデータ形式
ネイティブ・イメージ・メタデータ形式

イメージを読む

TIFFイメージはImageReaderによって読み取られます。ImageReaderは、公開されたTIFFImageReadParamを介して公開されているインタフェースと同様に制御されます。

色変換

ソース・イメージ・データにフォト・メトリック・タイプCIE L*a*b*またはYCbCrがあり、宛先カラー・スペース・タイプがRGBの場合、ソース・イメージ・データは内部カラー・コンバータを使用してRGBに自動的に変換されます。

カラー・スペース

デフォルトで割り当てられる未処理のカラー・スペース(つまり、ユーザー指定のImageTypeSpecifierがない場合)は、次のうち最初に適用されます:
  • 「ICCプロファイル」メタデータ・フィールド(存在し、イメージ・データ・レイアウトと互換性がある場合)から作成されるカラー・スペース。
  • イメージがモノクロ/バイレベル(内部的に2レベルのカラー・マップが作成されます)の場合はsRGB。
  • イメージがパレット色の場合、sRGB。
  • イメージにピクセル当たり3つのサンプルがある場合、フォト・メトリック・タイプCIE L*a*b*がある場合、またはフォト・メトリック・タイプYCbCrがあり、JPEG圧縮されていない場合、リニアRGB。
  • イメージにフォト・メトリック・タイプCMYKおよびピクセル当たり4つのサンプルがある場合、「デフォルトのCMYKカラー・スペース」
  • イメージに1ピクセル当たり1つまたは2つのサンプルがあり、1サンプル当たり1、2、4、8、16または32ビットが均一である場合、または浮動小数点である場合、グレースケール。
  • sRGBイメージに1ピクセルあたり3つまたは4つのサンプルがあり、サンプルあたり1、2、4、8、16、または32ビットが均一である場合、または浮動小数点である場合。
  • イメージに1ピクセル当たり4つ以上のサンプルがあり、すべてのバンドの1サンプル当たりのビット数が同じで、8の倍数である場合は、「汎用カラー・スペース」が作成されます。
  • サンプル当たりのビット数に関係なく、イメージに1ピクセル当たり1つまたは2つのサンプルがある場合はグレースケールします。
  • サンプル当たりのビット数に関係なく、イメージに1ピクセル当たり3つまたは4つのサンプルがある場合、sRGB。
  • 作成された「汎用カラー・スペース」(イメージに、サンプル当たりのビット数に関係なく、1ピクセル当たり4つ以上のサンプルが含まれる場合)。

デフォルトのCMYK色空間に使用される正規化色座標変換は、次のように定義されます:

  • CMYKからリニアRGB
    R = (1 - K)*(1 - C)
    G = (1 - K)*(1 - M)
    B = (1 - K)*(1 - Y)
    
  • リニアRGBからCMYK
    K = min{1 - R, 1 - G, 1 - B}
    if(K != 1) {
        C = (1 - R - K)/(1 - K)
        M = (1 - G - K)/(1 - K)
        Y = (1 - B - K)/(1 - K)
    } else {
        C = M = Y = 0
    }
    

他の色空間が推測されない場合に使用される一般的な色空間は、単にデータが読み込まれるようにするために提供されます。 あらゆる種類の正確な変換を提供するためのものではありません。

データが、前述のデータによって正しく処理されないカラー・スペースにあることが判明している場合は、ImageTypeSpecifierをリーダーに提供し、該当するデータに適したカラー・スペースから導出する必要があります。

ICCプロファイル

ICCプロファイルがイメージ・メタデータ(BaselineTIFFTagSet)に含まれている場合。 TAG_ICC_PROFILE、タグ番号34675)。ロードされたイメージのカラー・スペースの作成に使用されます。 データ・レイアウトがコンポーネント・タイプで、ピクセル当たりのサンプル数がICCプロファイルによって記述されたコンポーネント数以上である場合、または1より大きい場合に使用されます。 ICCプロファイルが使用されない場合、色空間はaboveで説明された後続のステップの1つで推定されます。

なんらかの理由で埋め込まれたICCプロファイルが自動的に使用されない場合は、この手順に従って手動で使用できます:

  1. ImageReader.getImageMetadataからイメージ・メタデータを取得
  2. ICCプロファイル・フィールドとその値を抽出します。
  3. ICC_Profile.getInstance(byte[])を使用して、ICCプロファイル・フィールド・データから作成されたICC_ProfileからICC_ColorSpaceを作成します。
  4. ICC_ColorSpaceを受け入れるファクトリ・メソッドの1つを使用して、新しい色空間からImageTypeSpecifierを作成します。
  5. 互換性のあるImageReadParamを作成し、ImageReadParam.setDestinationTypeを使用してImageTypeSpecifierを設定します。
  6. パラメータ・オブジェクトを適切なreadメソッドに渡します。

「ICCプロファイル」フィールドに基づかない推測色スペースがICCプロファイル・ベースのカラー・スペースと互換性がある場合は、推測されるこのカラー・スペースから導出される2番目のImageTypeSpecifierが、ImageReader.getImageTypesから返されるIteratorに含まれます。 イテレータに複数のタイプが含まれている場合、最初のタイプはICCプロファイルに基づき、2番目のタイプは推測カラー空間に基づきます。

メタデータの問題

デフォルトでは、TIFFイメージ・ファイル・ディレクトリ(IFD)で認識されるすべてのフィールドが、ネイティブ・イメージ・メタデータ・オブジェクトにロードされます。 ロードされるフィールドは、リーダーが認識できるTIFFタグ、認識できないタグを持つフィールドを読み取るかどうか、およびすべてのメタデータを無視するかどうかを設定することで制御できます。 読者は、ImageReader.setInput(Object,boolean,boolean)ignoreMetadataパラメータを介して、通常どおりすべてのメタデータを無視するように通知されます。 TIFFImageReadParam.addAllowedTagSet(TIFFTagSet)およびTIFFImageReadParam.removeAllowedTagSet(TIFFTagSet)を介して認識するかどうかは、どのTIFFTagに通知されます。 ignoreMetadatatrueの場合、イメージの読取りに不可欠なメタデータのみがネイティブ・イメージ・メタデータ・オブジェクトにロードされます。 ignoreMetadatafalseの場合、リーダーはデフォルトでネイティブ・イメージ・メタデータ・オブジェクトに、イメージの読取りに不可欠なフィールド、または許可されたTIFFTagSetの1つにTIFFTagが含まれているフィールドのみをロードします。 TIFFImageReadParam.setReadUnknownTags(boolean)がパラメータtrueで呼び出されたTIFFImageReadParamを渡すことによって、許可されたTIFFTagSetにないタグを持つフィールドの読み取りを強制することができます。

TIFFDirectoryオブジェクトを使用すると、メタデータ値へのアクセスが簡単になります。 TIFFDirectoryのインスタンスは、TIFFDirectory.createFromMetadataメソッドを使用して、TIFFリーダーによって返されたIIOMetadataオブジェクトから作成できます。

TIFFネイティブ・イメージ・メタデータの標準メタデータ・フォーマットへのマッピング

次の表に、「TIFFネイティブ・イメージ・メタデータ」からの標準メタデータ形式のjavax_imageio_1.0要素の導出を示します。
索引 標準メタデータ要素 TIFFフィールドからの派生
1 /Chroma/ColorSpaceType@name PhotometricInterpretation: WhiteIsZero、BlackIsZero、TransparencyMask = "GRAY"、RGB、PaletteColor => "RGB"、CMYK => "CMYK"、YCbCr => "YCbCr"、CIELab、ICCLab => "Lab"。
2 /Chroma/NumChannels@value SamplesPerPixel
3 /Chroma/BlackIsZero@value "TRUE" <=> PhotometricInterpretation => WhiteIsZero
4 /Chroma/Palette ColorMap
5 /Compression/CompressionTypeName@value 圧縮: 非圧縮=> "none"; CCITT 1D => "CCITT RLE";グループ3 FAX => "CCITT T.4";グループ4 FAX => "CCITT T.6"; LZW => "LZW"; JPEG => "Old JPEG";新規JPEG => "JPEG"; Zlib => "ZLib"; PackBits => "PackBits"; Deflate => "Deflate"; Exif JPEG => "JPEG"。
6 /Compression/Lossless@value 圧縮: JPEGまたは新しいJPEG => "FALSE"; そうでなければ"TRUE"。
7 /Data/PlanarConfiguration@value Chunky => "PixelInterleaved"; Planar => "PlaneInterleaved"。
8 /Data/SampleFormat@value PhotometricInterpretation PaletteColor => "Index" ; SampleFormat unsigned integer data => "UnsignedIntegral" ; SampleFormat two's complement signed integer data => "SignedIntegral" ; SampleFormat IEEE floating point data => "Real" ;それ以外の場合、要素は発行されません。
9 /Data/BitsPerSample@value スペース区切りのリストとしてBitsPerSample。
10 /Data/SampleMSB@value FillOrder: 左から右=> BitsPerSample-1のスペース区切りリスト。右から左=> 0のスペース区切りリスト。
11 /Dimension/PixelAspectRatio@value (1/XResolution)/(1/YResolution)
12 /Dimension/ImageOrientation@value 概要
13 /Dimension/HorizontalPixelSize@value ResolutionUnitがNoneでない場合は、1/XResolution(ミリメートル)。
14 /Dimension/VerticalPixelSize@value ResolutionUnitがNoneでない場合は、1/YResolution(ミリメートル)。
15 /Dimension/HorizontalPosition@value ResolutionUnitがNoneでない場合は、XPosition(ミリメートル)。
16 /Dimension/VerticalPosition@value ResolutionUnitがNoneでない場合は、YPosition(ミリメートル)。
17 /Document/FormatVersion@value 6.0
18 /Document/SubimageInterpretation@value NewSubFileType: 透明度=> "TransparencyMask"; 縮小解像度=> "ReducedResolution"; シングル・ページ=> "SinglePage"。
19 /Document/ImageCreationTime@value DateTime
20 /Text/TextEntry DocumentName、ImageDescription、Make、Model、PageName、Software、Artist、HostComputer、InkNames、Copyright: /Text/TextEntry@keyword = フィールド名、/Text/TextEntry@value = フィールド値。
例: 「TIFFソフトウェア」フィールド=> /Text/TextEntry@keyword = "Software"、/Text/TextEntry@value = イメージの作成に使用されるsoftwarepackage(s)の名前およびバージョン番号。
21 /Transparency/Alpha@value ExtraSamples: 関連するアルファ => "premultiplied"; 関連しないアルファ=> "nonpremultiplied"。

Exifイメージを読む

TIFFリーダーを使用して、圧縮されていないExifイメージ、または圧縮されたExifイメージのAPP1マーカー・セグメントの内容を読み取ることができます。

解凍したExifイメージを読む

非圧縮Exifイメージは、IFDおよびイメージ・データ・コンテンツの特定の順序を持つ1ページまたは2ページの非圧縮TIFFイメージです。 各ピクセルには、フォト・メトリック解釈RGBまたはYCbCrを持つ3つの8ビット・サンプルがあります。 イメージ・ストリームには1つのプライマリ・イメージが含まれている必要があり、存在する場合は圧縮解除も必要となる単一のサムネイルを含めることができます。 通常のImageReaderメソッドを使用して、イメージ・データとメタデータを読み取ることができます:

    ImageInputStream input;
    ImageReader tiffReader;
    ImageReadParam tiffReadParam;

    tiffReader.setInput(input);

    // Read primary image and IFD.
    BufferedImage image = tiffReader.read(0, tiffReadParam);
    IIOMetadata primaryIFD = tiffReader.getImageMetadata(0);

    // Read thumbnail if present.
    BufferedImage thumbnail = null;
    if (tiffReader.getNumImages(true) > 1) {
        thumbnail = tiffReader.read(1, tiffReadParam);
    }
Exifサムネイルは、サムネイルとしてではなく、TIFFストリーム内の個別のページとして扱われます。つまり、tiffReader.hasThumbnails(0)falseを返します。

圧縮されたExifイメージを読む

圧縮されたExifイメージは、APP1マーカー・セグメントが挿入された3バンドISO/IEC 10918-1のベースラインDCT JPEGストリームです。 長さの後のマーカー・セグメントのパラメータは、完全なTIFFストリームに続く6バイトのシーケンス{'E', 'x', 'i', 'f', 0x00, 0x00}です。 埋め込みのTIFFストリームには、オプションで、JPEGイメージの後にサムネイルIFDと圧縮または非圧縮のサムネイル・イメージ・データを記述するプライマリIFDが含まれています。 埋込みTIFFストリームには、プライマリIFDに関連付けられたイメージ・データや、JPEGストリーム自体で見つかった情報を複製する記述フィールドが含まれていないことに注意してください。

APP1マーカー・セグメントのパラメータ内容は、JPEGリーダーによって返されたイメージ・メタデータ・オブジェクトから抽出されたjavax_imageio_jpeg_image_1.0ネイティブ・イメージ・メタデータ・ツリー内の関連するNodeのユーザー・オブジェクトから取得することができます。 このAPP1 Exifノードは、"markerSequence"という名前のノードの子になり、名前unknownと、0xE1 (Stringの値"225")を持つMarkerTagという名前の属性を持ちます。 このノードのユーザー・オブジェクトは、6バイトの{'E', 'x', 'i', 'f', '0', '0'}で始まるバイト配列になります。 プライマリIFDおよびサムネイルIFDおよびイメージは、通常のImageReaderメソッドによってユーザー・オブジェクトから読み取ることができる:


    ImageReader jpegReader;
    ImageReader tiffReader;

    // Obtain the APP1 Exif marker data from the JPEG image metadata.
    IIOMetadata jpegImageMetadata = jpegReader.getImageMetadata(0);
    String nativeFormat = jpegImageMetadata.getNativeMetadataFormatName();
    Node jpegImageMetadataTree = jpegImageMetadata.getAsTree(nativeFormat);

    // getExifMarkerData() returns the byte array which is the user object
    // of the APP1 Exif marker node.
    byte[] app1Params = getExifMarkerData(jpegImageMetadataTree);
    if (app1Params == null) {
        throw new IIOException("APP1 Exif marker not found.");
    }

    // Set up input, skipping Exif ID 6-byte sequence.
    MemoryCacheImageInputStream app1ExifInput
        = new MemoryCacheImageInputStream
            (new ByteArrayInputStream(app1Params, 6, app1Params.length - 6));
    tiffReader.setInput(app1ExifInput);

    // Read primary IFD.
    IIOMetadata primaryIFD = tiffReader.getImageMetadata(0);

    // Read thumbnail if present.
    BufferedImage thumbnail = null;
    if (tiffReader.getNumImages(true) > 1) {
        thumbnail = tiffReader.read(1, tiffReadParam);
    }

    // Read the primary image.
    BufferedImage image = jpegReader.read(0);
tiffReader.getNumImages(true)は、空のイメージに対応するものを含め、埋込みTIFFストリーム内のIFDの数を返します。 tiffReader.read(0, readParam)をコールすると、埋込みTIFFストリームのプライマリ・イメージが常に空であるため、例外がスローされます。プライマリ・イメージは、JPEGリーダー自体を使用して取得する必要があります。

イメージを書く

TIFFイメージは、ImageWriterによって書き込まれます。ImageWriterは、公開されているImageWriteParamを介して公開されているインタフェースと同様に制御されます。 TIFF ImageWritergetDefaultWriteParam()メソッドによって返されたImageWriteParamに対して、canWriteTiles()およびcanWriteCompressed()メソッドはtrueを返します。canOffsetTiles()canWriteProgressive()メソッドはfalseを返します。 TIFFライターは、タイル表示されたイメージの書込み、イメージの挿入、空のイメージの書込みまたは挿入、イメージ・データの置換など、多くのオプション機能をサポートしています。 ピクセルは、空または空でないイメージで置換できますが、データが圧縮されていない場合のみ置換されます。

タイルが書き込まれている場合、各ディメンションは、TIFF仕様ごとに16の最も近い倍数に丸められます。 JPEG-in-TIFF圧縮が使用されていて、タイルが書き込まれている場合、各タイル・ディメンションは、そのディメンションのJPEG最小コード単位(MCU)の8倍の最も近い倍数に丸められます。 JPEG-in-TIFF圧縮が使用され、ストリップが書き込まれている場合、ストリップ当たりの行数は、両方のディメンションで最大MCUの8倍の倍数に丸められます。

圧縮

圧縮モードは、圧縮モードをMODE_EXPLICITに設定した後、ImageWriteParamsetCompressionType()メソッドによって設定することができます。 本来サポートされている圧縮形式のセットを次の表に示します:
サポートされる圧縮タイプ
索引 圧縮タイプ 説明 リファレンス
1 CCITT RLE 修正ハフマン圧縮 TIFF 6.0仕様、セクション10
2 CCITT T.4 CCITT T.4バイレベル符号化/グループ3ファクシミリ圧縮 TIFF 6.0仕様、セクション11
3 CCITT T.6 CCITT T.6バイレベル符号化/グループ4ファクシミリ圧縮 TIFF 6.0仕様、セクション11
4 LZW LZW圧縮 TIFF 6.0仕様、セクション13
5 JPEG "新しい" JPEG-in-TIFF圧縮 TIFFテクニカル・ノート#2
6 ZLib "Deflate/Inflate"圧縮 (この表の後のノートを参照) Adobe Photoshop® TIFFテクニカル・ノート
7 PackBits バイト指向、実行長圧縮 TIFF 6.0仕様、セクション9
8 Deflate "Zip-in-TIFF"圧縮 (この表の後のノートを参照) 「ZLIB圧縮データ・フォーマット仕様」, 「DEFLATE圧縮データ・フォーマット仕様」
9 Exif JPEG Exif固有のJPEG圧縮(この表の後のノートを参照) 「Exif 2.3仕様」 (PDF)、セクション4.5.8、"サムネイル・データの基本構造"

TIFF 6.0仕様のセクション22で説明されている古いスタイルのJPEG圧縮はサポートされていません。

CCITT圧縮タイプは、バイレベル(1-bit)イメージにのみ適用できます。 JPEG圧縮タイプは、バイト・グレースケール(1-band)およびRGB (3-band)イメージにのみ適用できます。

ZLibおよびDeflate圧縮は、「TIFF圧縮」フィールドの値を除いて同じです: ZLibの圧縮フィールドの値は8ですが、Deflateの場合は値32946 (0x80b2)です。 どちらの場合も、各イメージ・セグメント(ストリップまたはタイル)は、単一の完全なzlibデータ・ストリームとして書き込まれます。

"Exif JPEG"は、JPEGネイティブ・イメージ・メタデータ・ツリーに含めるためにAPP1 Exifマーカー・セグメントの内容を記述するときに使用される圧縮タイプです。 この圧縮タイプを使用するときに出力に追加される内容は、空または空でないイメージが書き込まれるかどうかの機能です。 イメージが空の場合、圧縮されたExifプライマリIFDの仕様に準拠するTIFF IFDが追加されます。 イメージが空でない場合、圧縮されたExifサムネイルIFDおよびイメージの指定に付随する完全なIFDおよびイメージが追加されます。 空のイメージのデータは、後でTIFFライターのピクセル置換機能を使用して追加されない場合があります。

ZLib/DeflateまたはJPEG圧縮を使用する場合は、圧縮品質を設定できます。 ZLib/Deflateの場合、指定された浮動小数点の品質値は[1, 9]の範囲に再スケーリングされ、Deflate圧縮レベルを得るために整数に切り捨てられます。 JPEGの場合、浮動小数点の品質値は、通常の方法で解釈するJPEGライター・プラグインに直接渡されます。

色変換

ソース・イメージのデータ・カラー・スペース・タイプがRGBで、宛先フォト・メトリック・タイプがCIE L*a*b*またはYCbCrの場合、ソース・イメージ・データは内部カラー・コンバータを使用してRGBから自動的に変換されます。

ICCプロファイル

次のいずれかの場合、ICC Profileフィールドが書き込まれます:
  • ライターに提供されたネイティブ・イメージ・メタデータIIOMetadataインスタンスに存在するか、
  • 宛先ImageTypeSpecifierColorSpaceは、ColorSpaceクラスのCS_*定数で定義されている標準色空間ではないICC_ColorSpaceのインスタンスです。 宛先タイプはImageWriteParam.setDestinationType(ImageTypeSpecifier)を介して設定され、デフォルトで書き込まれるイメージのImageTypeSpecifierに設定されます。

メタデータの問題

ライターの一部の動作は、ユーザーが提供できるイメージ・メタデータの内容の影響を受けるか、影響を受ける可能性があります。

バイレベル・イメージの場合、FillOrder、およびT4Optionsフィールドは出力データに影響します。 FillOrderの値が2 (BaselineTIFFTagSet.FILL_ORDER_RIGHT_TO_LEFT)の場合、データは右から左に入力され、それ以外の場合は左から右に入力されます。 T4Optionsの値は、データを1Dまたは2Dエンコードする必要があるかどうか、およびEOLパッディングを使用するかどうかを指定します。

すべてのイメージについて、RowsPerStripフィールドの値は、イメージがタイル化されていない場合、ストリップごとの行数を設定するために使用されます。 1ストリップあたりのデフォルト行数は8個、または8キロバイト以下になる行数のいずれか大きい方です。

すべてのイメージについて、タイリング・モードがImageWriteParam.MODE_COPY_FROM_METADATAの場合、TileWidthおよびTileLengthフィールド値を使用してタイル・ディメンションを設定できます。 このモードが設定されているが、フィールドが設定されていない場合、それぞれのデフォルト値はイメージの幅と高さです。

JPEG-in-TIFF圧縮を使用する場合、ライターに提供されたメタデータ・オブジェクトにJPEGTablesフィールドが含まれている場合にのみ、JPEGTablesフィールドがIFDに書き込まれ、JPEGストリームが各ストリップまたはタイルに短縮されます。 JPEGTablesフィールドの内容が有効なテーブルのみのJPEGストリームである場合は、それが使用されます。そうしないと、フィールドの内容はデフォルトの視覚的に無損失の表に置き換えられます。 そのようなJPEGTablesフィールドがメタデータに存在しない場合、JPEGTablesフィールドは出力に書き込まれず、各ストリップまたはタイルは独立した独立したJPEGストリームとして書き込まれます。

Deflate/ZLibまたはLZW圧縮を使用する場合、イメージが8ビット/サンプルの場合、Predictorフィールドの値が2 (BaselineTIFFTagSet.PREDICTOR_HORIZONTAL_DIFFERENCING)の場合、水平差分予測子が使用されます。 予測がリクエストされても、イメージが8ビット/サンプルを持たない場合、フィールドは1 (BaselineTIFFTagSet.PREDICTOR_NONE)の値にリセットされます。

いくつかのフィールドが追加または変更されることがあります:

  • PhotometricInterpretationが存在しない場合。
  • このフィールドが値Planarで存在する場合、PlanarConfigurationChunkyにリセットされます。
  • 常にCompression
  • イメージがバイレベルでない場合はBitsPerSample
  • 常にSamplesPerPixel
  • ExtraSamples (アルファ・チャネルが存在する場合)。
  • SampleFormatが存在しない場合、そのデータは16ビットまたは32ビットの整数または浮動小数点です。
  • PhotometricInterpretationRGBPaletteの場合はColorMap
  • 常にImageWidthImageLengthです。
  • TileWidth, TileLength, TileOffsets、およびタイル化されたイメージが書き込まれている場合はTileByteCounts
  • RowsPerStripStripOffsets、およびStripByteCountsが含まれています。
  • XResolutionYResolution、およびResolutionUnitが存在しない場合。
  • YCbCrSubsamplingYCbCrPositioningのように、測光の解釈がYCbCrで、圧縮のタイプがJPEGでない場合は(JPEG以外のYCbCr出力に対しては、[1, 1]サブサンプリングとサイズ測位のみがサポートされています)です。
  • YCbCrSubsamplingYCbCrPositioning、およびReferenceBlackWhite: 圧縮型がJPEGで色空間がRGBの場合、これらは、ヘッド・ルーム/フットルーム(0:255,128:255,128:255)を持たない[2, 2]中心のサブサンプリングにリセットされます。

いくつかのフィールドが削除されることがあります:

  • イメージがバイレベルの場合はBitsPerSample
  • イメージにアルファ・チャネルがない場合はExtraSamples
  • 測光の解釈がRGBPaletteでない場合はColorMap
  • TileWidth, TileLength, TileOffsets、およびタイルが使用されていない場合はTileByteCounts
  • RowsPerStripStripOffsets、およびStripByteCountsを使用しています。
  • YCbCrSubsamplingYCbCrPositioning、およびReferenceBlackWhiteを指定します。圧縮タイプがJPEGで、色空間がグレースケールの場合。
  • JPEGProc, JPEGInterchangeFormat, JPEGInterchangeFormatLength, JPEGRestartInterval, JPEGLosslessPredictors, JPEGPointTransforms, JPEGQTables, JPEGDCTables、および圧縮タイプがJPEGの場合はJPEGACTables

指定されたメタデータに存在するその他のフィールドは解釈されず、指定されたとおりに書き込まれます。

Exifイメージが書き込まれている場合、結果がExif 2.3仕様と一致するように、存在するフィールドのセットとその値が変更されます。

TIFFストリームに書き込むようにイメージ・メタデータを設定するには、TIFF IFDを表すTIFFDirectoryクラスを使用します。 TIFF IFD内のフィールドは、TIFFFieldのインスタンスで表されます。 書き込まれる各フィールドに対して、TIFFFieldTIFFDirectoryに追加し、後者をTIFFDirectory.getAsMetadataを呼び出してIIOMetadataオブジェクトに変換することができます。 取得されたIIOMetadataオブジェクトは、TIFFライターに渡すことができます。

TIFFネイティブ・イメージ・メタデータへの標準メタデータ・フォーマットのマッピング

次の表に、標準メタデータ形式javax_imageio_1.0からの「TIFFネイティブ・イメージ・メタデータ」要素の導出を示します。
索引 TIFFフィールド 標準メタデータ要素からの派生
1 PhotometricInterpretation /Chroma/ColorSpaceType@name: "GRAY" and /Chroma/BlackIsZero@value = "FALSE" => WhiteIsZero; "GRAY" and /Document/SubimageInterpretation@value = "TransparencyMask" => TransparencyMask; "RGB" and /Chroma/Palette present => PaletteColor; "GRAY" => BlackIsZero; "RGB" => RGB; "YCbCr" => YCbCr; "CMYK" => CMYK; "Lab" => CIELab.
2 SamplesPerPixel /Chroma/NumChannels@value
3 ColorMap /Chroma/Palette
4 Compression /Compression/CompressionTypeName@value: "none" =>非圧縮、"CCITT RLE" => CCITT 1D、"CCITT T.4" => Group 3 Fax、"CCITT T.6" => Group 4 Fax、"LZW" => LZW、"Old JPEG" => JPEG、"JPEG" => New JPEG、"ZLib" => ZLib、"PackBits" => PackBits、"Deflate" => Deflate。
5 PlanarConfiguration /Data/PlanarConfiguration@value: "PixelInterleaved" => Chunky; "PlaneInterleaved" => Planar.
6 SampleFormat /Data/SampleFormat@value: "SignedIntegral" => 2の補数符号付き整数データ、"UnsignedIntegral" =>符号なし整数データ、"Real" => IEEE浮動小数点データ、"Index" =>符号なし整数データ。
7 BitsPerSample /Data/BitsPerSample@value: char配列に解析された空白区切りのリスト。
8 FillOrder /Data/SampleMSB@value: スペース区切りリストのすべての値が0s =>右から左、それ以外の場合は=>左から右です。
9 XResolution (10 / /Dimension/HorizontalPixelSize@value)または(10 / (/Dimension/VerticalPixelSize@value * /Dimension/PixelAspectRatio@value))
10 YResolution (10 / /Dimension/VerticalPixelSize@value)または(10 / (/Dimension/HorizontalPixelSize@value / /Dimension/PixelAspectRatio@value))
11 ResolutionUnit XResolutionまたはYResolutionが設定されている場合はセンチメートル、それ以外の場合はなし。
12 Orientation /Dimension/ImageOrientation@value
13 XPosition /Dimension/HorizontalPosition@value / 10
14 YPosition /Dimension/VerticalPosition@value / 10
15 NewSubFileType /Document/SubimageInterpretation@value: "TransparencyMask" =>透過マスク、"ReducedResolution" =>縮小解像度、"SinglePage" =>単一ページ。
16 DateTime /Document/ImageCreationTime@value
17 DocumentName、ImageDescription、Make、Model、PageName、Software、Artist、HostComputer、InkNames、Copyright /Text/TextEntry: /Text/TextEntry@keywordがいずれかのTIFFフィールドの名前("Software"など)である場合、フィールドはコンテンツ/Text/TextEntry@valueおよびカウント1で追加されます。
18 ExtraSamples /Transparency/Alpha@value: "premultiplied" =>関連するアルファ、カウント1、"nonpremultiplied" =>関連付けられていないアルファ、カウント1。

Exifイメージの作成

TIFFライターを使用して、圧縮されていないExifイメージ、または圧縮されたExifイメージのAPP1マーカー・セグメントの内容を書き込むことができます。

非圧縮Exifイメージの作成

イメージのシーケンスを記述する場合、各イメージは通常 {IFD、IFD Value、Image Data}として記録されます。 Exif仕様では、非圧縮Exifイメージを次のように構成する必要があります:
  1. イメージ・ファイル・ヘッダー
  2. プライマリIFD
  3. プライマリIFD値
  4. サムネイルIFD
  5. サムネイルIFD値
  6. サムネイル・イメージ・データ
  7. プライマリ・イメージ・データ
最後に記録されるプライマリ・イメージ・データの要件を満たすには、プライマリ・イメージを最初に空のイメージとして記述し、サムネイルのIFDおよびイメージ・データが書き込まれた後で、そのデータをピクセル置換によって追加する必要があります:

    ImageWriter tiffWriter;
    ImageWriteParam tiffWriteParam;
    IIOMetadata tiffStreamMetadata;
    IIOMetadata primaryIFD;
    BufferedImage image;
    BufferedImage thumbnail;

    // Specify uncompressed output.
    tiffWriteParam.setCompressionMode(ImageWriteParam.MODE_DISABLED);

    if (thumbnail != null) {
        // Write the TIFF header.
        tiffWriter.prepareWriteSequence(tiffStreamMetadata);

        // Append the primary IFD.
        tiffWriter.prepareInsertEmpty(-1, // append
                new ImageTypeSpecifier(image),
                image.getWidth(),
                image.getHeight(),
                primaryIFD,
                null, // thumbnails
                tiffWriteParam);
        tiffWriter.endInsertEmpty();

        // Append the thumbnail image data.
        tiffWriter.writeToSequence(new IIOImage(thumbnail, null, null),
                tiffWriteParam);

        // Insert the primary image data.
        tiffWriter.prepareReplacePixels(0, new Rectangle(image.getWidth(),
                image.getHeight()));
        tiffWriter.replacePixels(image, tiffWriteParam);
        tiffWriter.endReplacePixels();

        // End writing.
        tiffWriter.endWriteSequence();
    } else {
        // Write only the primary IFD and image data.
        tiffWriter.write(tiffStreamMetadata,
                new IIOImage(image, null, primaryIFD),
                tiffWriteParam);
    }

圧縮されたExifイメージの作成

圧縮されたExifイメージのAPP1セグメント内の埋め込みTIFFストリームの構造は、1次イメージ・データが存在しないことを除いて、「非圧縮Exifイメージ構造」と同じです。つまり、1次IFDはイメージ・データを参照しません。

    ImageWriter tiffWriter;
    ImageWriteParam tiffWriteParam;
    IIOMetadata tiffStreamMetadata;
    BufferedImage image;
    BufferedImage thumbnail;
    IIOMetadata primaryIFD;
    ImageOutputStream output;

    // Set up an output to contain the APP1 Exif TIFF stream.
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    MemoryCacheImageOutputStream app1ExifOutput =
        new MemoryCacheImageOutputStream(baos);
    tiffWriter.setOutput(app1ExifOutput);

    // Set compression for the thumbnail.
    tiffWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
    tiffWriteParam.setCompressionType("Exif JPEG");

    // Write the APP1 Exif TIFF stream.
    if (thumbnail != null) {
        // Write the TIFF header.
        tiffWriter.prepareWriteSequence(tiffStreamMetadata);

        // Append the primary IFD.
        tiffWriter.prepareInsertEmpty(-1, // append
                new ImageTypeSpecifier(image),
                image.getWidth(),
                image.getHeight(),
                primaryIFD,
                null, // thumbnails
                tiffWriteParam);
        tiffWriter.endInsertEmpty();

        // Append the thumbnail IFD and image data.
        tiffWriter.writeToSequence(new IIOImage(thumbnail, null,
                null), tiffWriteParam);

        // End writing.
        tiffWriter.endWriteSequence();
    } else {
        // Write only the primary IFD.
        tiffWriter.prepareWriteEmpty(tiffStreamMetadata,
                new ImageTypeSpecifier(image),
                image.getWidth(),
                image.getHeight(),
                primaryIFD,
                null, // thumbnails
                tiffWriteParam);
        tiffWriter.endWriteEmpty();
    }

    // Flush data into byte stream.
    app1ExifOutput.flush();

    // Create APP1 parameter array.
    byte[] app1Parameters = new byte[6 + baos.size()];

    // Add APP1 Exif ID bytes.
    app1Parameters[0] = (byte) 'E';
    app1Parameters[1] = (byte) 'x';
    app1Parameters[2] = (byte) 'i';
    app1Parameters[3] = (byte) 'f';
    app1Parameters[4] = app1Parameters[5] = (byte) 0;

    // Append TIFF stream to APP1 parameters.
    System.arraycopy(baos.toByteArray(), 0, app1Parameters, 6, baos.size());

    // Create the APP1 Exif node to be added to native JPEG image metadata.
    IIOMetadataNode app1Node = new IIOMetadataNode("unknown");
    app1Node.setAttribute("MarkerTag", String.valueOf(0xE1));
    app1Node.setUserObject(app1Parameters);

    // Append the APP1 Exif marker to the "markerSequence" node.
    IIOMetadata jpegImageMetadata =
        jpegWriter.getDefaultImageMetadata(new ImageTypeSpecifier(image),
            jpegWriteParam);
    String nativeFormat = jpegImageMetadata.getNativeMetadataFormatName();
    Node tree = jpegImageMetadata.getAsTree(nativeFormat);
    NodeList children = tree.getChildNodes();
    int numChildren = children.getLength();
    for (int i = 0; i < numChildren; i++) {
        Node child = children.item(i);
        if (child.getNodeName().equals("markerSequence")) {
            child.appendChild(app1Node);
            break;
        }
    }
    jpegImageMetadata.setFromTree(nativeFormat, tree);

    // Write the JPEG image data including the APP1 Exif marker.
    jpegWriter.setOutput(output);
    jpegWriter.write(new IIOImage(image, null, jpegImageMetadata));
前述で作成した"unknown"ノードは、ネイティブJPEGイメージ・メタデータの"markerSequence"ノードに追加され、プライマリ・イメージがJPEGライターを使用して書き込まれるときにJPEGストリームに書き込まれます。

ストリーム・メタデータ

TIFFネイティブ・ストリーム・メタデータ形式のDTDは次のとおりです:
<!DOCTYPE "javax_imageio_tiff_stream_1.0" [

  <!ELEMENT "javax_imageio_tiff_stream_1.0" (ByteOrder)>

    <!ELEMENT "ByteOrder" EMPTY>
      <!-- The stream byte order -->
      <!ATTLIST "ByteOrder" "value" #CDATA #REQUIRED>
        <!-- One of "BIG_ENDIAN" or "LITTLE_ENDIAN" -->
        <!-- Data type: String -->
]>

イメージ・メタデータ

TIFFネイティブ・イメージ・メタデータ形式のDTDは次のとおりです:
<!DOCTYPE "javax_imageio_tiff_image_1.0" [

  <!ELEMENT "javax_imageio_tiff_image_1.0" (TIFFIFD)*>

    <!ELEMENT "TIFFIFD" (TIFFField | TIFFIFD)*>
      <!-- An IFD (directory) containing fields -->
      <!ATTLIST "TIFFIFD" "tagSets" #CDATA #REQUIRED>
        <!-- Data type: String -->
      <!ATTLIST "TIFFIFD" "parentTagNumber" #CDATA #IMPLIED>
        <!-- The tag number of the field pointing to this IFD -->
        <!-- Data type: Integer -->
      <!ATTLIST "TIFFIFD" "parentTagName" #CDATA #IMPLIED>
        <!-- A mnemonic name for the field pointing to this IFD, if known
             -->
        <!-- Data type: String -->

      <!ELEMENT "TIFFField" (TIFFBytes | TIFFAsciis |
        TIFFShorts | TIFFSShorts | TIFFLongs | TIFFSLongs |
        TIFFRationals | TIFFSRationals |
        TIFFFloats | TIFFDoubles | TIFFUndefined)>
        <!-- A field containing data -->
        <!ATTLIST "TIFFField" "number" #CDATA #REQUIRED>
          <!-- The tag number associated with the field -->
          <!-- Data type: String -->
        <!ATTLIST "TIFFField" "name" #CDATA #IMPLIED>
          <!-- A mnemonic name associated with the field, if known -->
          <!-- Data type: String -->

        <!ELEMENT "TIFFBytes" (TIFFByte)*>
          <!-- A sequence of TIFFByte nodes -->

          <!ELEMENT "TIFFByte" EMPTY>
            <!-- An integral value between 0 and 255 -->
            <!ATTLIST "TIFFByte" "value" #CDATA #IMPLIED>
              <!-- The value -->
              <!-- Data type: String -->
            <!ATTLIST "TIFFByte" "description" #CDATA #IMPLIED>
              <!-- A description, if available -->
              <!-- Data type: String -->

        <!ELEMENT "TIFFAsciis" (TIFFAscii)*>
          <!-- A sequence of TIFFAscii nodes -->

          <!ELEMENT "TIFFAscii" EMPTY>
            <!-- A String value -->
            <!ATTLIST "TIFFAscii" "value" #CDATA #IMPLIED>
              <!-- The value -->
              <!-- Data type: String -->

        <!ELEMENT "TIFFShorts" (TIFFShort)*>
          <!-- A sequence of TIFFShort nodes -->

          <!ELEMENT "TIFFShort" EMPTY>
            <!-- An integral value between 0 and 65535 -->
            <!ATTLIST "TIFFShort" "value" #CDATA #IMPLIED>
              <!-- The value -->
              <!-- Data type: String -->
            <!ATTLIST "TIFFShort" "description" #CDATA #IMPLIED>
              <!-- A description, if available -->
              <!-- Data type: String -->

        <!ELEMENT "TIFFSShorts" (TIFFSShort)*>
          <!-- A sequence of TIFFSShort nodes -->

          <!ELEMENT "TIFFSShort" EMPTY>
            <!-- An integral value between -32768 and 32767 -->
            <!ATTLIST "TIFFSShort" "value" #CDATA #IMPLIED>
              <!-- The value -->
              <!-- Data type: String -->
            <!ATTLIST "TIFFSShort" "description" #CDATA #IMPLIED>
              <!-- A description, if available -->
              <!-- Data type: String -->

        <!ELEMENT "TIFFLongs" (TIFFLong)*>
          <!-- A sequence of TIFFLong nodes -->

          <!ELEMENT "TIFFLong" EMPTY>
            <!-- An integral value between 0 and 4294967295 -->
            <!ATTLIST "TIFFLong" "value" #CDATA #IMPLIED>
              <!-- The value -->
              <!-- Data type: String -->
            <!ATTLIST "TIFFLong" "description" #CDATA #IMPLIED>
              <!-- A description, if available -->
              <!-- Data type: String -->

        <!ELEMENT "TIFFSLongs" (TIFFSLong)*>
          <!-- A sequence of TIFFSLong nodes -->

          <!ELEMENT "TIFFSLong" EMPTY>
            <!-- An integral value between -2147483648 and 2147482647 -->
            <!ATTLIST "TIFFSLong" "value" #CDATA #IMPLIED>
              <!-- The value -->
              <!-- Data type: String -->
            <!ATTLIST "TIFFSLong" "description" #CDATA #IMPLIED>
              <!-- A description, if available -->
              <!-- Data type: String -->

        <!ELEMENT "TIFFRationals" (TIFFRational)*>
          <!-- A sequence of TIFFRational nodes -->

          <!ELEMENT "TIFFRational" EMPTY>
            <!-- A rational value consisting of an unsigned numerator and
                 denominator -->
            <!ATTLIST "TIFFRational" "value" #CDATA #IMPLIED>
              <!-- The numerator and denominator, separated by a slash -->
              <!-- Data type: String -->

        <!ELEMENT "TIFFSRationals" (TIFFSRational)*>
          <!-- A sequence of TIFFSRational nodes -->

          <!ELEMENT "TIFFSRational" EMPTY>
            <!-- A rational value consisting of a signed numerator and
                 denominator -->
            <!ATTLIST "TIFFSRational" "value" #CDATA #IMPLIED>
              <!-- The numerator and denominator, separated by a slash -->
              <!-- Data type: String -->

        <!ELEMENT "TIFFFloats" (TIFFFloat)*>
          <!-- A sequence of TIFFFloat nodes -->

          <!ELEMENT "TIFFFloat" EMPTY>
            <!-- A single-precision floating-point value -->
            <!ATTLIST "TIFFFloat" "value" #CDATA #IMPLIED>
              <!-- The value -->
              <!-- Data type: String -->

        <!ELEMENT "TIFFDoubles" (TIFFDouble)*>
          <!-- A sequence of TIFFDouble nodes -->

          <!ELEMENT "TIFFDouble" EMPTY>
            <!-- A double-precision floating-point value -->
            <!ATTLIST "TIFFDouble" "value" #CDATA #IMPLIED>
              <!-- The value -->
              <!-- Data type: String -->

        <!ELEMENT "TIFFUndefined" EMPTY>
          <!-- Uninterpreted byte data -->
          <!ATTLIST "TIFFUndefined" "value" #CDATA #IMPLIED>
            <!-- A list of comma-separated byte values -->
            <!-- Data type: String -->
]>
導入されたバージョン:
9