今天遇到一个问题,调试了一天都没有搞明白。任务是这样的:将一个bitmap图片放到一个DC里,然后获取这个DC里的某一点的RGB值。情况正如下:
调试的时候,上面执行都没有问题,问题是:
int a = pDC.GetPixel(currentBit, currentLine);
a的返回值是-1,无论怎么改,都是这个值。然后没有办法,只能google,有人说调试的时候调用GetPixel会出错。我试了一下正常模式下运行,竟然通过了。真是的,都怪平时太依赖调试模式了。
几天后的更新:
原来GetPixel调用时也是可以获取正确的值的,但是要使用CompatibleDC,代码如下:
这种情况下将断点设置在
GetPixel上就没有问题了,原因是使用CreateCompatibleDC生成的DC是设备无关的,只是放在内存里,使用GetPixel获取RGB值只是读内存,而不是读界面的颜色。
- CFile file; //用于读取BMP文件
- BITMAPFILEHEADER bfhHeader; //bmp文件头
- BITMAPINFOHEADER bmiHeader; //bmp格式头
- LPBITMAPINFO lpBitmapInfo; //bmp格式具体信息
- int bmpWidth=0; //图片宽度
- int bmpHeight = 0; //图片高度
- if( !file.Open( filePath, CFile::modeRead ) )
- return ; //打开文件
- //读取文件头
- file.Read(&bfhHeader,sizeof(BITMAPFILEHEADER));
- if(bfhHeader.bfType!=((WORD) ('M'<<8)|'B')) //判断是否是"BM"
- return ;
- if(bfhHeader.bfSize!=file.GetLength())
- return ;
- //读取位图信息
- if (file.Read((LPSTR)&bmiHeader, sizeof(bmiHeader)) != sizeof(bmiHeader))
- return ;
- bmpHeight = bmiHeader.biHeight; //得到高度和宽度
- bmpWidth = bmiHeader.biWidth;
- file.SeekToBegin(); //指针移动到文件的开头
- file.Read(&bfhHeader,sizeof(BITMAPFILEHEADER));
- UINT uBmpInfoLen=(UINT) bfhHeader.bfOffBits-sizeof(BITMAPFILEHEADER);//File Size
- lpBitmapInfo=(LPBITMAPINFO) new BYTE[uBmpInfoLen]; //具体信息分配内存
- file.Read((LPVOID) lpBitmapInfo,uBmpInfoLen);
- if((* (LPDWORD)(lpBitmapInfo))!=sizeof(BITMAPINFOHEADER))
- return ;
- DWORD dwBitlen = bfhHeader.bfSize - bfhHeader.bfOffBits;//图像数据的字节大小
- unsigned char *lpSrcBits=new BYTE[dwBitlen];
- file.ReadHuge(lpSrcBits,dwBitlen);
- file.Close(); //关闭文件
- //将文件数据加到DC里
- CClientDC pDC(this);
- //CClientDC pDC(&m_blackWhiteImage);
- //CDC* pDC = NULL;
- //HDC pDC = ::CreateCompatibleDC( NULL );
- //::CreateCompatibleDC(pDC);
- int ret = StretchDIBits(pDC,0,0,bmpWidth,bmpHeight,0,0,bmpWidth,bmpHeight,
- lpSrcBits,lpBitmapInfo,DIB_RGB_COLORS,SRCCOPY);
调试的时候,上面执行都没有问题,问题是:
int a = pDC.GetPixel(currentBit, currentLine);
a的返回值是-1,无论怎么改,都是这个值。然后没有办法,只能google,有人说调试的时候调用GetPixel会出错。我试了一下正常模式下运行,竟然通过了。真是的,都怪平时太依赖调试模式了。
几天后的更新:
原来GetPixel调用时也是可以获取正确的值的,但是要使用CompatibleDC,代码如下:
- if ( m_hBmp != NULL)
- {
- DeleteObject(m_hBmp);
- }
- m_hBmp = (HBITMAP)LoadImage(AfxGetInstanceHandle(),
- imagePath,
- IMAGE_BITMAP,
- 0,
- 0,
- LR_LOADFROMFILE);
- if ( m_hBmp == NULL )
- {
- AfxMessageBox("无法打开指定的黑底白框图!");
- return;
- }else
- {
- BITMAP bmp;
- GetObject(m_hBmp, sizeof(BITMAP), &bmp);
- m_bmHeight = bmp.bmHeight; //得到高度和宽度
- m_bmWidth = bmp.bmWidth;
- }
- selectBlock = -1;
- //将文件数据加到DC里
- //CClientDC pDC(this);
- CDC dc;
- dc.CreateCompatibleDC( NULL );
- if ( dc == NULL )
- {
- AfxMessageBox("无法创建兼容DC");
- return;
- }
- HBITMAP hOldBmp = (HBITMAP)SelectObject(dc, m_hBmp);
- blocksCount = 0;
- //遍历各行找矩形框左上角的坐标
- for(int currentLine = 1; currentLine < m_bmHeight - 1; currentLine++)
- {
- for(int currentBit = 1; currentBit < m_bmWidth - 1; currentBit++)
- {
- //优化(不是必须的),提高执行效率
- for ( int i = 0; i < blocksCount; i++ )
- {
- if (currentLine >= blocks[i].pos.top &&
- currentLine <= blocks[i].pos.bottom &&
- currentBit >= blocks[i].pos.left &&
- currentBit <= blocks[i].pos.right)
- {
- currentBit = blocks[i].pos.right + 1;
- }
- }
- if ( 0x00ffffff == dc.GetPixel(currentBit, currentLine) && //自己是白点
- 0x00ffffff != dc.GetPixel(currentBit, (currentLine - 1)) && //上面是不是白点
- 0x00ffffff == dc.GetPixel(currentBit, (currentLine + 1)) && //下面是白点
- 0x00ffffff != dc.GetPixel((currentBit - 1), currentLine) && //左边是不是白点
- 0x00ffffff == dc.GetPixel((currentBit + 1), currentLine) ) //右边是白点
- //找到一个左上角
- {
- blocks[blocksCount].pos.top = currentLine;
- blocks[blocksCount].pos.left = currentBit;
- //计算按钮的高和宽
- UINT bottom = currentLine;
- for(;;bottom++)
- {
- if (0x00ffffff != dc.GetPixel(currentBit, bottom))
- break;
- }
- blocks[blocksCount].pos.bottom = bottom;
- UINT right = currentBit;
- for(;;right++)
- {
- if (0x00ffffff != dc.GetPixel(right, currentLine))
- break;
- }
- blocks[blocksCount].pos.right = right;
- blocks[blocksCount].id = -1;
- blocksCount++;
- }
- }
- }
- if ( blocksCount == 0 )
- {
- AfxMessageBox("无法检测到白框");
- }
- (HBITMAP)SelectObject(dc, hOldBmp);
- dc.DeleteDC();