簡易画像表示(Pict)


■ 概略説明
VisualBasicとは違い、VisualC++ではJPEG、GIF等の画像を簡単に表示することはできません。これらを特別な外部ライブラリを使用せず表示する方法を紹介します。下の写真は、このプログラムの外観です。


画像読込み部は、OLEPRO32.DLLのOleLoadPicture関数を使用しています。詳細はVCのヘルプを見てください。
ただし、このサンプルは、画像読込み表示専用で、画像を保存することはできません。
表示のみ必要とするプログラムに使ってください。
■ プログラムの説明
このプログラムは、通常のSDIを元に作成されています。
画像ファイルの読込みは、CPictDoc(CDocument)のOnFileOpen()から始まり、ファイルパス決定後CViewのFileOpen()を呼び出します。
この処理のメインであるファイルの読込みは、CPictView( CCScrollView)のLoadPicture()関数内で行われます。

bool CPictView::LoadPicture(CString path)
{
        CFile                   file;
        DWORD                   flen;
        BYTE*                   pbuff                   = NULL;
        HGLOBAL                 hGlobal;
        LPVOID                  pdata;
        LPSTREAM                pIStream                = NULL;
        HBITMAP                 hBitmap                 = NULL;

        if ( m_pPicture)
                m_pPicture->Release();                          // メモリの開放.

        if ( !file.Open( path, CFile::modeRead))                // ファイル読込みエラー.
                return false;
        flen = file.GetLength();
        if ( flen <= 0)                                         // ファイルサイズエラー.
                return false;

        pbuff = new BYTE[flen];                                 // バッファの作成.
        file.Read( pbuff, flen);                                // バッファにデータを読込む.
        file.Close();

        hGlobal = GlobalAlloc( GMEM_MOVEABLE, flen);
        ASSERT( hGlobal);
        pdata = GlobalLock( hGlobal);
        ASSERT( pdata);
        memcpy( pdata, pbuff, flen);                            // バッファからグローバルメモリにコピー
        GlobalUnlock( hGlobal);
        delete pbuff;                                           // バッファの削除

        if( SUCCEEDED( CreateStreamOnHGlobal( hGlobal, TRUE, &pIStream))) 
        { 
                if( SUCCEEDED( ::OleLoadPicture( pIStream, fsts.m_size, 
                                                        FALSE, IID_IPicture, (LPVOID*)&m_pPicture))) 
                { 
                        ASSERT( m_pPicture);

                        CClientDC       screenDC( NULL);
                        // 画像のHIMETRICサイズの取得.
                        m_pPicture->get_Width( &m_hsize.cx);
                        m_pPicture->get_Height( &m_hsize.cy);
                        // 画像のピクセルサイズの取得.(変換)
                        m_psize.cx = MulDiv( m_hsize.cx, screenDC.GetDeviceCaps( LOGPIXELSX), 2540);
                        m_psize.cy = MulDiv( m_hsize.cy, screenDC.GetDeviceCaps( LOGPIXELSY), 2540);
                };

                pIStream->Release();            // メモリの開放.
        };

        return true;
}
m_pPictureは、IPictureのポインターです。

また、このサンプルでは、表示のために読込んだ画像データをIPictureのまま扱うか、CBitmapにコピーして扱うかの選択がコンパイル時のソース上のスイッチの指定で可能になっています。
このスイッチはpictView.hの最初にあります。サンプルのままの場合は、ビットマップに移すタイプになっています。
IPictureのままにしたい場合は、下記の行をコメントアウトしてビルドして下さい。
#define DRAW_BITMAPTYPE
ビットマップとして扱う場合のメリットは、表示時の画像のサイズの変更等がしやすい事です。
一方、IPictureのまま扱う場合には、JPEG・GIF等のほか、ウィンドウズのメタファイルも読込み表示することができます。
必要に応じて使ってみてください。
■ 不具合修正 12/13/2004
読者のSさんから、不具合のレポートがありました。内容は、リリース版で画像読込み時にアサーションをおこすとの事でした。
調査の結果、GlobalAllocしたメモリ領域に直接ファイルの内容を読むと、正しくデータが読込めないようです。リリース版のみの現象なので詳しくデバッグできませんが、上記のように一度ローカルメモリーによみこんでからAllocの領域にコピーすると上手く動くようです。
既に、ダウンロードした方々は、すみませんが再度ダウンロードをお願いいたします。
■ファイルのダウンロード
(MFC6.0プロジェクトファィル22KB、12/13/2004修正)