我有一个大尺寸的位图(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;
}
答案 0 :(得分:1)
即使代码有效,也可以做一些清理工作 当你在MFC工作时,RAII是你真正需要的成语之一!
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 );
答案 1 :(得分:1)
我对C ++不是很熟悉,但是你在创建新DC之前是否选择了新的位图?此外,当您调用CreateCompatibleBitmap时,我认为您希望使用屏幕DC(用于创建目标DC的屏幕),而不是兼容的内存DC。因此,使用GetDC获取屏幕DC,并将其传递到CreateCompatibleDC和CreateCompatibleBitmap。
答案 2 :(得分:0)
有一个很棒的免费C ++图像库,名为CxImage,在zlib许可下是开源的。
无需重新发明轮子。
答案 3 :(得分:0)
下载http://www.gdiwatch.com/,它可能会显示错误的位置(也可以将其与vs 2008一起使用 - 只需将注册表项从vs2005手动复制到vs2008目录)
您是否尝试在SelectObject()调用之前执行CreateCompatibleBitmap()?
新位图的GetBitmap()是否返回正确的大小,即新的位图是否有效?
其余的似乎没问题,它应该像我相信的那样工作。它可以与其他StretchBltModes一起使用吗?
答案 4 :(得分:-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);