1

大きなサイズ (2000 x 2000) のビットマップがあります。そのビットマップを小さなサイズ (150 x 150) に縮小する必要があります。私はそのためのコードを書きましたが、うまくいきません。誰でも問題を見つけるのを手伝ってもらえますか? 問題は、宛先ビットマップが空白であることです。間違った DC を選択していますか? ソースと宛先の両方が正しいことを確認しました。bitblt を実行した後、宛先ビットマップに対してさらに何かを行う必要がありますか?

BOOL ReSizeBitmap(CBitmap *pBitmap, CBitmap *pNewBitmap)
{

    // Get new bitmap size
    BITMAP bmOld;
    if( !pBitmap->GetBitmap(&bmOld) )
    {
        return FALSE;
    }

    CRect rcPrev(0, 0, bmOld.bmWidth, bmOld.bmHeight);
    int newWidth  = 150;
    int newHeight = 150;

    if( newWidth < 1 || newHeight < 1 )
    {
        ::SetLastError(ERROR_INVALID_PARAMETER);
        return FALSE;
    }

    BOOL bResult = FALSE;
    try
    {   
            CDC dcDest;
            CDC dcSource;

            dcSource.CreateCompatibleDC(NULL);
            dcDest.CreateCompatibleDC(NULL);

            CBitmap* pSourceOld = dcSource.SelectObject(pBitmap);
            CBitmap* pDestold = dcDest.SelectObject(pNewBitmap);

            if( !pNewBitmap->CreateCompatibleBitmap(
                &dcDest, newWidth, newHeight) )
            {

                return FALSE;
            }

            int oldStretchMode = dcDest.SetStretchBltMode(HALFTONE);

            bResult = dcDest.StretchBlt(
                0, 0, 150, 150,
                &dcSource, 0, 0, bmOld.bmWidth, bmOld.bmHeight,
                SRCCOPY);   
            dcDest.SetStretchBltMode(oldStretchMode);

            dcSource.SelectObject(pSourceOld);
            dcDest.SelectObject(pDestold);


        bResult = TRUE;
    }
    catch(CResourceException* /*e*/)
    {

    }

    return bResult;
}
4

5 に答える 5

1

私は C++ にはあまり詳しくありませんが、新しいビットマップを作成する前に新しい DC に選択していますか? また、CreateCompatibleBitmap を呼び出すときは、互換性のあるメモリ DC ではなく、スクリーン DC (宛先 DC の作成に使用したもの) を使用する必要があると思います。したがって、GetDC で画面 DC を取得し、それを CreateCompatibleDC と CreateCompatibleBitmap の両方に渡します。

于 2009-06-09T14:31:15.520 に答える
1

コードが機能する場合でも、クリーンアップを行う必要があります。
RAIIは、MFC で作業するときに本当に必要なイディオムの 1 つです。

if( !pNewBitmap->CreateCompatibleBitmap(&dcDest, newWidth, newHeight) )
{
   return FALSE;
}

FALSE を返すか、呼び出していない例外がある場合

cSource.SelectObject(pSourceOld);
dcDest.SelectObject(pDestold); 

関数を終了する前にクリーンアップします。

常にクリーンアップする小さなヘルパー クラスを作成します。 return または throw ステートメントについて心配する必要はありません。

class SelectObjectAndCleanUp
{
    CDC& deviceContext;
    CBitmap *const oldSource;
public:
    SelectObjectCleanUp( CDC& deviceContext, CBitmap* source ) 
    : deviceContext(deviceContext),
      oldSource( deviceContext.SelectObject(source) ) {
    }

    ~SelectObjectCleanUp() {
            deviceContext.SelectObject(oldSource) 
    }
};

// use of the helper
SelectObjectCleanUp  sourceSelectionAndCleanup(dcSource, pBitmap );
SelectObjectCleanUp  destionationSelectionAndCleanup(dcDest, pNewBitmap );
于 2009-06-09T13:22:58.637 に答える
0
  • ダウンロードhttp://www.gdiwatch.com/、エラーの場所が表示される場合があります(vs 2008でも動作するようにすることができます-vs2005からvs2008ディレクトリにレジストリキーを手動でコピーするだけです)

  • SelectObject() 呼び出しの前に CreateCompatibleBitmap() を試しましたか?

  • 新しいビットマップの GetBitmap() は正しいサイズを返しますか?つまり、新しいビットマップは有効ですか?

残りは問題ないようです。このように機能するはずです。他の StretchBltModes で動作しますか?

于 2009-06-09T15:54:18.177 に答える
-1

のぞき見して解決策を提案してくれたすべての人に感謝します。何らかのデバッグの後、問題が見つかりました。これが解決策です!!!

CBitmap *SrcBmp;
HBITMAP hBmp;
hBmp= (HBITMAP)LoadImage( NULL, L"c:\\source.bmp", IMAGE_BITMAP, 0,0, LR_LOADFROMFILE );
SrcBmp = CBitmap::FromHandle(hBmp);

BITMAP BmpInfo;
SrcBmp->GetBitmap(&BmpInfo);


CDC SrcDC;
SrcDC.CreateCompatibleDC(NULL);

CBitmap DestBmp;
DestBmp.CreateCompatibleBitmap(&SrcDC,150,150);

CDC DestDC;
DestDC.CreateCompatibleDC(NULL);

CBitmap *pOldBmp1 = SrcDC.SelectObject(SrcBmp);
CBitmap *pOldBmp2 = DestDC.SelectObject(&DestBmp);

DestDC.StretchBlt(0,0,150,150,&SrcDC,0,0,BmpInfo.bmWidth,BmpInfo.bmHeight,SRCCOPY);

CImage image;
image.Attach(DestBmp);
image.Save(_T("C:\\test.bmp"), Gdiplus::ImageFormatBMP);

SrcDC.SelectObject(pOldBmp1);
DestDC.SelectObject(pOldBmp2);
于 2009-06-09T17:34:19.097 に答える