SOI マーカ、量子化テープル定義セグメント、ハフマンテープル定義セグメント、フレー ムヘッダ、スキャンヘッダなどを作成して、 2.62 節 ( p. 34 ) のフォーマットで記録します。 そして、最後に EOI マーカを記録して終了します。 Fig. 2.27 符号化処理の流れ DCT 係数の統計をとる 量子化 DCT 不完全 MCU の補完 画像を成分に分解 量子化テーブル定義セグメントをファイルに記録 SOI をファイルに記録 開始 省略化 ハフマンテーブル定義セグメントをファイルに記録 ハフマンテーブルを構成する ハフマン符号化 スキャンヘッダをファイルに記録 フレームヘッダをファイルに記録 42 MCU 単位でファイルに記録 EOI をファイルに記録 終了 第 2 章 JPEG におけるデジタル静止画像圧縮
ドキュメントクラスは、 CJpegCodWi nDo c です。 BMP ファイルのオープンと表示、 JPEG 符号化とファイル保存の制御を行います。 BMP ファイルならばすべて開くことがで きますが、 JPEG 符号化できるのは 16 色以上のデータだけです。 16 色未満のデータは表示 はできますが、 JPEG 符号化はできません。 オープンした BMP 画像の表示を行うのが CJpegC 。 dW 土 nv 土 ew です。このクラスは CScr011V 土 ew からの派生クラスです。 BMP データから DIB (RGB) データを作るために CDib というクラスを作成しました。 その他に CJpegCoder と coutBitStream が含まれています。 このプロジェクトは CJpegC 。 der と c 〇 u に B 土し s し ream の動作を確認するためのもので す。ですから、 BMP ファイルのオープンと表示、符号化して得られた JPEG データのファ イル保存機能しかあり . ません。実用的なアプリケーションは読者が独自に作成してください。 ・ファイルの読み出し メニューから [ ファイル ] - [ 開く ] を選ぶと、ファイル選択ダイアログが開きます。 ファイルを選択すると、 CJpegCodWinDoc: :OnOpenDocument( ) が呼び出されます。 こで BMP ファイルを読み込み、 DIB データを作成しています。 / / CJpegC0dWinDoc コマンド BOOL CJpegCodWinDoc : : OnOpenDocument (LPCTSTR 1pszPathName ) if ( ! CDocument : : OnOpenDocument ( 1pszPathName ) ) return FALSE; / / TODO : この位置に固有の作成用コードを追加してください try{ CFi1e BmpFi1e (1pszPathName, CFi1e: :modeRead) : m Dib . BmpLoad(BmpFi1e) : BmpFi1e . C10se() : }catch (CDibException eDib) { CString strMessage; 1pszPathName : strMessage strMessage + = strMessage + = eDib . GetErrMessage( ) ー AfxMessageBox(strMessage) 冫 return FALSE; }catch (CException e) { TCHAR szErrBuf [ 256 ] ー e . GetErrorMessage(szErrBuf, AfxMessageBox ( szErrBuf ) : return FALSE : return TRUE ー DIB データができれば、 CJpegCodWinView : s 土 z e 0 f ( s z ErrBu f ) ) : :0nDraw( ) で表示されます。 90 第 4 章実装
5.1.4 ー = 。 ツール テストを行うには次のソフトが必要です。 ・テ / ヾッガ ・ JPEG データの表示ができるソフト ( ネットスケーブナビゲータなど ) また、次のようなソフトや道具があるとより便利です。 ・ファイルのバイナリーダンプができるソフト ・ 2 つのファイルをバイナリーで比較できるソフト ・関数電卓 ・縦罫線のあるメモ用紙 ・画面の拡大表示ができるツール ・ JPEG データと BMP, P ℃ T データが作成できるソフト マットでの作成はもちろん、 JPEG データも作れるソフトがあれば、より便利です。 認が容易なテストデータが作れると便利です。 BMP や PICT などの OS で使用するフォー テストデータは付録 CD - ROM に用意しましたが、発生している不具合に合わせて、確 です。また、バイナリーで編集ができると動作の確認のための実験を行いやすくなります。 バイナリーのダンプはデバッガなどでもできますが、専用ツールがあるとたいへん便利 [C-JPEG] (CJpegCoder での符号化例 JPEG ファイル ) CBMP] (CJpegCoder 用 BMP ファイル ) [TestData] は、以下のように配置しています。 付録 CD-ROM の CTestData] フォルダにテストデータを用意しました。 Windows 用で 5.2 ーテストデータについて 186 第 5 章テスト で符号化したものです。 CJpegCoder の符号化テストの際に利用してください。 CC-JPEG] フォルダのデータは、 CBMP], CPICT] フォルダのデータを c こ pegc 。 der [D-JPEG] ( 市販グラフィックソフトでの符号化例 JPEG ファイル ) [C-JPEG] (CJpegCoder での符号化例 JPEG ファイル ) (CJpegCoder 用 P ℃ T ファイル ) CP ℃ T] [TestData] Macintosh 用では、以下のようになっています。 [D-JPEG] ( 市販グラフィックソフトでの符号化例 JPEG ファイル )
iJpegSize; Ⅲ bCodeF1g = TRUE; delete rp; delete gp; delete bp; ますはじめに、 JPEG データの属性を設定します。画像サイズは BMP データのとおりで、 成分数は 3 に固定します。コメントは適当なものを設定しています。画像密度は 72dpi と しています。 次に、 DivideBitData( ) で RGB データを作成します。 こまでできたら、いよいよ符号化を実行します。ます、 CJpegcoder のインスタンス を生成し、 RGB データのアドレスを渡します。次に、 SetJpegProperty() で JPEG の画 像属性をセットします。そして、 D 。 c 。 d 土 ng ( ) で符号化を実行します。最後に、データを 取り出します。 Docoding() では、エラーが発生するかもしれません。工ラーの場合、例外を送出して ダイアログを表示します。 0 コ 2 ・ JPEG 復号アプリケーション ・プロジェクトの構成 JPEG 復号プロジェクトワークスペースは "JpegDecodeWin. dsw" という名称です。ワー クスペースの FileView を Fig. 4.2 に示します。 プロジェクトの種類は "MFC AppWizard(exe)" の "MDI" です。印刷や保存はサポート しません。 アプリケーションクラスは CJpegDecodeWinApp です。 ドキュメントクラスは CJpegDecodeWinDoc です。復号する JPEG ファイルのオープ ンと復号・表示の制御を行います。 復号した画像の表示を行うのが CJpegDecodeWinView です。このクラスは cscr 。 11 v 土 ew からの派生クラスです。 RGB データから DIB データを作るために、 CD 土 bExcep 。 n というクラスを作成しま 0 その他に CJpegDecoder と c 工 nBitstream が含まれています。 このプロジェクトは、 CJpegDecoder と c 工 nBitStream の動作を確認するためのもの です。ですから、 JPEG ファイルのオープンと復号された画像の表示機能しかありません。 実用的なアプリケーションは読者が独自に作成してください。 ・ファイルの読み出し メニューから [ ファイル ] - [ 開く ] を選ぶと、ファイル選択ダイアログが開きます。 ファイルを選択すると、 CJpegDecodeWinDoc : :on0penDocument( ) が呼び出されます。 こで、 L 〇 adJpegF 土 le ( ) を呼び出します。ファイルの読み込みはこのメソッドの前半 4.1 上位クラス で行っています。
ファイル名 ファイルは、クラスごとに作成します。クラスの宣言は、ヘッダファイル " クラス名 . h " で行います。メソッドは、ソースファイル " クラス名 . cpp" に記述します。 CJpegC0der. h, CJpegC0der. CPP 例 CJpegC0der → 他にも、必要に応じて適宜ヘッダファイルを作成します。そのファイル名は一見して意 味のわかるものにします。 3 ゴ 2 ー 型 規約ではありませんが、プログラム中でよく使う型名にし ypedef 宣言を用いて、短い 同義語を定義しています。たいへん便利ですので、これ以降、本文中でも使用します。 typedef unsigned char u—char : typedef unsigned 土 n に u—int 冫 32 ー全体の構成 本書では主に 2 つのクラスを作成します。 1 つは RGB 表色系で構成された画像を JPEG 形式に符号化するクラス、 CJpegCoder です。もう 1 つは、 JPEG 形式のデータを復号し て RGB 表色系の画像データを作るクラス、 CJpegDecoder です。 JPEG データの読み書きでは、バイト単位でなくビット単位で行わなければならないこ とがあります。この操作は、 c + + の入出力機能や各種 ()S のシステムコールだけでは不十 分です。そこで、ビット単位の書き込みを行うクラス c 〇 u し B s し rea Ⅲと、ビット単位の 読み出しを行うクラス c 工 nB s し ream を作成します。 CJpegcoder, CJpegDecoder を生成して呼び出すクラス、およびアプリケーション 全体の構成については、本書では詳しくは説明しません。付録 CD-ROM に、 Windows 用 の Visual C + + 5.0 と MFC4.2 を用いたプロジェクトファイル群と、 Macintosh 用の CodeWarroirPr03 と PowerPIant 1.9 を用いたプロジェクトファイル群を添付しました。 これらのプロジェクトを調べてみてください。それぞれのプラットフォームとフレーム ワークでのアプリケーション開発の経験が十分にあれば、アプリケーションで JPEG デー タを扱う方法が簡単にわかるでしよう。 第 2 章でも触れたとおり、エラー処理はとても重要です。プログラムのなかでは、多く の場所でエラーが発生する可能性があります。しかし、 C + + の例外処理を用いれば、そ れらのエラーに一括して対処することができます。つまり、少数の catch ハンドラを効 果的な位置に設けることで、エラー処理をソースプログラムの一部に集中させることがで 3.2 全体の構成
/ / CJpegC0dWinView クラスの描画 void CJpegC0dWinView: : OnDraw (CDC* PDC) CJpegCodWinDoc* PDOC = GetDocument ( ) 冫 ASSERT_VAL 工 D (pDoc ) ー / / TODO : この場所にネイテイプデータ用の描画コードを追加します cpoint point(O,O) ー / / D ェ B を描画 CDib* pDib = pDoc->GetDib( ) ー pDib—>Draw 工 mage (PDC ′ point) : ・符号化の実行とファイルの書き込み / / TODO : この位置に固有の処理を追加するか、または基本クラスを呼び出してください BOOL CJpegCodWinDoc : : OnSaveDocument (LPCTSTR lpszPathName) / / ユ PEG ファイルセープ時の処理 ます。符号化が完了したら、 JPEG データをファイル保存します。 す。このメソッドで CJpegCodWinDoc: :DoCoding( ) を呼び出し、 JPEG 符号化を行い ファイルが指定されると、 CJpegCodWinDoc: :0nSaveDocument( ) が呼び出されま て保存 ] を選ぶと実行されます。 符号化はメニューから [ ファイル ] ー [ 上書き保存 ] または [ ファイル ] ー [ 名前を付け JpegFiIe . WriteHuge(pBitStream, (DWORD)iSize) : CFiIe: :modeCreatelCFiIe: :modeWrite lCFi1e: :typeBinary) : CStdioFiIe JpegFiIe(1pszPathName, / / JPEG ファイルの保存 DoCoding(pBitStream, iSize) ー / / JPEG 符号化 try{ 土土 S 土 Z e char* pBitStream = NULL; JpegFi1e . C10se(); }catch(CException e) { TCHAR szErrBuf[256]; e . GetErrorMessage ( szErrBuf , AfxMessageBox ( szErrBuf ) : return FALSE; }catch(CString strErr) { AfxMessageBox(strErr) : return FALSE; sizeof(szErrBuf) ) : 4.1 上位クラス
4.1 ー上位クラス この節では、アプリケーションとして動作させるためのコードについて説明します。そ れはユーザインタフェースを担当し、アプリケーションの起動・終了処理、ファイル操作、 ウインドウ描画などを行うクラスのコードです。制御構造上、 CJpegCoder などのインス タンスを生成してメッセージを送出するクラスを含むので、本書ではまとめて上位クラス と呼ぶことにします。 上位クラスはプラットフォームに依存するので、 Windows 用と Macintosh 用について 別々に説明します。他の OS に適用する場合は、これらの説明を参考にしてコーディング してください。 ご処理の内容 作成するアプリケーションは次の 2 つです。 ・ JPEG 符号化アプリケーション このアプリケーションは、ユーザからの「ファイルオープン」コマンドで画像ファイル をオープンして表示します。そして、「符号化」コマンドで JPEG 符号化を行い、ファイ ル出力処理を行います。印刷やその他の高度な機能はサポートしません。 ・ JPEG 復号アプリケーション このアプリケーションは、ユーザからの「ファイルオープン」コマンドで JPEG データ ファイルをオープンし、すぐに復号を行って画面に表示します。復号結果のファイル保存、 Windows 印刷、その他の高度な機能はサポートしません。 してみてください。 CJpegCoder と c ユ pegDec 。 der の使い方を参考にして、独自にアプリケーションを作成 これ以外の開発環境を使用している方は、本書付属のサンプルプログラム中の た、変更した部分には筆者らのコメントがつけてあります。 てください。ソースプログラム中には、 AppWizard が作成したコメントがあります。ま いて作成しています。 Visual C + + と MFC については、それぞれのドキュメントを参照し Windows 用のアプリケーションは、マイクロソフト社のⅥ suaIC + + 5.0 と MFC4.2 を用 第 4 章実装
ヲ / 0 -6 っ 0 っ 0 っ 0 - ) -6 ラ / ラ / 8 8 8 8 3.5.2> CInBitStream クラス・ 3.5.3> CJpegC0der クラス・ 3.5.4> CJpegDecoder クラス・ 3 工ラー処理 3.6.1 工ラー処理の方針 3.6.2> 工ラー通知用クラス 3.6.3> catch する場所 ・・・ 88 ・・・ 88 ・・・ 88 ・・・ 107 ・・・ 107 ・・・ 107 ・・ 112 ・・・ 116 ・・・ 116 ・・・ 116 ・・・ 121 ・・・ 154 ・・・ 159 ・・・ 159 ・・・ 159 ・・・ 140 ・・・ 144 実装 第 4 章 上位クラス 4.1 4.1.1> 処理の内容・ 4.1 .2> Windows 4.1.3> Macintosh ・ 4.2 COutBitStream クラス 4.2.1 ヘッダファイル・・ 4.2.2> インタフェース・・ 4.2.3> 非公開メソッド・・ 4.3 CJpegC0der クラス 4.3.1> ヘッダファイル・・ 4.3.2> インタフェース・・ 4.3.3> 非公開メソッド・・ 44 CInBitStream クラス 4.4.1> ヘッダファイル・・ 4.4.2> インタフェース・・ 4.4.3> 非公開メソッド・・ 4.5 CJpegDecoder クラス 4.5.1 ヘッダファイル・・ 4.5.2> インタフェース・・ 4.5.3> 非公開メソッド・・
・ファイルの読み出し メニューから CFiIe] ー COpen. 」を選ぶと、 CJpegDecoderApp : : ChooseDocument ( ) が呼び出されます。こで、ファイルタイプを , JPEG , と指定しています。 / / Browse for a document . UDesktop: :Deactivate( ) : / / Deactivate the desktop . CJpegDecoderApp : : ChooseDocument ( ) VOid SFTypeList PPC DEBUG D00 PP \ ファイル リンク Fig. 4.4 JPEGDecoder StandardFi 1eRep1y App 石 0 ・ 0 龜 ファイル theTypeList theReply; JPEGDecoder ま : ファイルタイプの指定 ClnBitStream. cpp 陽 CJpegDecoder. cpp CJpegDecoder App. 叩 置 CJpegDocument. 叩 CJpegView. cp 陽 MuPP—DebugHeaders. pch + + . JpegDecoder. ppob . JpegDecoder. r 0 . C010rA1 rt に 0n5. rsrc . PP Action strings. rsrc . PP App1eEvents. rsrc . PP Deb リ 9A1 . rc . PP Doc リ n A1曾r愑 . rsrc App1e Events Commanders は F れ & Stream Support Uti1ities を Link T ・「・彙 5 99 ファイル ー 8K 1 624 10444 2 1 24 引 00 1340 n/a n/a n/a n/a n/a n/a n/a n/a 20K 54K 29K 17K 13K 17K 152K 52K 54K 205K 0 615K 537 1780 1 61 9 1626 1055 n/a n/a n/a n/a n/a n/a n/a n/a 6 55K 1 OK 66K 0 1 51 K 4.1 曰△ 上位クラス 105
ただちに結果がわかります。実は、ファイルの比較をするのであれば、ヘッダ部分もエン トロピー符号化セグメント部分も同時にテストできるのですが、問題をきり分けやすくす るために、 こでは 2 つに分けて考えることにします。 0 」 1 ・ヘッダ書き込み c こ pegc 〇 der ではテープルを固定しています。ヘッダの書き込み内容のテストは 1 度行 えばよいでしよう。 ファイルコンペアで相違が見つかった場合は、 CJpegDecoder を利用して前処理のテ ストをしてください ( 5.3.2 節 , p. 19D 。メンバ変数の値に異常が見つかったら、 CJpegCoder: :writeHeader( ) の該当部分をデバッガでステップ実行して動作を確認し てください。 ロ 12 ・符号化 ます、入力データファイルを選んでオープンします。そして、符号化を行い、ファイル を保存します。その結果を℃ - JPEG] フォルダの同名ファイルと比較します。比較には ファイルコンペアソフトを使うか、または JPEG データを表示できるソフトを使って目で 確認してください。目で確認するときは画面の拡大表示ができるツールがあれば、特に色 の変化の激しい部分を拡大して確認してください。 2 つのデータの表示結果が異なる場合は、 5.4.4 節 ( p. 206 ) を参考にして、原因となりそ うな部分に見当をつけ、プレークポイントを設定して実行します。プログラムが一時停止 したらメモリ領域や変数の内容を確認します。 また、 c ユ pegDec 。 der のテストが終わっていれば、エントロピー符号化セグメントの 一部が異なるときには、次のようにして場所を調べられます。 CJpegDecoder で復号処理を行い、データに異常がある場所を見つけます。そのとき のユニット位置、プロック位置、成分番号、 DCT 係数番号などをメモします。 c こ pegc 。 der で、元画像に対して同じ位置を符号化する直前で停止するようにデバッガでプレークポイ ントを設定します。プログラムが停止したらステップ実行して動作を確認してください。 542 ヘッダ書き込みのテスト 前処理での異常は c ユ pegDecoder のバグではなく、入力データ (CJpegCoder で符号化 で符号化したファイルを検証してください。 CJpegDecoder のテストが終わっていれば、 き ) は 5.3.2 節 ( p. 19D の CJpegDecoder の前処理のテストを参考にして、 CJpegCoder ファイルコンペアで相違が見つかったとき ( または、ファイルコンペアツールがないと してください。 当な名前をつけて保存してください。そして、 HEADER. JPG とファイルコンペアで比較 ヘッダの内容を確認するために、 HEADER. * を入力データとします。符号化結果に適 5.4 CJpegCoder のテスト したデータ ) の異常が原因と考えてよいでしよう。