bitmap 剪裁的问题

tyzyx 2009-06-22 05:39:56
目的:剪裁出目标图像的特定区域,生成一个bitmap对像

核心函数:StretchBlt CreateCompatibleBitmap


CFileDialog file(TRUE, _T("(*.bmp)|*.bmp","*.bmp" ,OFN_EXPLORER ,"位图文件(*.bmp)"));
if(!file.DoModal())
return;
CDC *pDC;
CRect rect;
GetWindowRect(rect);
pDC = GetDC();
CDC dcMemory;
CBitmap bitmapdes,bitmapsrc;
CString filename;
HDC m_hMemDC;
LONG m_nWidth,m_nHeight;
filename = file.GetPathName();
HBITMAP hbitmap = (HBITMAP) LoadImage(NULL,filename,IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
bitmapsrc.Attach(hbitmap);


//CDC *pDC;
CDC memdc;
if(!memdc.CreateCompatibleDC(pDC)) return;
memdc.SelectObject(bitmapsrc);

pDC->StretchBlt(0,0,50,50,&memdc,100,100,50,50,SRCCOPY);
// 至此,可以在对话框中显示剪裁的位图图像

//但是如何把这个显示出来的矩形区逾保存至bitmap对象中呢?
HBITMAP temp = CreateCompatibleBitmap(memdc.GetSafeHdc(),50,50);//这句生成bitmap,保存的图像是一片黑的,画出也是一版黑
memdc.DeleteDC();
bitmapdes.Attach(temp);
SaveBitmapToFile(bitmapdes,_T("C:\\a.bmp"));



BITMAP bmInfo;
bitmapdes.GetObject(sizeof(bmInfo),&bmInfo);
dcMemory.CreateCompatibleDC(pDC);
dcMemory.SelectObject(&bitmapdes);
memdc.SelectObject(bitmapdes);
//m_hMemDC = (HDC)hbitmap; // 与客户区兼容的内存DC句柄
m_hMemDC = (HDC)bitmapsrc.GetSafeHandle();
m_nWidth = bmInfo.bmWidth; // BMP图像的宽度
m_nHeight = bmInfo.bmHeight; // BMP图像的高度


pDC->BitBlt(0,0,bmInfo.bmWidth,bmInfo.bmHeight,&dcMemory,0,0,SRCCOPY);

ReleaseDC(pDC);

...全文
175 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
lambochan 2009-06-23
  • 打赏
  • 举报
回复
那都是内存GDI dc/DDB copy而已..
例如:

CBitmap bmpSrc, bmpDest;
// load 原图
HBITMAP hBitmap = (HBITMAP)LoadImage(NULL,filename,IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
bmpSrc.Attach( hBitmap );

CRect rc( 100, 100, 150 , 150 )
CutBmp( bmpDest, bmpSrc, rc );

// 那么这个:bmpDest就已经是在内存里裁剪下的CBitmap对象了,而且全是在内存做GDI操作,不需要有窗口显示.

void CutBmp( CBitmap &destBmp, CBitmap &srcBmp, CRect rcDest )
{
CDC destDC, SrcDC;
HDC hDC = ::GetDC( NULL );
destDC.CreateCompatibleDC( CDC::FromHandle( hDC ) );
SrcDC.CreateCompatibleDC( CDC::FromHandle( hDC ) );

destBmp.CreateCompatibleBitmap( CDC::FromHandle( hDC ), rcDest.Width(), rcDest.Height() );
CBitmap *pOldDest = ( CBitmap * )destDC.SelectObject( &destBmp );
CBitmap *pOldSrc = ( CBitmap * )SrcDC.SelectObject( &srcBmp );
// cut it..
destDC.SetStretchBltMode( COLORONCOLOR );
destDC.StretchBlt( 0, 0, rcDest.Width(), rcDest.Height(), &SrcDC, rcDest.left, rcDest.top,
rcDest.Width(), rcDest.Height(), SRCCOPY );
destDC.SelectObject( pOldDest );
SrcDC.SelectObject( pOldSrc );
::ReleaseDC( NULL, hDC );
}


而假如你是指内存操作不涉及GDI的话,那要另写,代码可能较长...
因为要Load DIB出来直接cut,然后绑定到CBitmap对象.
不过那不是裁剪CBitmap,而是裁剪DIB了.
tyzyx 2009-06-23
  • 打赏
  • 举报
回复
非常感谢lambochan的回答,我希望整个操作都在内存中进行

剪裁一个Cbitmap对象,然后重新生成一个Cbitmap对象,
至于显示在窗口中和保存在文件,是为了验证剪裁结果的正确性。

希望lambochan再次回答,如果分不够,我可以另开贴重加分
wscuiqiu 2009-06-23
  • 打赏
  • 举报
回复
lz程序做好了,能给我发一份么。。
正在学习这个
wscuiqiu@126.com
先谢过了
lambochan 2009-06-23
  • 打赏
  • 举报
回复
直接cut..

void CutBmp( CBitmap &destBmp, CBitmap &srcBmp, CRect rcDest )
{
CDC destDC, SrcDC;
HDC hDC = ::GetDC( NULL );
destDC.CreateCompatibleDC( CDC::FromHandle( hDC ) );
SrcDC.CreateCompatibleDC( CDC::FromHandle( hDC ) );

destBmp.CreateCompatibleBitmap( CDC::FromHandle( hDC ), rcDest.Width(), rcDest.Height() );
CBitmap *pOldDest = ( CBitmap * )destDC.SelectObject( &destBmp );
CBitmap *pOldSrc = ( CBitmap * )SrcDC.SelectObject( &srcBmp );
// cut it..
destDC.SetStretchBltMode( COLORONCOLOR );
destDC.StretchBlt( 0, 0, rcDest.Width(), rcDest.Height(), &SrcDC, rcDest.left, rcDest.top,
rcDest.Width(), rcDest.Height(), SRCCOPY );
destDC.SelectObject( pOldDest );
srcDC.SelectObject( pOldSrc );
::ReleaseDC( NULL, hDC );
}

那么就可以:
CBitmap bmp;
CRect cutRect( 100, 100, 150, 150 );
CutBmp( bmp, bitmapsrc, cutRect );
tyzyx 2009-06-23
  • 打赏
  • 举报
回复
按照4楼的做法,可以画出图像了,但还是无法保存为Cbitmap 或是 bmp文件
Soyokaze 2009-06-22
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 hendriclee 的回复:]
建议楼主用GDI+吧,很简单……
[/Quote]

GDI能完成的,不建议绕远用GDI+。因为GDI+是GDI的封装,速度比GDI要慢。
lizhigang34 2009-06-22
  • 打赏
  • 举报
回复
//但是如何把这个显示出来的矩形区逾保存至bitmap对象中呢?
HBITMAP temp = CreateCompatibleBitmap(memdc.GetSafeHdc(),50,50);//这句生成bitmap,保存的图像是一片黑的,画出也是一版黑
此时temp上什么都没有,当然是黑的,解决方法4楼已经说很清楚了
memdc.DeleteDC();
bitmapdes.Attach(temp);
SaveBitmapToFile(bitmapdes,_T("C:\\a.bmp"));
码侬 2009-06-22
  • 打赏
  • 举报
回复
我的CDib类实现了这个功能,建议楼主参考一下

DECLARE_HANDLE(HDIB);
class CDib : public CObject
{
private:
HDIB m_hDib;
};


CDib* CDib::CropDIB(LPRECT lpRect) // 扣出
{
if (m_hDib == NULL)
{
return NULL;
}


LPBITMAPINFO lpbmi = NULL;

LPSTR lpSourceBits;
LPSTR lpTargetBits;

HDC hDC = NULL;
HDC hSourceDC;
HDC hTargetDC;

HBITMAP hSourceBitmap;
HBITMAP hTargetBitmap;
HBITMAP hOldTargetBitmap;
HBITMAP hOldSourceBitmap;

DWORD dwSourceBitsSize;
DWORD dwTargetBitsSize;
DWORD dwTargetHeaderSize;

int nWidth;
int nHeight;

CDib* newDIB = new CDib;
DWORD dwSize;


LPBITMAPINFO lpSrcDIB = (LPBITMAPINFO) m_hDib;


//////////////////////////////////////////////////////////////////////////
// 信息头

// 为新的DIB申请内存并填充其BITMAPINFO结构
dwTargetHeaderSize = sizeof( BITMAPINFOHEADER ) + GetPaletteSize();

lpbmi = (LPBITMAPINFO) new BYTE[dwTargetHeaderSize];
memcpy(lpbmi, lpSrcDIB, dwTargetHeaderSize);

nWidth = RECTWIDTH(lpRect);
nHeight = RECTHEIGHT(lpRect);

lpbmi->bmiHeader.biWidth = nWidth;
lpbmi->bmiHeader.biHeight = nHeight;

// 利用DIBSections和BitBlt函数进行格式转换
hDC = GetDC( NULL );

hTargetBitmap = CreateDIBSection( hDC, lpbmi, DIB_RGB_COLORS, (VOID **)&lpTargetBits, NULL, 0 );
hSourceBitmap = CreateDIBSection( hDC, lpSrcDIB, DIB_RGB_COLORS, (VOID **)&lpSourceBits, NULL, 0 );
hSourceDC = CreateCompatibleDC( hDC );
hTargetDC = CreateCompatibleDC( hDC );

dwSourceBitsSize = lpSrcDIB->bmiHeader.biHeight * GetBytesPerLine();
dwTargetBitsSize = lpbmi->bmiHeader.biHeight * WIDTHBYTES(nWidth*GetBitsCount());

memcpy( lpSourceBits, (void *)GetDIBBits(), dwSourceBitsSize );
lpbmi->bmiHeader.biSizeImage = dwTargetBitsSize;

// 把DIBSections选入设备上下文
hOldSourceBitmap = (HBITMAP)SelectObject( hSourceDC, hSourceBitmap );
hOldTargetBitmap = (HBITMAP)SelectObject( hTargetDC, hTargetBitmap );

// Crop
BitBlt(hTargetDC,
0,
0,
nWidth,
nHeight,
hSourceDC,
lpRect->left,
lpRect->top,
SRCCOPY);


SelectObject( hSourceDC, hOldSourceBitmap );
SelectObject( hTargetDC, hOldTargetBitmap );
DeleteDC( hSourceDC );
DeleteDC( hTargetDC );
ReleaseDC( NULL, hDC );


GdiFlush();

// 拷贝位数据
dwSize = dwTargetHeaderSize + dwTargetBitsSize;
newDIB->m_hDib = (HDIB) new BYTE[dwSize];

// 信息头
memcpy( newDIB->m_hDib, lpbmi, dwTargetHeaderSize );

// DIB数据
memcpy((BYTE*)newDIB->m_hDib + dwTargetHeaderSize, lpTargetBits, dwTargetBitsSize );

DeleteObject( hTargetBitmap );
DeleteObject( hSourceBitmap );

delete[] lpbmi;
lpbmi = NULL;

return newDIB;
}
fengrx 2009-06-22
  • 打赏
  • 举报
回复
HBITMAP hBitmap = CreateCompatibleBitmap(memdc.GetSafeHdc(), 50, 50);
HDC hNewDC = CreateCompatibleDC(memdc.GetSafeHdc());
HBITMAP hOldBitmap = SelectObject(hNewDC, hBitmap);
BitBlt(hNewDC, 0, 0, 50, 50, memdc.GetSafeHdc(), 100, 100, SRCCOPY);
SelectObject(hNewDC, hOldBitmap);
tkminigame 2009-06-22
  • 打赏
  • 举报
回复
HBITMAP temp = CreateCompatibleBitmap(memdc.GetSafeHdc(),50,50);//这句生成bitmap,保存的图像是

这个当然是一片黑,因为它只生成一个指定长宽的空白图片,你还要再画一次。

pDC.SelectObject(temp);
pDC->StretchBlt(0,0,50,50,&memdc,100,100,50,50,SRCCOPY);
greatws 2009-06-22
  • 打赏
  • 举报
回复
你只创建了一个兼容的DC,并没有进行拷贝啊,所以是黑的


HBITMAP hBitmap = CreateCompatibleBitmap(memdc.GetSafeHdc(), 50, 50);
HDC hNewDC = CreateCompatibleDC(memdc.GetSafeHdc());
HBITMAP hOldBitmap = SelectObject(hNewDC, hBitmap);
BitBlt(hNewDC, 0, 0, 50, 50, memdc.GetSafeHdc(), 0, 0, SRCCOPY);
SelectObject(hNewDC, hOldBitmap);

skyxie 2009-06-22
  • 打赏
  • 举报
回复
这个实际就是 hbitmap 保存为 .bmp的问题

这里有函数

BOOL SaveBmp(HBITMAP hBitmap, CString FileName)
hendriclee 2009-06-22
  • 打赏
  • 举报
回复
hendriclee 2009-06-22
  • 打赏
  • 举报
回复
建议楼主用GDI+吧,很简单……

19,468

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 图形处理/算法
社区管理员
  • 图形处理/算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧