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