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 工作时真正需要的成语之一!

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

当您返回 FALSE 或出现您未调用的异常时

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

在您离开该功能之前进行清理。

创建一个小助手类来一直清理,您不必担心返回或抛出语句。

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 回答
0

有一个很棒的免费 C++ 图像库,叫做CxImage,它是在 zlib 许可下开源的。

无需重新发明轮子。

于 2009-06-09T13:01:15.343 回答
-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 回答