几何尺寸与公差论坛------致力于产品几何量公差标准GD&T (GDT:ASME)|New GPS(ISO)研究/CAD设计/CAM加工/CMM测量  


返回   几何尺寸与公差论坛------致力于产品几何量公差标准GD&T (GDT:ASME)|New GPS(ISO)研究/CAD设计/CAM加工/CMM测量 » 仿射空间:CAX软件开发(三)二次开发与程序设计 » 程序设计 » vc编程
用户名
密码
注册 帮助 会员 日历 银行 搜索 今日新帖 标记论坛为已读


回复
 
主题工具 搜索本主题 显示模式
旧 2009-09-25, 01:50 PM   #1
huangyhg
超级版主
 
huangyhg的头像
 
注册日期: 04-03
帖子: 18592
精华: 36
现金: 249466 标准币
资产: 1080358888 标准币
huangyhg 向着好的方向发展
默认 关于位图的一点疑问

关于位图的一点疑问


void CBmpDemoDlg::OnPaint()
{
CPaintDC dc(this); // device context for painting
if (!m_dcMem.GetSafeHdc())
{
m_dcMem.CreateCompatibleDC(&dc);
}
if (!m_bmpMem.GetSafeHandle())
{
if (m_dcMem.GetSafeHdc())
{
m_bmpMem.CreateCompatibleBitmap(&dc,m_rcClient.Width(),m_rcClient.Height());
m_dcMem.SelectObject(&m_bmpMem);
}
}
ASSERT(m_dcMem.GetSafeHdc()!=NULL);
ASSERT(m_bmpMem.GetSafeHandle()!=NULL);
m_dcMem.FillSolidRect(m_rcClient,RGB(129,0,0));

CDC dcMem;
dcMem.CreateCompatibleDC(&dc);
/*CBitmap *pBmpTemp=m_dcMem.GetCurrentBitmap();*/
CBitmap bmpMem;
bmpMem.CreateCompatibleBitmap(&dc,m_rcClient.Width(),m_rcClient.Height());

m_dcMem.SelectObject(&bmpMem); //1
dcMem.SelectObject(&m_bmpMem); //3

dcMem.FillSolidRect(m_rcClient,RGB(50,200,0)); //2

dc.BitBlt(m_rcClient.left,m_rcClient.top,m_rcClient.Width(),m_rcClient.Height(),&dcMem,0,0,SRCCOPY);
}
上述代码仅仅是为了测试,
现在的疑问是1处的代码如果不调用,那么dcMem接下来的绘图操作2失效了?

疑问2 是关于GetCurrentBitmap,MSDN上面说这个函数会返回当前DC中选入的Bitmap,
如果我把3改成dcMem.SelectObject(dcMem.GetCurrentBitmap),为什么会没有效果呢?


////////////////////////////////////

BOOL CBmpDemoDlg::SaveBitmapFile(HDC p_hDC, LPCTSTR p_pchFileName)
{

HBITMAP hBmp = (HBITMAP)GetCurrentObject( p_hDC, OBJ_BITMAP );

BITMAPINFO stBmpInfo;
stBmpInfo.bmiHeader.biSize = sizeof( stBmpInfo.bmiHeader );
stBmpInfo.bmiHeader.biBitCount = 0;
GetDIBits( p_hDC, hBmp, 0, 0, NULL, &stBmpInfo, DIB_RGB_COLORS );

ULONG iBmpInfoSize;
switch( stBmpInfo.bmiHeader.biBitCount )
{
case 24:
iBmpInfoSize = sizeof(BITMAPINFOHEADER);
break;
case 16:
case 32:
iBmpInfoSize = sizeof(BITMAPINFOHEADER)+sizeof(DWORD)*3;
break;
default:
iBmpInfoSize = sizeof(BITMAPINFOHEADER)
+ sizeof(RGBQUAD)
* ( 1 << stBmpInfo.bmiHeader.biBitCount );
break;
}

PBITMAPINFO pstBmpInfo;
if( iBmpInfoSize != sizeof(BITMAPINFOHEADER) )
{
pstBmpInfo = (PBITMAPINFO)GlobalAlloc
( GMEM_FIXED | GMEM_ZEROINIT, iBmpInfoSize );
PBYTE pbtBmpInfoDest
= (PBYTE)pstBmpInfo;
PBYTE pbtBmpInfoSrc
= (PBYTE)&stBmpInfo;
ULONG iSizeTmp
= sizeof( BITMAPINFOHEADER );

while( iSizeTmp-- )
{
*( ( pbtBmpInfoDest )++ ) = *( ( pbtBmpInfoSrc )++ );
}
}

HANDLE hFile
= CreateFile
( p_pchFileName, GENERIC_WRITE, 0
, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_ARCHIVE
, NULL );

BITMAPFILEHEADER stBmpFileHder;
stBmpFileHder.bfType = 0x4D42; // 'BM'
stBmpFileHder.bfSize
= sizeof(BITMAPFILEHEADER)
+ sizeof(BITMAPINFOHEADER)
+ iBmpInfoSize
+ pstBmpInfo->bmiHeader.biSizeImage;
stBmpFileHder.bfReserved1 = 0;
stBmpFileHder.bfReserved2 = 0;
stBmpFileHder.bfOffBits = sizeof(BITMAPFILEHEADER) + iBmpInfoSize;

DWORD dRet;
WriteFile
( hFile, (LPCVOID)&stBmpFileHder
, sizeof(BITMAPFILEHEADER), &dRet, NULL );

PBYTE pBits
= (PBYTE)GlobalAlloc
( GMEM_FIXED | GMEM_ZEROINIT
, stBmpInfo.bmiHeader.biSizeImage );

HBITMAP hBmpOld;
HBITMAP hTmpBmp
= CreateCompatibleBitmap
( p_hDC
, pstBmpInfo->bmiHeader.biWidth
, pstBmpInfo->bmiHeader.biHeight );
hBmpOld = (HBITMAP)SelectObject( p_hDC, hTmpBmp );
GetDIBits
( p_hDC, hBmp, 0, pstBmpInfo->bmiHeader.biHeight
, (LPSTR)pBits, pstBmpInfo, DIB_RGB_COLORS );

WriteFile
( hFile, (LPCVOID)pstBmpInfo
, iBmpInfoSize, &dRet, NULL );

WriteFile( hFile, (LPCVOID)pBits
, pstBmpInfo->bmiHeader.biSizeImage
, &dRet, NULL );

SelectObject( p_hDC, hBmpOld );
DeleteObject( hTmpBmp );
CloseHandle( hFile );
GlobalFree( pstBmpInfo );
GlobalFree( pBits );
return TRUE;
}
这段代码本意是将当前DC内容保存到文件,但是如果调用时传入的DC是任何窗口dc,其结果是保持的是整个屏幕的位图,这里用到了GetCurrentObject,是不是这个函数返回的HBITMAP,只能取其数据,将其选入dc作为兼容位图就不行?
/////////////////////////////////////
void CBmpDemoDlg::OnPaint()
{
CPaintDC dc(this); // device context for painting
if (!m_dcMem.GetSafeHdc())
{
m_dcMem.CreateCompatibleDC(&dc);
}
if (!m_bmpMem.GetSafeHandle())
{
if (m_dcMem.GetSafeHdc())
{
m_bmpMem.CreateCompatibleBitmap(&dc,m_rcClient.Width(),m_rcClient.Height());
m_dcMem.SelectObject(&m_bmpMem);
}
}
ASSERT(m_dcMem.GetSafeHdc()!=NULL);
ASSERT(m_bmpMem.GetSafeHandle()!=NULL);
m_dcMem.FillSolidRect(m_rcClient,RGB(129,0,0));

CDC dcMem;
dcMem.CreateCompatibleDC(&dc);
/*CBitmap *pBmpTemp=m_dcMem.GetCurrentBitmap();*/
CBitmap bmpMem;
bmpMem.CreateCompatibleBitmap(&dc,m_rcClient.Width(),m_rcClient.Height());

//类成员内存DC在上面已经选择了类成员位图对象了,
//下面这句执行后,就会将临时创建的位图对象选进了DC,而将类成员位图对象选出来了,
//之后的绘图操作均会被绘制到临时的位图对象中,而类成员位图对象则不会被绘制到。
m_dcMem.SelectObject(&bmpMem); //1


//这句是将类成员位图对象选进了临时的DC中,如果函数退出时没有进行选出,
//则会导致该位图对象的损坏。
dcMem.SelectObject(&m_bmpMem); //3

dcMem.FillSolidRect(m_rcClient,RGB(50,200,0)); //2

dc.BitBlt(m_rcClient.left,m_rcClient.top,m_rcClient.Width(),m_rcClient.Height(),&dcMem,0,0,SRCCOPY);

//这边应该要将类成员位图对象选出,否则会导致下次OnPaint没有效果。
//因为m_bmpMem != NULL,而它的数据却已经损坏,不再可以被选进DC中了。
//所以第二次的OnPaint的运行效果就没有了。
//应该在这里将dcMem的OldBMP选进来!!!

}
上述代码仅仅是为了测试,
现在的疑问是1处的代码如果不调用,那么dcMem接下来的绘图操作2失效了?

疑问2 是关于GetCurrentBitmap,MSDN上面说这个函数会返回当前DC中选入的Bitmap,
如果我把3改成dcMem.SelectObject(dcMem.GetCurrentBitmap),为什么会没有效果呢?

关于你的上面2点疑问,我觉得首先需要重新调整你的代码写法,然后再来回答。
我们感觉你的这个函数代码在后面部分是乱的,所以调整后,问题自然就不存在了。
GetCurrentBitmap的意思是返回DC的当前选中的HBitmap,而你在后面又选进来了,
这不是逻辑上有问题吗?选进一个已经选中的对象,是不是一个逻辑错误呢?


////////////////////////////////////////////////////////////////
BOOL CBmpDemoDlg::SaveBitmapFile(HDC p_hDC, LPCTSTR p_pchFileName)
{
//你这样获得的位图有一个问题,就是你这个位图目前还在DC中,
//如果你要使用那个位图,必须将该位图选出DC,这样可以保证该位图不会被DC临时
//修改。一般不要这样使用GetCurrentObject,最好选进一个Bitmap,返回值就是我们想要的那个位图了。

HBITMAP hBmp = (HBITMAP)GetCurrentObject( p_hDC, OBJ_BITMAP );

BITMAPINFO stBmpInfo;
stBmpInfo.bmiHeader.biSize = sizeof( stBmpInfo.bmiHeader );
stBmpInfo.bmiHeader.biBitCount = 0;
GetDIBits( p_hDC, hBmp, 0, 0, NULL, &stBmpInfo, DIB_RGB_COLORS );

ULONG iBmpInfoSize;
switch( stBmpInfo.bmiHeader.biBitCount )
{
case 24:
iBmpInfoSize = sizeof(BITMAPINFOHEADER);
break;
case 16:
case 32:
iBmpInfoSize = sizeof(BITMAPINFOHEADER)+sizeof(DWORD)*3;
break;
default:
iBmpInfoSize = sizeof(BITMAPINFOHEADER)
+ sizeof(RGBQUAD)
* ( 1 << stBmpInfo.bmiHeader.biBitCount );
break;
}

PBITMAPINFO pstBmpInfo;
if( iBmpInfoSize != sizeof(BITMAPINFOHEADER) )
{
pstBmpInfo = (PBITMAPINFO)GlobalAlloc
( GMEM_FIXED | GMEM_ZEROINIT, iBmpInfoSize );
PBYTE pbtBmpInfoDest
= (PBYTE)pstBmpInfo;
PBYTE pbtBmpInfoSrc
= (PBYTE)&stBmpInfo;
ULONG iSizeTmp
= sizeof( BITMAPINFOHEADER );

while( iSizeTmp-- )
{
*( ( pbtBmpInfoDest )++ ) = *( ( pbtBmpInfoSrc )++ );
}
}

HANDLE hFile
= CreateFile
( p_pchFileName, GENERIC_WRITE, 0
, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_ARCHIVE
, NULL );

BITMAPFILEHEADER stBmpFileHder;
stBmpFileHder.bfType = 0x4D42; // 'BM'
stBmpFileHder.bfSize
= sizeof(BITMAPFILEHEADER)
+ sizeof(BITMAPINFOHEADER)
+ iBmpInfoSize
+ pstBmpInfo->bmiHeader.biSizeImage;
stBmpFileHder.bfReserved1 = 0;
stBmpFileHder.bfReserved2 = 0;
stBmpFileHder.bfOffBits = sizeof(BITMAPFILEHEADER) + iBmpInfoSize;

DWORD dRet;
WriteFile
( hFile, (LPCVOID)&stBmpFileHder
, sizeof(BITMAPFILEHEADER), &dRet, NULL );

PBYTE pBits
= (PBYTE)GlobalAlloc
( GMEM_FIXED | GMEM_ZEROINIT
, stBmpInfo.bmiHeader.biSizeImage );

HBITMAP hBmpOld;
HBITMAP hTmpBmp
= CreateCompatibleBitmap
( p_hDC
, pstBmpInfo->bmiHeader.biWidth
, pstBmpInfo->bmiHeader.biHeight );
hBmpOld = (HBITMAP)SelectObject( p_hDC, hTmpBmp );
GetDIBits
( p_hDC, hBmp, 0, pstBmpInfo->bmiHeader.biHeight
, (LPSTR)pBits, pstBmpInfo, DIB_RGB_COLORS );

WriteFile
( hFile, (LPCVOID)pstBmpInfo
, iBmpInfoSize, &dRet, NULL );

WriteFile( hFile, (LPCVOID)pBits
, pstBmpInfo->bmiHeader.biSizeImage
, &dRet, NULL );

SelectObject( p_hDC, hBmpOld );
DeleteObject( hTmpBmp );
CloseHandle( hFile );
GlobalFree( pstBmpInfo );
GlobalFree( pBits );
return TRUE;
}
///////////////////////////////////
不好意思,上面的代码是有点乱,主要是做测试用,“dcMem.SelectObject(dcMem.GetCurrentBitmap)”实属笔误,本意是dcMem.SelectObject(m_dcMem.GetCurrentBitmap),看下面代码,我稍微做了下注释:
void CBmpDemoDlg::OnPaint()
{
CPaintDC dc(this); // device context for painting
if (!m_dcMem.GetSafeHdc())
{
m_dcMem.CreateCompatibleDC(&dc);
}
if (!m_bmpMem.GetSafeHandle())
{
if (m_dcMem.GetSafeHdc())
{
m_bmpMem.CreateCompatibleBitmap(&dc,m_rcClient.Width(),m_rcClient.Height());
m_dcMem.SelectObject(&m_bmpMem);
}
}
ASSERT(m_dcMem.GetSafeHdc()!=NULL);
ASSERT(m_bmpMem.GetSafeHandle()!=NULL);
//先将图绘制到成员m_dcMem中
m_dcMem.FillSolidRect(m_rcClient,RGB(129,200,0));

CDC dcMem;
dcMem.CreateCompatibleDC(&dc);
//再将已经绘制了内容的成员m_bmpMem选到临时dcMem中
CBitmap *pOldBmp=(CBitmap*)dcMem.SelectObject(&m_bmpMem);
//将临时dcMem拷贝到屏幕
dc.BitBlt(m_rcClient.left,m_rcClient.top,m_rcClient.Width(),m_rcClient.Height(),&dcMem,0,0,SRCCOPY);
//将成员bmpMem选出
dcMem.SelectObject(pOldBmp);
}

我的本意是:类成员m_dcMem和m_bmpMem只创建一次,先将内容画在m_bmpMem上,然后将这个位图选入到另一个dcMem上,我的理解是此时dcMem的绘制表面就是m_bmpMem了,然后在dcMem上面的绘图都是绘制到m_bmpMem上,不知道这样对不对?主要是测试下,没有什么其他实际意义。

///////////////////////////////////////////////
这样写,dc上面还是什么都没有,不知道为什么,但是我将m_dcMem.SelectObject(&bmpMem); //1
放在CBitmap *pOldBmp=(CBitmap*)dcMem.SelectObject(&m_bmpMem);之前就可以了,难道是一个位图不能被选到两个dc中吗?


GetCurrentObject这个函数一般应该怎么用,如果我要获取当前DC位图,感觉这个函数是最直接的
/////////////////////////////////////
还有一点就是上面的SaveBitmapFile函数传入任何窗口dc,哪怕是对话框上面的一个button的dc,最后保存文件都是整个屏幕,但是如果我传入m_dcMem,它就是获取的该dc的区域,不知道是不是窗口的dc通过GetCurrentObject都是整个屏幕?
////////////////////////////////////////////////////////
一个被选到DC中的位图再被选出之前当然不能再次被选入另外一个DC中!
画不出来是当然的。
/////////////////////////////////////////////////////////
An application can use the GetCurrentObject and GetObject functions to retrieve descriptions of the graphic objects currently selected into the given device context.

我觉得你应该整理清楚思路。
第一、确保你获得窗口DC是正确的,你是如何获得DC的;
第二、请不要再使用GetCurrentObject,你问为什么,我只能告诉你在这个地方使用不合适;
第三、确保可以正确选取位图,通过使用老位图来将位图选出。
////////////////////////////////////////////////////
CButton* pButton=(CButton*)GetDlgItem(IDC_BUTTON1);
CClientDC dc(pButton);
SaveBitmapFile((HDC)dc,"Test1.bmp");

上面是你的写法。

其实很简单,只要将CClientDC 拷贝到一个新的内存DC就OK

/////////////////////////////////////////////////////////
嗯,现在理解了,GetCurrentObject只能获得兼容位图
__________________
借用达朗贝尔的名言:前进吧,你会得到信心!
[url="http://www.dimcax.com"]几何尺寸与公差标准[/url]
huangyhg离线中   回复时引用此帖
GDT自动化论坛(仅游客可见)
旧 2009-09-25, 01:52 PM   #2
huangyhg
超级版主
 
huangyhg的头像
 
注册日期: 04-03
帖子: 18592
精华: 36
现金: 249466 标准币
资产: 1080358888 标准币
huangyhg 向着好的方向发展
默认 回复: 关于位图的一点疑问

__________________
借用达朗贝尔的名言:前进吧,你会得到信心!
[url="http://www.dimcax.com"]几何尺寸与公差标准[/url]
huangyhg离线中   回复时引用此帖
回复


主题工具 搜索本主题
搜索本主题:

高级搜索
显示模式

发帖规则
不可以发表新主题
不可以回复主题
不可以上传附件
不可以编辑您的帖子

vB 代码开启
[IMG]代码开启
HTML代码关闭



所有的时间均为北京时间。 现在的时间是 03:11 AM.


于2004年创办,几何尺寸与公差论坛"致力于产品几何量公差标准GD&T | GPS研究/CAD设计/CAM加工/CMM测量"。免责声明:论坛严禁发布色情反动言论及有关违反国家法律法规内容!情节严重者提供其IP,并配合相关部门进行严厉查处,若內容有涉及侵权,请立即联系我们QQ:44671734。注:此论坛须管理员验证方可发帖。
沪ICP备06057009号-2
更多