JPEG メタデータ形式の仕様および使用上の注意

JPEG メタデータ
省略されたストリーム
テーブルのソース
カラースペースの変換と一般的なマーカー
サムネールイメージ
プログレッシブエンコーディング
ネイティブメタデータ形式のツリー構造と編集
イメージメタデータ DTD
ストリームメタデータ DTD

: JPEG リーダーおよびライターオブジェクトはかなりのネイティブリソースを消費し、これらのリソースはガベージコレクションでは適切に復元されないため、不要になった時点で dispose() を呼び出すことが重要です。リーダーとライターはどちらもファイナライザで dispose() を呼び出しますが、ネイティブコードによってネイティブメモリーがなくなるまで、これらのファイナライザを呼び出すことはできません。

JPEG ライターはピクセルの置き換えをサポートしていません。

JPEG メタデータ

JPEG メタデータは、JPEG ストリーム内のマーカーセグメントに含まれるデータで構成されます。読み込みで返されるイメージメタデータオブジェクトには、そのイメージの SOI マーカーと EOI マーカー間にあるマーカーセグメントの内容が記述されます。書き込みに渡されるイメージメタデータオブジェクトは、そのイメージの SOI マーカーと EOI マーカー間にあるストリームの内容を指定し、ImageWriteParam 内のコントロールに従います。

ストリームメタデータは、省略されたイメージを含むストリームの先頭にある (または配置される) テーブル専用イメージにのみ使用されます。テーブル専用イメージはイメージとして扱われず、イメージインデックスを使用しません。ストリームの先頭にテーブル専用イメージがある場合、読み込みで返されるストリームメタデータオブジェクトには、その単一のイメージの SOI マーカーと EOI マーカー間にあるマーカーセグメントの内容が記述されます。ストリームの先頭にテーブル専用イメージがない場合、ImageReadergetStreamMetadata メソッドは null を返します。ストリームメタデータがライターに提供されると、ストリームメタデータオブジェクトのテーブルを含む単一のテーブル専用イメージがストリームの先頭に書き込まれます。ストリームメタデータオブジェクトにテーブルが含まれていない場合は、デフォルトのテーブルが書き込まれます。ストリームメタデータの唯一の目的は省略されたストリームの先頭にあるテーブル専用イメージを指定することであり、ストリームメタデータ引数は ImageWriter.prepareWriteSequence メソッドでのみ有効です。ほかのすべてのメソッドでは無視されます。

ImageWriter.getDefaultStreamMetadata メソッドは、JPEGImageWriteParam であり、かつテーブルを含んでいる場合、ImageWriteParam 引数のテーブルを含むオブジェクトを返します。それ以外の場合、返されるオブジェクトにはデフォルトのテーブルが含まれます。

ImageWriteParam 引数にテーブルが含まれている場合、ImageWriter.getDefaultImageMetadata メソッドはテーブルを含まないメタデータオブジェクトを返します。それ以外の場合は、返されるメタデータオブジェクトにはデフォルトの視覚的に損失のないテーブルが含まれます。当然、JPEGImageWriteParam にのみテーブルを含めることができます。

ignoreMetadatatrue に設定され、リーダーに入力が設定されている場合、ストリームメタデータは利用できませんがイメージメタデータは利用できます。

省略されたストリーム

リーダーとライターはどちらも、操作から操作へとテーブルを保持するため、いくつかの小さな制限があるだけで、省略されたストリームを非常に自然に使用できます。
  1. 省略されたストリームにはテーブル専用イメージを 1 つだけ含めることができ、それはストリームの先頭に位置している必要があります。それ以降にあるテーブル専用イメージは、未定義の動作を引き起こします。
  2. 省略されたストリームは完全に、かつ順序どおりに読み込む必要があります。どちらの方向にも、ランダムアクセスは許可されません。同じイメージを複数回読み込むことができます。直前の呼び出しと同一でないか、または直前の呼び出しよりも大きいイメージインデックス (または呼び出しがない場合は 0) を使用して呼び出した場合、IllegalArgumentException がスローされます。
つまり、これらの制限により、テーブルを含むイメージの挿入された、省略されたイメージをストリームに含めることができます。JPEG の要件に応じて、ストリームに現れるテーブルは、以前のテーブルのソースにかかわらず以前のテーブルをオーバーライドします。

テーブル専用イメージが一度読み込まれると、別のストリームから別のテーブル専用イメージが読み込まれるかリーダーがリセットされるまで、リーダーはその内容をストリームメタデータとして利用できます。入力を変更してもストリームメタデータはリセットされません。これは、1 つのファイルからテーブルを読み込んだあと、入力を変更して一連のイメージを含む、省略されたストリームを読み込むのに便利です。テーブルは自動的に使用され、「ストリーム」メタデータとして引き続き利用できます。

省略されたストリームは ImageWriter のシーケンス型メソッドを使用して書き込まれます。ImageWriter.prepareWriteSequence を使用すると、ストリームメタデータを使用してストリームの先頭にテーブル専用イメージを書き込み、テーブルを使用するための設定を行うことができます。ImageWriter.prepareWriteSequence にストリームメタデータが指定されていない場合、テーブル専用イメージは書き込まれません。テーブルを含まないストリームメタデータが ImageWriter.prepareWriteSequence に指定されている場合、デフォルトの視覚的に損失のないテーブルを含むテーブル専用イメージが書き込まれます。

テーブルのソース

メタデータオブジェクトにテーブルが存在する場合、イメージはテーブルとともに書き込まれ、メタデータオブジェクトにテーブルが存在しない場合はテーブルなしで書き込まれます。メタデータオブジェクトが存在しない場合はテーブルが書き込まれます。圧縮に使用するテーブルは、順に参照される次のソースのいずれかから取得されます。

  1. ImageWriteParam があり、圧縮モードが EXPLICIT に設定されている場合、品質設定を使用して構築されたデフォルトのテーブルが使用されます。メタデータにテーブルが含まれる場合、またはメタデータが存在しない場合にのみ書き込まれますが、メタデータのテーブルで置き換えられます。
  2. ImageWriteParam があり、圧縮モードが DEFAULT に設定されている場合、デフォルトの視覚的に損失のないテーブルが使用されます。メタデータにテーブルが含まれる場合、またはメタデータが存在しない場合にのみ書き込まれますが、メタデータのテーブルで置き換えられます。
  3. それ以外の場合は、ImageWriteParam の圧縮モードが MODE_COPY_FROM_METADATA である必要があります。この場合、次が使用されます。
    1. イメージメタデータ内のテーブル (存在する場合)
    2. ストリームメタデータ内のテーブル (存在する場合)
    3. JPEGImageWriteParam 内のテーブル (存在する場合)
    4. デフォルトの視覚的に損失のないテーブル
    テーブルはイメージメタデータから取得された場合にのみ書き込まれます。
この順序付けは、ほかのソースを利用できない場合にテーブルを指定する手段としてのみ JPEGImageWriteParam にテーブルを含めておく必要があるという設計目的によるものです。また、これが発生する可能性があるのは、圧縮に既知の非標準テーブルを使用してテーブルのない省略されたストリームに書き込みを行う場合のみです。

読み込み時には、前の読み込みでテーブルが設定されていない場合にのみ JPEGImageReadParam のテーブルが参照されます。JPEGImageReadParam から設定されたテーブルは、読み込まれるストリーム内に存在するテーブルでオーバーライドされます。

特定のイメージに対してイメージメタデータオブジェクトが指定されていない場合は、デフォルトのテーブルを含むデフォルトのオブジェクトが使用されます。

カラースペースの変換と一般的なマーカー

カラースペースの変換は、イメージの読み込みおよび書き込み両方のデスティネーションタイプによって制御されます。Raster の読み込み時には、カラースペースの変換は行われず、デスティネーションタイプは無視されます。この場合、デスティネーションタイプが指定されていると警告がリスナーに送信されます。Raster の書き込み時には、デスティネーションタイプがバンドの解釈に使用されます。これによって、JFIF または Adobe ヘッダーが書き込まれたり、異なるコンポーネント ID がフレームおよびスキャンヘッダーに書き込まれたりする場合があります。メタデータオブジェクト内に存在する値がデスティネーションタイプと一致しない場合は、デスティネーションタイプが使用され、警告がリスナーに送信されます。

オプションの ColorSpace のサポート: 標準プラグインによる PhotoYCC (YCC)、PhotoYCCA (YCCA)、RGBA、および YCbCrA カラースペースの処理は、次に説明するように、JPEG データの解釈に使用するライブラリの機能によって異なります。そのため、結果として起こるすべての動作はオプションによるものです。復号化のときにサポートを利用できない場合は、カラースペースが未認識として扱われ、指定された数のコンポーネントチャネルに応じたデフォルトのカラースペースを使用できます。書き込み時に、復号化の前に適切な変換を適用できない場合は Exception がスローされます。ただし、これらのカラースペースのサポートを利用できる場合、動作はドキュメント化されたとおりになります。

読み込み時には、ストリームの内容は通常の JPEG 規則によって次のように解釈されます。

符号化されたカラースペースが決定されると、ターゲットのカラースペースが次のように決定されます。

書き込みでは、適用されるカラー変換は次のように決定されます。

ソースバンドのサブセットが書き込まれる場合、カラー変換は行われません。デスティネーションは (設定されている場合)、書き込まれるバンド数と一致する必要があり、変換要求ではなく選択されたバンドの解釈に使用されます。その動作は Raster のものと同じです。すべてのバンドが書き込まれ、Raster ではなくイメージが書き込まれる場合、デスティネーションのタイプは無視され、警告がリスナーに送信されます。

デスティネーションタイプが使用されており、メタデータオブジェクトがある場合にその特性とデスティネーションタイプに互換性がなければ、デスティネーションタイプが使用され、書き込まれるメタデータは提供されるメタデータから変更され、警告がリスナーに送信されます。これには、app0JFIF および app14Adobe ノードが含まれます。sof および sos ノード内のコンポーネント ID は変更されませんが、app0JFIF ノードが存在しないかぎり、あらゆる値を使用できます。

イメージ全体を書き込む場合、デスティネーションのカラースペースはイメージの内容およびメタデータの設定に基づき、次のアルゴリズムに従って選択されます。

メタデータオブジェクトが指定されていない場合は、次のデフォルトが適用されます。

これらのイメージタイプのデフォルトのメタデータオブジェクトは、これらの設定を反映します。

メタデータオブジェクトが指定されている場合、フレームおよびスキャンヘッダー内のチャネル数は書き込まれるバンド数と常に一致する必要があり、一致しない場合には例外がスローされます。app0JFIF および app14Adobe ノードは、app14Adobe ノードが YCbCr を示し、コンポーネント ID が JFIF と互換性がある場合 (0-2) にのみ同じメタデータオブジェクトに存在することができます。さまざまなイメージタイプが次の方法で処理されます。
(すべてのマルチチャネルイメージは、カラースペースにかかわらず、メタデータオブジェクトのフレームヘッダーノード内のサンプリング係数に従ってサブサンプリングされます。)

サムネールイメージ

サムネールは JFIF および JFIF 拡張マーカーセグメントの使用によりサポートされます。書き込みメソッドで提供されるサムネールによって、含められるサムネールが決定します。メタデータに存在する app0JFIF および app0JFXX ノードには、サムネールのピクセルデータは含まれません。ただし、書き込まれるサムネールの種類は、次のようにメタデータオブジェクトの内容によって異なります。インデックス付きまたは RGB イメージとして書き込まれるサムネール、および 255 × 255 よりも大きいサムネールは、縮小ではなく、255 × 255 にクリッピングされます。JPEG イメージとして書き込まれるサムネールのサイズに制限はありません。サムネールがクリッピングされる場合には、警告がリスナーに送信されます。

サムネールを格納するメカニズムだけが JFIF または JFIF 拡張マーカーセグメントを使用するため、グレースケールまたは RGB イメージだけがサムネールを持つことができます。その他のイメージタイプを書き込むときにサムネールが存在する場合、サムネールは無視され、警告が警告リスナーに送信されます。

プログレッシブエンコーディング

書き込み操作に渡される ImageWriteParam ではプログレッシブエンコーディングを有効にする必要があり、これが有効になっていないと、メタデータオブジェクトに含まれるスキャンヘッダーにかかわらず、イメージが順番に書き込まれます。プログレッシブエンコーディングが有効で、メタデータからコピーするように設定されている場合、メタデータのスキャンヘッダーの順序を使用してイメージが書き込まれます。プログレッシブエンコーディングが有効で、デフォルトを使用するように設定されている場合、メタデータのスキャンは無視されてスキャンのデフォルト設定が使用されます。プログレッシブエンコーディングでは常に、最適化されたハフマンテーブルが強制的に使用されます。メタデータに存在するハフマンテーブルは無視され、警告が警告リスナーに送信されます。 ハフマンテーブルの最適化は ImageWriteParam で要求され、メタデータまたは ImageWriteParam 自身のハフマンテーブルはすべて無視され、そのようなテーブルが存在する場合には警告が警告リスナーに送信されます。

ネイティブメタデータ形式のツリー構造と編集

次の DTD は、IIOMetadata オブジェクトによって実際に返されるメタデータオブジェクトのツリーだけを記述しています。これらの解析の区切り文字は意味のあるメタデータを持たないため、SOIEOI、または 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 APP14APPnCOM、および不明なセグメントが書き込まれ、次に DQT (および非プログレッシブ書き込みには DHT) マーカーセグメント、続いて SOF および SOS マーカーセグメントが書き込まれます。プログレッションの制御にメタデータを使用するプログレッシブ書き込みでは、対応するノードが markerSequence ノードに存在している順序で SOS セグメントが使用されます。

resetmergeTree、および setFromTree 操作は、JPEG プラグインメタデータオブジェクトに対して次のセマンティクスを持ちます。

reset - reset の呼び出しは、ストリームの読み込みで作成されたものか ImageWriter からデフォルトのオブジェクトを取得したものかにかかわらず、メタデータオブジェクトを作成直後と同じ状態に復元します。これは、メタデータオブジェクトが作成後に何度変更されたかにかかわらず当てはまります。

mergeTree - ネイティブ形式
mergeTree 操作は、次の DTD に従う有効なツリーを受け入れ、次の順序付け規則を使用してノードをマージします。すべての場合において、新しいノードに存在するデータのみが対応する既存のノード (存在する場合) 内で変更されます。つまり、mergeTree を使用してそれらのノードを削除することはできません。ノードを削除するには、setFromTree を使用します。ツリーは IIOMetadataNode で構成される必要があります。

mergeTree - 標準形式
mergeTree 操作は、標準形式のツリーの場合、次の方法でネイティブツリーを変更します。

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 -->
]>