JPEGメタデータ形式の仕様および使用上のノート
JPEGメタデータ
省略されたストリーム
表のソース
カラー・スペースの変換と一般的なマーカー
サムネール・イメージ
プログレッシブ・エンコーディング
ネイティブ・メタデータ形式のツリー構造と編集
イメージ・メタデータDTD
ストリーム・メタデータDTD
NOTE: ガベージ・コレクションによって適切に復元されない重要なネイティブ・リソースを消費するため、JPEGリーダーおよびライター・オブジェクトが不要になったときにdispose()を呼び出すことが重要です。 リーダーとライターはどちらもファイナライザでdispose()を呼び出しますが、ネイティブ・コードによってネイティブ・メモリーがなくなるまで、これらのファイナライザを呼び出すことはできません。
JPEGライターはピクセルの置換えをサポートしていません。
JPEGメタデータ
JPEGメタデータは、JPEGストリーム内のマーカー・セグメントに含まれるデータで構成されます。 読込みで返されるイメージ・メタデータ・オブジェクトには、そのイメージのSOIマーカーとEOIマーカー間にあるマーカー・セグメントの内容が記述されます。 書込みに渡されるイメージ・メタデータ・オブジェクトは、そのイメージのSOIマーカーとEOIマーカー間にあるストリームの内容を指定し、ImageWriteParam内のコントロールに従います。
ストリーム・メタデータは、省略されたイメージを含むストリームの先頭にある(または配置される)表専用イメージにのみ使用されます。 表専用イメージはイメージとして扱われず、イメージ・インデックスを使用しません。 ストリームの先頭に表専用イメージがある場合、読込みで返されるストリーム・メタデータ・オブジェクトには、その単一のイメージのSOIマーカーとEOIマーカー間にあるマーカー・セグメントの内容が記述されます。 ストリームの先頭に表専用イメージがない場合、ImageReaderのgetStreamMetadataメソッドはnullを返します。 ストリーム・メタデータがライターに提供されると、ストリーム・メタデータ・オブジェクトの表を含む単一の表専用イメージがストリームの先頭に書き込まれます。 ストリーム・メタデータ・オブジェクトに表が含まれていない場合は、デフォルトの表が書き込まれます。 ストリーム・メタデータの唯一の目的は省略されたストリームの先頭にある表専用イメージを指定することであり、ストリーム・メタデータ引数はImageWriter.prepareWriteSequenceメソッドでのみ有効です。 ほかのすべてのメソッドでは無視されます。
ImageWriter.getDefaultStreamMetadataメソッドは、JPEGImageWriteParamであり、かつ表を含んでいる場合、ImageWriteParam引数の表を含むオブジェクトを返します。 それ以外の場合、返されるオブジェクトにはデフォルトの表が含まれます。
ImageWriteParam引数が表を含む場合、ImageWriter.getDefaultImageMetadataメソッドは表を含まないメタデータ・オブジェクトを返します。 それ以外の場合は、返されるメタデータ・オブジェクトにはデフォルトの視覚的に損失のない表が含まれます。 当然、JPEGImageWriteParamにのみ表を含めることができます。
ignoreMetadataがtrueに設定され、リーダーに入力が設定されている場合、ストリーム・メタデータは利用できませんがイメージ・メタデータは利用できます。
省略されたストリーム
リーダーとライターはどちらも、操作から操作へと表を保持するため、いくつかの小さな制限があるだけで、省略されたストリームを非常に自然に使用できます。- 省略されたストリームには表専用イメージを1つだけ含めることができ、それはストリームの先頭に位置している必要があります。 それ以降にある表専用イメージは、未定義の動作を引き起こします。
- 省略されたストリームは完全に、かつ順序どおりに読み込む必要があります。 どちらの方向にも、ランダム・アクセスは許可されません。 同じイメージを複数回読み込むことができます。 直前の呼び出しと同一でないか、または直前の呼び出しよりも大きいイメージ・インデックス(または呼出しがない場合は0)を使用して呼び出した場合、
IllegalArgumentExceptionがスローされます。
表専用イメージが一度読み込まれると、別のストリームから別の表専用イメージが読み込まれるかリーダーがリセットされるまで、リーダーはその内容をストリーム・メタデータとして利用できます。 入力を変更してもストリーム・メタデータはリセットされません。 これは、1つのファイルから表を読み込んだあと、入力を変更して一連のイメージを含む、省略されたストリームを読み込むのに便利です。 表は自動的に使用され、「ストリーム」メタデータとして引き続き利用できます。
省略されたストリームはImageWriterのシーケンス型メソッドを使用して書き込まれます。 ImageWriter.prepareWriteSequenceを使用すると、ストリーム・メタデータを使用してストリームの先頭に表専用イメージを書き込み、表を使用するための設定を行うことができます。 ImageWriter.prepareWriteSequenceにストリーム・メタデータが指定されていない場合、表専用イメージは書き込まれません。 表を含まないストリーム・メタデータがImageWriter.prepareWriteSequenceに指定されている場合、デフォルトの視覚的に損失のない表を含む表専用イメージが書き込まれます。
表のソース
メタデータ・オブジェクトに表が存在する場合、イメージは表とともに書き込まれ、メタデータ・オブジェクトに表が存在しない場合は表なしで書き込まれます。 メタデータ・オブジェクトが存在しない場合は表が書き込まれます。 圧縮に使用する表は、順に参照される次のソースのいずれかから取得されます。
-
ImageWriteParamがあり、圧縮モードがEXPLICITに設定されている場合、品質設定を使用して構築されたデフォルトの表が使用されます。 メタデータに表が含まれる場合、またはメタデータが存在しない場合にのみ書き込まれますが、メタデータの表で置き換えられます。 -
ImageWriteParamがあり、圧縮モードがDEFAULTに設定されている場合、デフォルトの視覚的に損失のない表が使用されます。 メタデータに表が含まれる場合、またはメタデータが存在しない場合にのみ書き込まれますが、メタデータの表で置き換えられます。 - それ以外の場合は、
ImageWriteParamの圧縮モードがMODE_COPY_FROM_METADATAである必要があります。この場合、次が使用されます。- イメージ・メタデータ内の表(存在する場合)
- ストリーム・メタデータ内の表(存在する場合)
-
JPEGImageWriteParam内の表(存在する場合) - デフォルトの視覚的に損失のない表
JPEGImageWriteParamに表を含めておく必要があるという設計目的によるものです。また、これが発生する可能性があるのは、圧縮に既知の非標準表を使用して表のない省略されたストリームに書込みを行う場合のみです。
読込み時には、前の読込みで表が設定されていない場合にのみJPEGImageReadParamの表が参照されます。 JPEGImageReadParamから設定された表は、読み込まれるストリーム内に存在する表でオーバーライドされます。
特定のイメージに対してイメージ・メタデータ・オブジェクトが指定されていない場合は、デフォルトの表を含むデフォルトのオブジェクトが使用されます。
カラー・スペースの変換と一般的なマーカー
カラー・スペースの変換は、イメージの読み込みおよび書込み両方のデスティネーション・タイプによって制御されます。Rasterの読込み時には、カラー・スペースの変換は行われず、デスティネーション・タイプは無視されます。 この場合、デスティネーション・タイプが指定されていると警告がリスナーに送信されます。 Rasterの書込み時には、デスティネーション・タイプがバンドの解釈に使用されます。 これによって、JFIFまたはAdobeヘッダーが書き込まれたり、異なるコンポーネントIDがフレームおよびスキャン・ヘッダーに書き込まれたりする場合があります。 メタデータ・オブジェクト内に存在する値がデスティネーション・タイプと一致しない場合は、デスティネーション・タイプが使用され、警告がリスナーに送信されます。
オプションのColorSpaceのサポート:標準プラグインによるPhotoYCC (YCC)、PhotoYCCA (YCCA)、RGBA、およびYCbCrAカラー・スペースの処理は、次に説明するように、JPEGデータの解釈に使用するライブラリの機能によって異なります。 そのため、結果として起こるすべての動作はオプションによるものです。 復号化のときにサポートを利用できない場合は、カラー・スペースが未認識として扱われ、指定された数のコンポーネント・チャネルに応じたデフォルトのカラー・スペースを使用できます。 書込み時に、復号化の前に適切な変換を適用できない場合はExceptionがスローされます。 ただし、これらのカラー・スペースのサポートを利用できる場合、動作はドキュメント化されたとおりになります。
読込み時には、ストリームの内容は通常のJPEG規則によって次のように解釈されます。
- JFIF
APP0マーカー・セグメントが存在する場合、カラー・スペースはグレー・スケールまたはYCbCrのどちらかであると認識されます。 ICCプロファイルが埋め込まれたAPP2マーカー・セグメントも存在する場合、YCbCrはJFIF規格で定められた式に従ってRGBに変換され、ICCプロファイルはその結果得られるRGB空間を参照していると見なされます。 - Adobe
APP14マーカー・セグメントが存在する場合、カラー・スペースはtransformフラグを参照して決定されます。transformフラグは3つの値のいずれかを取ります。- 2 - イメージはYCCKとして符号化されます(符号化時にCMYKから暗黙的に変換)。
- 1 - イメージはYCbCrとして符号化されます(符号化時にRGBから暗黙的に変換)。
- 0 - 不明。3チャネルのイメージはRGBと見なされ、4チャネルのイメージはCMYKと見なされます。
- どちらのマーカー・セグメントも存在しない場合は、次の手順に従います。単一チャネルのイメージはグレー・スケールと見なされ、2チャネルのイメージはアルファ・チャネル付きのグレー・スケールと見なされます。 3チャネルおよび4チャネルのイメージについては、コンポーネントIDが参照されます。 3チャネルのイメージでこれらの値が1-3の場合、そのイメージはYCbCrと見なされます。 上記のオプションのカラー・スペースのサポートを利用できることを前提として、4チャネルのイメージでこれらの値が1-4の場合、そのイメージはYCbCrAと見なされます。 これらの値が4よりも大きい場合、ASCIIコードに照らして「R」、「G」、「B」、「A」、「C」、「c」があるかチェックされます。 これらは次のカラー・スペースを符号化できます。
RGB
RGBA
YCC (「Y」、「C」、「c」による)、PhotoYCCと見なされる
YCCA (「Y」、「C」、「c」、「A」による)、PhotoYCCAと見なされるそれ以外の場合、3チャネルのサブサンプル・イメージはYCbCrと見なされ、3チャネルの非サブサンプル・イメージはRGBと見なされ、4チャネルのサブサンプル・イメージはYCCKと見なされ、4チャネルの非サブサンプル・イメージはCMYKと見なされます。
- その他のすべてのイメージは解釈不可として宣言され、
BufferedImageとして読み込もうとすると例外がスローされます。 そのようなイメージはRasterとしてのみ読み込むことができます。 イメージが解釈可能であるが、符号化された色空間(「例えば」YCbCr)に対応するJavaColorSpaceが存在しない場合、ImageReader.getRawImageTypeはnullを返す。
- デスティネーションのタイプが設定されていない場合、アップサンプリングのあとに次のデフォルト変換が実行されます。YCbCr (およびYCbCrA)イメージは、基盤となるIJGライブラリにより提供される変換を使用してRGB (およびRGBA)に変換され、埋め込まれたICCプロファイルに基づく組込みのsRGB
ColorSpaceまたはカスタムRGBColorSpaceオブジェクトを使用して出力ColorModelが作成されます。 PhotoYCCおよびPhotoYCCAイメージは変換されません。 CMYKおよびYCCKイメージは現在サポートされていません。 - デスティネーションのイメージまたはタイプが設定されている場合は、次のように使用されます。IJGライブラリが適切な変換を提供する場合は、それが使用されます。 それ以外の場合は、デフォルトのライブラリ変換に続いてJavaのカラー・スペース変換が行われます。
- バンドは、ライブラリのカラー・スペース変換のあとに選択されます。 ソースまたはデスティネーション・バンドのサブセットが使用される場合、デスティネーションのタイプにかかわらずデフォルトのライブラリ変換のあとにJavaの変換は行われません。
-
BufferedImage(「例えば」 CMYK)としてサポートされていないjpegカラー・スペースのイメージを読み込もうとすると、例外がスローされます。 そのようなイメージはRasterとして読み込むことができます。 イメージのカラー・スペースがサポートされていない、または解釈不可の場合は、ImageReader.getImageTypesが空のIteratorを返します。 未処理のバンドのサブセットが必要な場合、まずRasterを取得し、そこからバンドを取得する必要があります。
書込みでは、適用されるカラー変換は次のように決定されます。
ソース・バンドのサブセットが書き込まれる場合、カラー変換は行われません。 デスティネーションは(設定されている場合)、書き込まれるバンド数と一致する必要があり、変換要求ではなく選択されたバンドの解釈に使用されます。 その動作はRasterのものと同じです。 すべてのバンドが書き込まれ、Rasterではなくイメージが書き込まれる場合、デスティネーションのタイプは無視され、警告がリスナーに送信されます。
デスティネーション・タイプが使用されており、メタデータ・オブジェクトがある場合にその特性とデスティネーション・タイプに互換性がなければ、デスティネーション・タイプが使用され、書き込まれるメタデータは提供されるメタデータから変更され、警告がリスナーに送信されます。 これには、app0JFIFおよびapp14Adobeノードが含まれます。 sofおよびsosノード内のコンポーネントIDは変更されませんが、app0JFIFノードが存在しないかぎり、あらゆる値を使用できます。
イメージ全体を書き込む場合、デスティネーションのカラー・スペースはイメージの内容およびメタデータの設定に基づき、次のアルゴリズムに従って選択されます。
メタデータ・オブジェクトが指定されていない場合は、次のデフォルトが適用されます。
- グレー・スケール・イメージは、JFIF
APP0マーカー・セグメントとともに書き込まれます。 アルファ付きグレー・スケール・イメージは、特殊なマーカーなしで書き込まれます。 JFIFの要件に応じて、フレーム内のコンポーネントIDおよびスキャン・ヘッダーは1に設定されます。 - RGBイメージはYCbCrに変換され、クロミナンス・チャネル内で水平方向と垂直方向の両方が半分にサブサンプリングされ、JFIF
APP0マーカー・セグメントとともに書き込まれます。 イメージのColorSpaceがICCProfile(ICC_ColorSpaceのインスタンス、ただし標準の組み込みColorSpacesの1つではありません)に基づいている場合、そのプロファイルはAPP2マーカー・セグメントに埋め込まれます。 JFIFの要件に応じて、フレーム内のコンポーネントIDおよびスキャン・ヘッダーは1、2、および3に設定されます。 - 上記のオプションのライブラリのサポートを前提として、RGBAイメージはYCbCrAに変換され、クロミナンス・チャネル内で水平方向と垂直方向の両方が半分にサブサンプリングされ、特殊なマーカー・セグメントなしで書き込まれます。 フレーム内のコンポーネントIDおよびスキャン・ヘッダーは1、2、3、および4に設定されます。
- 上記のオプションのライブラリのサポートを前提として、PhotoYCCおよびYCCAイメージはクロミナンス・チャネル内で水平方向と垂直方向の両方が半分にサブサンプリングされ、Adobe
APP14マーカー・セグメント、およびフレームとスキャン・ヘッダー内のコンポーネントIDとして「Y」、「C」、および「c」(アルファ・チャネルが存在する場合はさらに「A」)とともに書き込まれます。
メタデータ・オブジェクトが指定されている場合、フレームおよびスキャン・ヘッダー内のチャネル数は書き込まれるバンド数と常に一致する必要があり、一致しない場合には例外がスローされます。app0JFIFおよびapp14Adobeノードは、app14AdobeノードがYCbCrを示し、コンポーネントIDがJFIFと互換性がある場合(0-2)にのみ同じメタデータ・オブジェクトに存在することができます。 さまざまなイメージ・タイプが次の方法で処理されます。
(すべてのマルチチャネル・イメージは、カラー・スペースにかかわらず、メタデータ・オブジェクトのフレーム・ヘッダー・ノード内のサンプリング係数に従ってサブサンプリングされます。)
- グレー・スケール・イメージ:
- メタデータ・オブジェクトに
app0JFIFノードが存在する場合、JFIFAPP0マーカー・セグメントが書き込まれます。 - メタデータ・オブジェクトに
app14Adobeノードが存在する場合は、有効性(transformがUNKNOWNでなければなりません)がチェックされてから書き込まれます。 - メタデータ・オブジェクトにどちらのノードも存在しない場合は、特殊なマーカー・セグメントが書き込まれません。
- メタデータ・オブジェクトに
- アルファ・チャネル付きグレー・スケール・イメージ:
- JFIFでは2チャネル・イメージがサポートされていないため、メタデータ・オブジェクトに
app0JFIFノードが存在する場合は無視され、警告がリスナーに送信されます。 - メタデータ・オブジェクトに
app14Adobeノードが存在する場合は、有効性(transformがUNKNOWNでなければなりません)がチェックされてから書き込まれます。transformがUNKNOWNでない場合、リスナーに警告が送信され、正しい変換が書き込まれます。 - メタデータ・オブジェクトにどちらのノードも存在しない場合は、特殊なマーカー・セグメントが書き込まれません。
- JFIFでは2チャネル・イメージがサポートされていないため、メタデータ・オブジェクトに
- RGBイメージ:
- メタデータ・オブジェクトに
app0JFIFノードが存在する場合、イメージはYCbCrに変換され、JFIFAPP0マーカー・セグメントとともに書き込まれます。 イメージのColorSpaceが非標準のICCプロファイルに基づいている場合、そのプロファイルはAPP2マーカー・セグメントに埋め込まれます。ColorSpaceは非標準のICCプロファイルに基づいていないものの、メタデータ内にapp2ICCノードが存在する場合、APP2マーカー・セグメントは適切な標準プロファイルを使用して書き込まれます。 ファイルはJFIFに準拠していなければならないため、プロファイルはRGBカラー・スペースを指定する必要があります。 - メタデータ・オブジェクトに
app14Adobeノードが存在する場合、イメージはカラー変換の設定に従って変換され、AdobeAPP14マーカー・セグメントとともに書き込まれます。 コンポーネントIDが、フレームおよびスキャン・ヘッダーに表示されたとおりに書き込まれます。 カラー変換はYCbCrまたはUNKNOWNである必要があります。UNKNOWNの場合、イメージはカラー変換されません。 - どちらのノードも存在しない場合は、フレーム・ヘッダー内のコンポーネントIDが参照されます。 これらが前述のとおりにカラー・スペースを示している場合は、可能な場合、そのカラー・スペースにイメージが変換されます。 コンポーネントIDがカラー・スペースを示していない場合は、サンプリング係数が参照されます。 イメージがサブサンプリングされる場合は、まずYCbCrに変換されます。 イメージがサブサンプリングされない場合は、変換が適用されません。 特殊なマーカー・セグメントは書き込まれません。
- メタデータ・オブジェクトに
- RGBAイメージ: 上記のオプションのライブラリのサポートを前提として、次のようになります。
- JFIFでは4チャネル・イメージがサポートされていないため、メタデータ・オブジェクトに
app0JFIFノードが存在する場合は無視され、警告がリスナーに送信されます。 - メタデータ・オブジェクトに
app14Adobeノードが存在する場合、イメージはAdobeAPP14マーカー・セグメントとともに書き込まれます。 カラー・スペース変換は行われません。 コンポーネントIDが、フレームおよびスキャン・ヘッダーに表示されたとおりに書き込まれます。 カラー変換はUNKNOWNである必要があります。 それ以外の場合は、警告がリスナーに送信されます。 -
app14Adobeノードが存在しない場合は、フレーム・ヘッダー内のコンポーネントIDが参照されます。 これらが前述のとおりにカラー・スペースを示している場合は、可能な場合、そのカラー・スペースにイメージが変換されます。 コンポーネントIDがカラー・スペースを示していない場合は、サンプリング係数が参照されます。 イメージがサブサンプリングされる場合は、YCbCrAに変換されます。 イメージがサブサンプリングされない場合は、変換が適用されません。 特殊なマーカー・セグメントは書き込まれません。
- JFIFでは4チャネル・イメージがサポートされていないため、メタデータ・オブジェクトに
- PhotoYCCイメージ: 上記のオプションのライブラリのサポートを前提として、次のようになります。
- メタデータ・オブジェクトに
app0JFIFノードが存在する場合、イメージはsRGBに変換されたあと、符号化中にYCbCrに変換され、JFIFAPP0マーカー・セグメントが書き込まれます。 - メタデータ・オブジェクトに
app14Adobeノードが存在する場合は、変換が適用されず、AdobeAPP14マーカー・セグメントが書き込まれます。 カラー変換はYCCである必要があります。 それ以外の場合は、警告がリスナーに送信されます。 - メタデータ・オブジェクトにどちらのノードも存在しない場合は、変換が適用されず、特殊なマーカー・セグメントが書き込まれません。
- メタデータ・オブジェクトに
- PhotoYCCAイメージ: 上記のオプションのライブラリのサポートを前提として、次のようになります。
- JFIFでは4チャネル・イメージがサポートされていないため、メタデータ・オブジェクトに
app0JFIFノードが存在する場合は無視され、警告がリスナーに送信されます。 - メタデータ・オブジェクトに
app14Adobeノードが存在する場合は、変換が適用されず、AdobeAPP14マーカー・セグメントが書き込まれます。 カラー変換はUNKNOWNである必要があります。 それ以外の場合は、警告がリスナーに送信されます。 - メタデータ・オブジェクトにどちらのノードも存在しない場合は、変換が適用されず、特殊なマーカー・セグメントが書き込まれません。
- JFIFでは4チャネル・イメージがサポートされていないため、メタデータ・オブジェクトに
サムネール・イメージ
サムネールはJFIFおよびJFIF拡張マーカー・セグメントの使用によりサポートされます。 書込みメソッドで提供されるサムネールによって、含められるサムネールが決定します。メタデータに存在するapp0JFIFおよびapp0JFXXノードには、サムネールのピクセル・データは含まれません。 ただし、書き込まれるサムネールの種類は、次のようにメタデータ・オブジェクトの内容によって異なります。 インデックス付きまたはRGBイメージとして書き込まれるサムネール、および255×255よりも大きいサムネールは、縮小ではなく、255×255にクリッピングされます。 JPEGイメージとして書き込まれるサムネールのサイズに制限はありません。 サムネールがクリッピングされる場合には、警告がリスナーに送信されます。
- サムネールが1つの場合は、次のように処理されます。
- サムネール・イメージがRGBパレット・イメージの場合は、次のように処理されます。
- メタデータに
app0JFXXノードが存在しない場合、またはメタデータに存在する最初のapp0JFXXノードにJFIFthumbPalette要素が含まれている場合は、JFXXAPP0マーカー・セグメントにパレット・サムネールが書き込まれます。 - メタデータに存在する最初の
app0JFXXノードに別のサムネール形式(RGBまたはJPEG)が含まれている場合、パレット・イメージはRGBに拡張され、示されたサムネール形式が書き込まれます。
- メタデータに
- サムネール・イメージがRGBイメージの場合は、次のように処理されます。
- メタデータに
app0JFXXノードが存在しない場合は、サムネールがJFIFAPP0マーカー・セグメントの一部として書き込まれます。 - メタデータに存在する最初の
app0JFXXノードにJFIFthumbRGB要素が含まれる場合は、RGBサムネールがJFXXAPP0マーカー・セグメントに書き込まれます。 - メタデータ・オブジェクトに存在する最初の
app0JFXXノードにJFIFthumbJPEG要素が含まれる場合は、JPEGサムネールがJFXXAPP0マーカー・セグメントに書き込まれます。 - メタデータに存在する最初の
app0JFXXノードにJFIFthumbPalette要素が含まれる場合は、RGBサムネールがJFXXAPP0マーカー・セグメントに書き込まれ、警告がリスナーに送信されます。
- メタデータに
- サムネール・イメージがグレー・スケール・イメージの場合は、次のように処理されます。
- メタデータに
app0JFXXノードが存在しない場合は、サムネールがRGBに拡張され、JFIFAPP0マーカー・セグメントの一部として書き込まれます。 - メタデータに存在する最初の
app0JFXXノードにJFIFthumbRGB要素が含まれる場合は、サムネールがRGBに拡張され、独立したJFXXRGBマーカー・セグメントに書き込まれます。 - メタデータ・オブジェクトに存在する最初の
app0JFXXノードにJFIFthumbJPEG要素が含まれる場合は、JPEGサムネールがJFXXAPP0マーカー・セグメントに書き込まれます。 - メタデータに存在する最初の
app0JFXXノードにJFIFthumbPalette要素が含まれる場合は、JPEGサムネールがJFXXAPP0マーカー・セグメントに書き込まれ、警告がリスナーに送信されます。
- メタデータに
- その他のサムネール・イメージ・タイプは無視され、警告がリスナーに送信されます。
- サムネール・イメージがRGBパレット・イメージの場合は、次のように処理されます。
- 複数のサムネールがある場合、JFIF
APP0セグメント内にサムネールが配置されていない場合を除いて各セグメントは上記のとおり処理され、各サムネールのために参照されるapp0JFXXノードは、サムネールと同じシーケンスで発生するメタデータのapp0JFXXノードです。 「つまり。」、最初のapp0JFXXノードが最初のサムネイルに適用され、2番目のノードが2番目のサムネイルに適用されます。 メタデータのapp0JFXXノードがサムネールより少ない場合、これらのサムネールは一致するapp0JFXXノードがないと見なされます。 一致するapp0JFXXノードのないRGBサムネールは、JFXXAPP0マーカー・セグメントに書き込まれます。 一致するapp0JFXXノードのないグレー・スケール・サムネールは、JPEGイメージとしてJFXXAPP0マーカー・セグメントに書き込まれます。
サムネールを格納するメカニズムだけがJFIFまたはJFIF拡張マーカー・セグメントを使用するため、グレー・スケールまたはRGBイメージだけがサムネールを持つことができます。 その他のイメージ・タイプを書き込むときにサムネールが存在する場合、サムネールは無視され、警告が警告リスナーに送信されます。
プログレッシブ・エンコーディング
書込み操作に渡されるImageWriteParamではプログレッシブ・エンコーディングを有効にする必要があり、これが有効になっていないと、メタデータ・オブジェクトに含まれるスキャン・ヘッダーにかかわらず、イメージが順番に書き込まれます。 プログレッシブ・エンコーディングが有効で、メタデータからコピーするように設定されている場合、メタデータのスキャン・ヘッダーの順序を使用してイメージが書き込まれます。 プログレッシブ・エンコーディングが有効で、デフォルトを使用するように設定されている場合、メタデータのスキャンは無視されてスキャンのデフォルト設定が使用されます。 プログレッシブ・エンコーディングでは常に、最適化されたハフマン表が強制的に使用されます。 メタデータに存在するハフマン表は無視され、警告が警告リスナーに送信されます。 ハフマン表の最適化はImageWriteParamで要求され、メタデータまたはImageWriteParam自身のハフマン表はすべて無視され、そのような表が存在する場合には警告が警告リスナーに送信されます。
ネイティブ・メタデータ形式のツリー構造と編集
次のDTDは、IIOMetadataオブジェクトによって実際に返されるメタデータ・オブジェクトのツリーだけを記述しています。 これらの解析の区切り文字は意味のあるメタデータを持たないため、SOI、EOI、またはRSTマーカーに対応するノードは含まれていません。
最初のノードは常にJPEGvarietyノードです。 JPEGメタデータ形式のjavax_imageio_jpeg_image_1.0バージョンでは、このノードが1つの子であるapp0JFIFノードを持つ場合(JPEGストリームにJFIFマーカー・セグメントと関連データが含まれることを示す)と、子を持たない場合(ストリームにJFIFマーカーが含まれないことを示す)があります。 JPEGメタデータ形式の今後のバージョンでは、JPEGvarietyノードの子として表示されるその他のタイプのノードを定義することで、ほかのさまざまなJPEGメタデータ(Exifなど)がサポートされる可能性があります。
(javax_imageio_jpeg_image_1.0形式のメタデータ・ツリー構造でExifメタデータを解釈しようとするアプリケーションは、APP1マーカーを示し、それをExifマーカー・セグメントとして識別するデータを含んだタグのあるunknownマーカー・セグメントを調べる必要があります。 そのあとで、アプリケーション固有のコードを使用してマーカー・セグメント内のデータを解釈できます。 そのようなアプリケーションがJPEGメタデータ形式の今後のバージョンに従ってフォーマットされたメタデータ・ツリーを検出した場合、Exifマーカー・セグメントはその形式のunknownではなく、JPEGvarietyノードの子ノードとして構造化される可能性があります。 このため、アプリケーションはIIOMetadataオブジェクトの取得に使用されるメソッドまたはコンストラクタにバージョンを識別する文字列を渡すことで、使用するバージョンを識別することが重要です。)
読込み時には、JFXXおよびapp2ICCノードがapp0JFIFノードの子として発生します。 これは、JFXX APP0およびAPP2マーカー・セグメントがストリーム内のどこで実際に発生するかにかかわらず当てはまります。 markerSequenceノード内のノードの順序は、JPEGストリーム内にあるマーカー・セグメントの順序に対応します。
書込み時には、常に最初のノードでなければならないapp0JFIFノード(それ自身がJPEGvarietyノードの子)の子としてJFXXおよびapp2ICCノードが発生します。 (ストリームがJFIFに準拠していない場合は、app0JFIFノードは提供されず、JPEGvarietyノードは子を持ちません。) まずJFIF APP0、JFXX APP0、およびAPP2マーカー・セグメントが書き込まれ、次にmarkerSequenceノード内に対応するノードが現れる順序ですべてのAdobe APP14、APPn、COM、および不明なセグメントが書き込まれ、次にDQT (および非プログレッシブ書込みにはDHT)マーカー・セグメント、続いてSOFおよびSOSマーカー・セグメントが書き込まれます。 プログレッションの制御にメタデータを使用するプログレッシブ書込みでは、対応するノードがmarkerSequenceノードに存在している順序でSOSセグメントが使用されます。
reset、mergeTree、およびsetFromTree操作は、JPEGプラグイン・メタデータ・オブジェクトに対して次のセマンティックスを持ちます。
reset - resetの呼出しは、ストリームの読込みで作成されたものかImageWriterからデフォルトのオブジェクトを取得したものかにかかわらず、メタデータ・オブジェクトを作成直後と同じ状態に復元します。 これは、メタデータ・オブジェクトが作成後に何度変更されたかにかかわらず当てはまります。
mergeTree - ネイティブ形式
mergeTree操作は、次のDTDに従う有効なツリーを受け入れ、次の順序付けルールを使用してノードをマージします。 すべての場合において、新しいノードに存在するデータのみが対応する既存のノード(存在する場合)内で変更されます。 つまり、mergeTreeを使用してそれらのノードを削除することはできません。 ノードを削除するには、setFromTreeを使用します。 ツリーはIIOMetadataNodeで構成される必要があります。
-
app0JFIF-
app0JFIFノードがすでに存在する場合は、新しいノードの内容によって既存のノードが変更されます。 - そのようなノードが存在しない場合は、新しいノードが作成され、適切な位置に挿入されます。
-
-
dqt- シーケンス内に
dqtノードがすでに存在する場合、dqtノード内では、ノード内の各表によって同じ表IDを持つ最初の表が置き換えられます。 - 既存の
dqtノードに同じIDの表が含まれていない場合、その表は既存の最後のdqtノードに追加されます。 -
dqtノードが存在しない場合は、次のように新しいノードが作成され、追加されます。-
dhtノードが存在する場合は、最初のノードの前に新しいdqtノードが挿入されます。 -
dhtノードが存在しない場合は、sofノード(存在する場合)の前に新しいdqtノードが挿入されます。 -
sofノードが存在しない場合は、最初のsosノード(存在する場合)の前に新しいdqtノードが挿入されます。 -
sosノードが存在しない場合は、シーケンスの最後に新しいdqtノードが追加されます。
-
- シーケンス内に
-
dht- シーケンス内に
dhtノードがすでに存在する場合、dhtノード内では、ノード内の各表によって同じ表クラスと表IDを持つ最初の表が置き換えられます。 - 既存の
dhtノードに同じクラスとIDを持つ表が含まれていない場合、その表は既存の最後のdhtノードに追加されます。 -
dhtノードが存在しない場合は、次のように新しいノードが作成され、追加されます。-
dqtノードが存在する場合は、最後のdqtノードの直後に新しいdhtノードが挿入されます。 -
dqtノードが存在しない場合は、sofノード(存在する場合)の前に新しいdhtノードが挿入されます。 -
sofノードが存在しない場合は、最初のsosノード(存在する場合)の前に新しいdhtノードが挿入されます。 -
sosノードが存在しない場合は、シーケンスの最後に新しいdhtノードが追加されます。
-
- シーケンス内に
-
dri-
driノードがすでに存在する場合は、再起動の間隔の値が更新されます。 -
driノードが存在しない場合は、次のように新しいノードが作成され、追加されます。-
sofノードが存在する場合は、その前に新しいdriノードが挿入されます。 -
sofノードが存在しない場合は、最初のsosノード(存在する場合)の前に新しいdriノードが挿入されます。 -
sosノードが存在しない場合は、シーケンスの最後に新しいdriノードが追加されます。
-
-
-
com
次のように新しいcomノードが作成され、挿入されます。-
comノードがすでに存在する場合は、最後のノードの後ろに新しいノードが挿入されます。 -
comノードが存在しない場合は、app14Adobeノードの後ろに(存在する場合)新しいcomノードが挿入されます。 -
app14Adobeノードが存在しない場合は、シーケンスの最初に新しいcomノードが挿入されます。
-
-
app14Adobe-
app14Adobeノードがすでに存在する場合は、その属性は既存のノードから更新されます。 -
app14Adobeノードが存在しない場合は、次のように新しいノードが作成され、追加されます。- 新しい
app14Adobeノードが最後のunknownノード(存在する場合)の後ろに挿入されます。 -
unknownノードが存在しない場合は、シーケンスの最初に新しいapp14Adobeノードが挿入されます。
- 新しい
-
-
unknown
次のように新しいunknownノードが作成され、シーケンスに追加されます。-
unknownマーカー・ノードがすでに存在する場合は、最後のノードの後ろに新しいノードが挿入されます。 -
unknownノードが存在しない場合は、app14Adobeノード(存在する場合)の前に新しいunknownノードが挿入されます。 -
app14Adobeノードが存在しない場合は、シーケンスの最初に新しいunknownノードが挿入されます。
-
-
sof- シーケンス内に
sofノードがすでに存在する場合は、その値は既存のノードから更新されます。 -
sofノードが存在しない場合は、次のように新しいノードが作成され、追加されます。-
sosノードが存在する場合は、最初のノードの前に新しいsofノードが挿入されます。 -
sosノードが存在しない場合は、シーケンスの最後に新しいsofノードが追加されます。
-
- シーケンス内に
-
sos- 単一の
sosノードがすでに存在する場合は、その値は既存のノードから更新されます。 - 既存の
sosノードが複数存在する場合は、sosノードをプログレッシブ・スキャンのセットにマージできないため、IIOInvalidTreeExceptionがスローされます。 -
sosノードが存在しない場合は、新しいノードが作成され、シーケンスの最後に追加されます。
- 単一の
mergeTree - 標準形式
mergeTree操作は、標準形式のツリーの場合、次の方法でネイティブ・ツリーを変更します。
-
Chroma-ChromaノードのColorSpaceTypeサブノードによって、圧縮イメージのターゲット・カラー・スペースを変更できます。 新しいカラー・スペースの選択によって、上記のアルゴリズムに従っていくつかの変更が生じることがあります。app0JFIFおよびapp14Adobeノードの追加または削除、サブサンプリングの追加または削除、コンポーネントIDの変更が行われることがあり、それに応じてsofおよびsosノードが更新されます。 必要に応じて、追加の数量化表およびハフマン表が追加されます。 数量化表の場合、既存表の品質レベルに合わせてデフォルトがスケーリングされます。 既存の表を含まないメタデータには表は追加されません。 既存のメタデータがプログレッシブ・エンコーディングを指定している場合は、チャネル数を変更しないでください。Alphaサブノードのnoneの明示的な値によってアルファ・チャネルが削除される場合や、none以外によってアルファ・チャネルが追加される場合があるため、Transparencyノードも考慮されます。 -
Dimension-PixelAspectRatio仕様によってapp0JFIFノード(存在する場合)の内容が変更されたり、適切な値を含むapp0JFIFノード(可能な場合)が追加されたりする場合があります。 浮動小数点の比率から、ノードに含める適切な整数のペアが計算されます。 -
Text- 圧縮解除された各テキスト項目はcomノードに変換され、comノードをマージするための上記のルールに従って挿入されます。
setFromTree - ネイティブ形式
setFromTree操作は、後述するネイティブ形式のツリーの場合、単に既存のツリー全体を新しいツリーで置き換えます。 ツリーはIIOMetadataNodeで構成される必要があります。
setFromTree - 標準形式
setFromTree操作は、標準形式のツリーの場合、resetを実行したあとに新しいツリーをマージします。
イメージ・メタデータDTD
<!DOCTYPE "javax_imageio_jpeg_image_1.0" [
<!ELEMENT "javax_imageio_jpeg_image_1.0" (JPEGvariety, markerSequence)>
<!ELEMENT "JPEGvariety" (app0JFIF)>
<!-- A node grouping all marker segments specific to the variety of
stream being read/written (e.g. JFIF) - may be empty -->
<!ELEMENT "app0JFIF" (JFXX?, app2ICC?)>
<!ATTLIST "app0JFIF" "majorVersion" #CDATA "1">
<!-- The major JFIF version number -->
<!-- Data type: Integer -->
<!-- Min value: 0 (inclusive) -->
<!-- Max value: 255 (inclusive) -->
<!ATTLIST "app0JFIF" "minorVersion" #CDATA "2">
<!-- The minor JFIF version number -->
<!-- Data type: Integer -->
<!-- Min value: 0 (inclusive) -->
<!-- Max value: 255 (inclusive) -->
<!ATTLIST "app0JFIF" "resUnits" ("0" | "1" | "2") "0">
<!-- The resolution units for Xdensisty and Ydensity (0 = no
units, just aspect ratio; 1 = dots/inch; 2 = dots/cm) -->
<!ATTLIST "app0JFIF" "Xdensity" #CDATA "1">
<!-- The horizontal density or aspect ratio numerator -->
<!-- Data type: Integer -->
<!-- Min value: 1 (inclusive) -->
<!-- Max value: 65535 (inclusive) -->
<!ATTLIST "app0JFIF" "Ydensity" #CDATA "1">
<!-- The vertical density or aspect ratio denominator -->
<!-- Data type: Integer -->
<!-- Min value: 1 (inclusive) -->
<!-- Max value: 65535 (inclusive) -->
<!ATTLIST "app0JFIF" "thumbWidth" #CDATA "0">
<!-- The width of the thumbnail, or 0 if there isn't one -->
<!-- Data type: Integer -->
<!-- Min value: 0 (inclusive) -->
<!-- Max value: 255 (inclusive) -->
<!ATTLIST "app0JFIF" "thumbHeight" #CDATA "0">
<!-- The height of the thumbnail, or 0 if there isn't one -->
<!-- Data type: Integer -->
<!-- Min value: 0 (inclusive) -->
<!-- Max value: 255 (inclusive) -->
<!ELEMENT "JFXX" (app0JFXX)*>
<!-- Min children: 1 -->
<!ELEMENT "app0JFXX" (JFIFthumbJPEG | JFIFthumbPalette |
JFIFthumbRGB)>
<!-- A JFIF extension marker segment -->
<!ATTLIST "app0JFXX" "extensionCode" ("16" | "17" | "19")
#IMPLIED>
<!-- The JFXX extension code identifying thumbnail type: (16 =
JPEG, 17 = indexed, 19 = RGB -->
<!ELEMENT "JFIFthumbJPEG" (markerSequence?)>
<!-- A JFIF thumbnail in JPEG format (no JFIF segments
permitted) -->
<!ELEMENT "JFIFthumbPalette" EMPTY>
<!-- A JFIF thumbnail as an RGB indexed image -->
<!ATTLIST "JFIFthumbPalette" "thumbWidth" #CDATA #IMPLIED>
<!-- The width of the thumbnail -->
<!-- Data type: Integer -->
<!-- Min value: 0 (inclusive) -->
<!-- Max value: 255 (inclusive) -->
<!ATTLIST "JFIFthumbPalette" "thumbHeight" #CDATA #IMPLIED>
<!-- The height of the thumbnail -->
<!-- Data type: Integer -->
<!-- Min value: 0 (inclusive) -->
<!-- Max value: 255 (inclusive) -->
<!ELEMENT "JFIFthumbRGB" EMPTY>
<!-- A JFIF thumbnail as an RGB image -->
<!ATTLIST "JFIFthumbRGB" "thumbWidth" #CDATA #IMPLIED>
<!-- The width of the thumbnail -->
<!-- Data type: Integer -->
<!-- Min value: 0 (inclusive) -->
<!-- Max value: 255 (inclusive) -->
<!ATTLIST "JFIFthumbRGB" "thumbHeight" #CDATA #IMPLIED>
<!-- The height of the thumbnail -->
<!-- Data type: Integer -->
<!-- Min value: 0 (inclusive) -->
<!-- Max value: 255 (inclusive) -->
<!ELEMENT "app2ICC" EMPTY>
<!-- An ICC profile APP2 marker segment -->
<!-- Optional User object: java.awt.color.ICC_Profile -->
<!ELEMENT "markerSequence" (dqt | dht | dri | com | unknown |
app14Adobe | sof | sos)*>
<!-- A node grouping all non-jfif marker segments -->
<!ELEMENT "dqt" (dqtable)*>
<!-- A Define Quantization Table(s) marker segment -->
<!-- Min children: 1 -->
<!-- Max children: 4 -->
<!ELEMENT "dqtable" EMPTY>
<!-- A single quantization table -->
<!-- User object: javax.imageio.plugins.jpeg.JPEGQTable -->
<!ATTLIST "dqtable" "elementPrecision" #CDATA "0">
<!-- The number of bits in each table element (0 = 8, 1 = 16)
-->
<!-- Data type: Integer -->
<!ATTLIST "dqtable" "qtableId" ("0" | "1" | "2" | "3") #REQUIRED>
<!ELEMENT "dht" (dhtable)*>
<!-- A Define Huffman Table(s) marker segment -->
<!-- Min children: 1 -->
<!-- Max children: 4 -->
<!ELEMENT "dhtable" EMPTY>
<!-- A single Huffman table -->
<!-- User object: javax.imageio.plugins.jpeg.JPEGHuffmanTable -->
<!ATTLIST "dhtable" "class" ("0" | "1") #REQUIRED>
<!-- Indicates whether this is a DC (0) or an AC (1) table -->
<!ATTLIST "dhtable" "htableId" ("0" | "1" | "2" | "3") #REQUIRED>
<!-- The table id -->
<!ELEMENT "dri" EMPTY>
<!-- A Define Restart Interval marker segment -->
<!ATTLIST "dri" "interval" #CDATA #REQUIRED>
<!-- The restart interval in MCUs -->
<!-- Data type: Integer -->
<!-- Min value: 0 (inclusive) -->
<!-- Max value: 65535 (inclusive) -->
<!ELEMENT "com" EMPTY>
<!-- A Comment marker segment. The user object contains the actual
bytes. -->
<!-- User object: array of [B -->
<!-- Min length: 1 -->
<!-- Max length: 65533 -->
<!ATTLIST "com" "comment" #CDATA #IMPLIED>
<!-- The comment as a string (used only if user object is null)
-->
<!-- Data type: String -->
<!ELEMENT "unknown" EMPTY>
<!-- An unrecognized marker segment. The user object contains the
data not including length. -->
<!-- User object: array of [B -->
<!-- Min length: 1 -->
<!-- Max length: 65533 -->
<!ATTLIST "unknown" "MarkerTag" #CDATA #REQUIRED>
<!-- The tag identifying this marker segment -->
<!-- Data type: Integer -->
<!-- Min value: 0 (inclusive) -->
<!-- Max value: 255 (inclusive) -->
<!ELEMENT "app14Adobe" EMPTY>
<!-- An Adobe APP14 marker segment -->
<!ATTLIST "app14Adobe" "version" #CDATA "100">
<!-- The version of Adobe APP14 marker segment -->
<!-- Data type: Integer -->
<!-- Min value: 100 (inclusive) -->
<!-- Max value: 255 (inclusive) -->
<!ATTLIST "app14Adobe" "flags0" #CDATA "0">
<!-- The flags0 variable of an APP14 marker segment -->
<!-- Data type: Integer -->
<!-- Min value: 0 (inclusive) -->
<!-- Max value: 65535 (inclusive) -->
<!ATTLIST "app14Adobe" "flags1" #CDATA "0">
<!-- The flags1 variable of an APP14 marker segment -->
<!-- Data type: Integer -->
<!-- Min value: 0 (inclusive) -->
<!-- Max value: 65535 (inclusive) -->
<!ATTLIST "app14Adobe" "transform" ("0" | "1" | "2") #REQUIRED>
<!-- The color transform applied to the image (0 = Unknown, 1 =
YCbCr, 2 = YCCK) -->
<!ELEMENT "sof" (componentSpec)*>
<!-- A Start Of Frame marker segment -->
<!-- Min children: 1 -->
<!-- Max children: 4 -->
<!ATTLIST "sof" "process" ("0" | "1" | "2") #IMPLIED>
<!-- The JPEG process (0 = Baseline sequential, 1 = Extended
sequential, 2 = Progressive) -->
<!ATTLIST "sof" "samplePrecision" #CDATA "8">
<!-- The number of bits per sample -->
<!-- Data type: Integer -->
<!ATTLIST "sof" "numLines" #CDATA #IMPLIED>
<!-- The number of lines in the image -->
<!-- Data type: Integer -->
<!-- Min value: 0 (inclusive) -->
<!-- Max value: 65535 (inclusive) -->
<!ATTLIST "sof" "samplesPerLine" #CDATA #IMPLIED>
<!-- The number of samples per line -->
<!-- Data type: Integer -->
<!-- Min value: 0 (inclusive) -->
<!-- Max value: 65535 (inclusive) -->
<!ATTLIST "sof" "numFrameComponents" ("1" | "2" | "3" | "4")
#IMPLIED>
<!-- The number of components in the image -->
<!ELEMENT "componentSpec" EMPTY>
<!-- A component specification for a frame -->
<!ATTLIST "componentSpec" "componentId" #CDATA #REQUIRED>
<!-- The id for this component -->
<!-- Data type: Integer -->
<!-- Min value: 0 (inclusive) -->
<!-- Max value: 255 (inclusive) -->
<!ATTLIST "componentSpec" "HsamplingFactor" #CDATA #REQUIRED>
<!-- The horizontal sampling factor for this component -->
<!-- Data type: Integer -->
<!-- Min value: 1 (inclusive) -->
<!-- Max value: 255 (inclusive) -->
<!ATTLIST "componentSpec" "VsamplingFactor" #CDATA #REQUIRED>
<!-- The vertical sampling factor for this component -->
<!-- Data type: Integer -->
<!-- Min value: 1 (inclusive) -->
<!-- Max value: 255 (inclusive) -->
<!ATTLIST "componentSpec" "QtableSelector" ("0" | "1" | "2" |
"3") #REQUIRED>
<!-- The quantization table to use for this component -->
<!ELEMENT "sos" (scanComponentSpec)*>
<!-- A Start Of Scan marker segment -->
<!-- Min children: 1 -->
<!-- Max children: 4 -->
<!ATTLIST "sos" "numScanComponents" ("1" | "2" | "3" | "4")
#REQUIRED>
<!-- The number of components in the scan -->
<!ATTLIST "sos" "startSpectralSelection" #CDATA "0">
<!-- The first spectral band included in this scan -->
<!-- Data type: Integer -->
<!-- Min value: 0 (inclusive) -->
<!-- Max value: 63 (inclusive) -->
<!ATTLIST "sos" "endSpectralSelection" #CDATA "63">
<!-- The last spectral band included in this scan -->
<!-- Data type: Integer -->
<!-- Min value: 0 (inclusive) -->
<!-- Max value: 63 (inclusive) -->
<!ATTLIST "sos" "approxHigh" #CDATA "0">
<!-- The highest bit position included in this scan -->
<!-- Data type: Integer -->
<!-- Min value: 0 (inclusive) -->
<!-- Max value: 15 (inclusive) -->
<!ATTLIST "sos" "approxLow" #CDATA "0">
<!-- The lowest bit position included in this scan -->
<!-- Data type: Integer -->
<!-- Min value: 0 (inclusive) -->
<!-- Max value: 15 (inclusive) -->
<!ELEMENT "scanComponentSpec" EMPTY>
<!-- A component specification for a scan -->
<!ATTLIST "scanComponentSpec" "componentSelector" #CDATA
#REQUIRED>
<!-- The id of this component -->
<!-- Data type: Integer -->
<!-- Min value: 0 (inclusive) -->
<!-- Max value: 255 (inclusive) -->
<!ATTLIST "scanComponentSpec" "dcHuffTable" ("0" | "1" | "2" |
"3") #REQUIRED>
<!-- The huffman table to use for encoding DC coefficients -->
<!ATTLIST "scanComponentSpec" "acHuffTable" ("0" | "1" | "2" |
"3") #REQUIRED>
<!-- The huffman table to use for encoding AC coefficients -->
]>
ストリーム・メタデータDTD
<!DOCTYPE "javax_imageio_jpeg_stream_1.0" [
<!ELEMENT "javax_imageio_jpeg_stream_1.0" (dqt |
dht |
dri |
com |
unknown)*>
<!-- All elements are as defined above for image metadata -->
]>