CImageクラスに格納された画像のサムネイル表示

解決


hiroaki  2006-08-19 04:41:05  No: 62757

現在,ウインドウの左側ペインにCTreeView,右側ペインにCListViewクラスを配した,エクスプローラのような実行画面の画像ビューアを作っています.
画像ファイルから,CListViewクラスのイメージリストにビットマップを表示させたいのですが,以下のようなコードを実装したところ,イメージリストに登録された画像が真っ黒な状態で表示されてしまい,手が詰まってしまいました.ご存知の方,お教えいただければ幸いに思います.

ドキュメントクラスのヘッダ(一部のみ)
public:
  CListViewEx *m_pListView;  //  リストビューへのポインタ
  list<CString> m_vFileName;  //  読み込む画像のファイル名のリスト
  int LoadThumbImages ( LPVOID lpParam ) ;  //  指定されたフォルダ内のbmpファイルからサムネイルを読み込み,表示する関数

ドキュメントクラスに実装した,サムネイル画像を読み込む関数
int CTestSplitterDoc::LoadThumbImages(LPVOID lpParam)
{
  CListCtrl& ListCtrl = this->m_pListView->GetListCtrl() ;
  CImageList* pImgList = &( this->m_pListView->m_ImageListThumb ) ;

  // イメージ リスト内のイメージの数を取得 -> 全てのイメージを削除
  
  for ( int i = 0 ; i < this->m_pListView->m_ImageListThumb.GetImageCount () ; i++ ) {
    pImgList->Remove ( i ) ;
  }

  // リスト ビュー コントロールからすべてのアイテムを削除
  ListCtrl.DeleteAllItems();

  // 新しくイメージ数をセット
  pImgList->SetImageCount ( (UINT) this->m_vFileName.size () ) ;
  
  list<CString>::iterator iter;
  
  // まず再描画フラグをクリアし、項目追加後に再描画フラグを設定
  ListCtrl.SetRedraw(FALSE);

  int nIndex = 0 ;

  for( iter =  this->m_vFileName.begin () ;
       iter != this->m_vFileName.end () ;
     iter++, nIndex++ )
  {
    // サムネイル表示    
    //ListCtrl.InsertItem( nIndex, *iter, nIndex );
    
    // Path の設定
    CString path;
    path.Empty();
    path.Format( "%s\\%s", this->m_strCurrentDirectory, *iter);

    // Image の読み込み
    CImage image;
    image.Destroy () ;
    image.Load(path);

    // Image のサイズを取得
    int sourceWidth = image.GetWidth();
    int sourceHeight = image.GetHeight();

    int destX = 0 ,
      destY = 0 ;

    // Image に対するサムネイル画像の大きさを定義
    float nPercent = 0 ;
    float nPercentW = ((float)THUMBNAIL_WIDTH/(float)sourceWidth);    // 横の割合 [%]
    float nPercentH = ((float)THUMBNAIL_HEIGHT/(float)sourceHeight);  // 縦の割合 [%]

    // 画像が縦長か横長かによって縮小の割合を縦と横のどちらを採用するのか決定
    if ( nPercentH < nPercentW )
    {  // 横長画像
      nPercent = nPercentH;
      destX   = (int)((THUMBNAIL_WIDTH - (sourceWidth * nPercent))/2);
    }else
    {  // 縦長画像
      nPercent = nPercentW;
      destY    = (int)((THUMBNAIL_HEIGHT - (sourceHeight * nPercent))/2);
    }

    int destWidth  = (int)(sourceWidth * nPercent);
    int destHeight = (int)(sourceHeight * nPercent);
  
    //  bitmapの動的読み込み
    CDC *pImageDC ;
    CDC MemDC;

    pImageDC = CDC::FromHandle ( ::GetDC ( NULL ) ) ;

    MemDC.CreateCompatibleDC( pImageDC ) ;

    CBitmap *Thumbnail = new CBitmap ;

    //  pImageDCと互換性のある仮想画面を作成する
    if ( Thumbnail->CreateCompatibleBitmap (
      pImageDC ,
      THUMBNAIL_WIDTH ,
      THUMBNAIL_HEIGHT
    ) != TRUE ) {
      TRACE ( "failed CreateCompatibleaBitmap.\n" ) ;
    }

    CBitmap *l_OldBitmap = MemDC.SelectObject ( Thumbnail ) ;

    ::SetStretchBltMode ( MemDC , COLORONCOLOR ) ;

    //  ビットマップの転送
    if ( image.StretchBlt (
      MemDC ,
      destX ,
      destY ,
      destWidth ,
      destHeight
    ) != TRUE ) {
      TRACE ( "Failed.\n" ) ;
    }

    MemDC.SelectObject( l_OldBitmap ) ;

    if ( ::ReleaseDC ( NULL , pImageDC->m_hDC ) != 1 ) {
      return FALSE ;
    }

    pImgList->Add ( Thumbnail , RGB( 0 , 0 , 0 ) ) ;

    Thumbnail->DeleteObject () ;

    ListCtrl.InsertItem( nIndex , *iter , nIndex ) ;

    if ( Thumbnail != NULL ) {
      delete Thumbnail ;
    }
    Thumbnail = NULL ;
  }

  // 再描画フラグを TRUE にし、Invalidate() によってリストボックスを再描画
  ListCtrl.SetRedraw(TRUE);

  ListCtrl.Invalidate();

  return 0;
}

長文になってしまい,申し訳ございません.よろしくお願いします.


hiroaki  2006-08-19 13:35:04  No: 62758

少々長文になってしまったので要約させて頂きます.

目標 :
CImage image に入っている画像データを CImageList::Add するために,仮想画面に描画して CBitmap Thumbnail に流し込みたい

実装 :
1. MemDC.CreateCompatibleDC () でハンドル取得
2. Thumbnail->CreateCompatibleBitmap () で仮想画面を用意
3. l_OldBitmap = MemDC.SelectObject ( Thumbnail )
4. image.StrechBlt () でデータ転送
5. MemDC.SelectObject ( l_OldBitmap )
6. Release ()
7. イメージリストへの追加

現状 :
1. imageには画像データが取り込まれている
2. 実装の 1 〜 7 の処理はどれも成功していて,エラーは返っていない
3. しかし,Thumbnailにはデータが転送されていない

重ね重ね申し訳ありません.よろしくお願いします.


hiroaki  2006-08-20 10:34:04  No: 62759

上記の件,ListCtrl::InsertItem() の引数が誤っていたためということが分かりました.長文を載せてしまい,申し訳ありません.

変更後のプログラム int CTestSplitterDoc::LoadThumbImages()内部
...略...
int Idx = pImgList->GetImageCount () ;
if ( Idx != pImgList->Add ( pThumbnail , RGB( 0 , 255 , 255 ) ) ) {
  goto Error ;
}
ListCtrl.InsertItem( Idx , *iter , Idx ) ;
...略...


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加