bitblt
BitBlt 函数 执行 位块传输 ,传输的内容是 一个device context (DC)中的一个矩形区域的像素的颜色数据。
传输过程是从一个device contex(DC)传送到另外一个Device Contex(DC)
并且可以针对ROP 参数的设置,来改动像素的值。
BOOL BitBlt(
HDC hdc,
int x,
int y,
int cx,
int cy,
HDC hdcSrc,
int x1,
int y1,
Dword rop
);
BOOL BitBlt(
HDC hdcDest,
int nXDest,
int nYDest,
int nWidth,
int nHeight,
HDC hdcSrc,
int nXSrc,
int nYSrc,
dword dwRop
);
参数:
hdcDest
[in] handle to the destination device context. DC
nXDest
[in] 指定目标矩形区域的左上角的X坐标值
nYDest
[in]指定目标矩形区域的左上角的Y坐标值
nWidth
[in] 指定源和目的矩形的宽度
nHeight
[in] 指定源和目的矩形的高度
hdcSrc
[in] Handle to the source device context. DC
nXSrc
[in]指定源矩形的左上角那一点的X轴的坐标
nYSrc
[in] 指定源矩形的左上角那一点的Y轴的坐标
dwRop
[in] Specifies a raster-operation code.
指定光栅操作码
这个操作码定义源矩形中的颜色数据,如何和目标矩形中的颜色数据 结合,以生成最终的颜色。
下面是常用的光栅操作码:主要看(SRCCOPY)
Value | Description |
---|---|
BLACKNESS | Fills the destination rectangle using the color associated with index 0 in the physical palette. This color is black for the default physical palette. |
DSTINVERT | Inverts the destination rectangle. |
MERGECOPY | Merges the colors of the source rectangle with the specified pattern by using the Boolean AND operator. |
MERGEPaiNT | Merges the colors of the inverted source rectangle with the colors of the destination rectangle by using the Boolean OR operator. |
NOTSRCCOPY | Copies the inverted source rectangle to the destination. |
NOTSRCerase | Combines the colors of the source and destination rectangles by using the Boolean OR operator and then inverts the resultant color. |
PATCOPY | Copies the specified pattern into the destination bitmap. |
PATINVERT | Combines the colors of the specified pattern with the colors of the destination rectangle by using the Boolean XOR operator. |
PATPAINT | Combines the colors of the pattern with the colors of the inverted source rectangle by using the Boolean OR operator.The result of this operation is combined with the colors of the destination rectangle by using the Boolean OR operator. |
SRCAND | Combines the colors of the source and destination rectangles by using the Boolean AND operator. |
SRCCOPY | Copies the source rectangle directly to the destination rectangle. |
SRCERASE | Combines the inverted colors of the destination rectangle with the colors of the source rectangle by using the Boolean AND operator. |
SRCINVERT | Combines the colors of the source and destination rectangles by using the Boolean XOR operator. |
SRCPAINT | Combines the colors of the source and destination rectangles by using the Boolean OR operator. |
WHITENESS | Fills the destination rectangle using the color associated with index 1 in the physical palette.This color is white for the default physical palette. |
返回值
如果成功,返回非0
如果失败,返回 0
得到进一步的信息,使用函数GetLastERROR.
例子代码
下面的代码,演示如何使用BitBlt 复制一个 bitmap中的像素到另外一个bitmap中。
注意:
为了代码的易读,没有包括错误检查。
这个代码例子不能用在release配置中,除非修改后包含了安全error执行。
HBITMAP CopyBitmap( HBITMAP hbm) {
HDC hdcSrc = createcompatibledc(NULL);
HDC hdcDst = CreateCompatibleDC(NULL);
HBITMAP hbmOld, hbmOld2, hbmNew;
BITMAP bm;
GetObject(hbm, sizeof(bm), &bm);
hbmOld = SelectObject(hdcSrc, hbm);
hbmNew = CreateBitmap( bm.bmWidth, bm.bmHeight, bm.bmPlanes,
bm.bmBitsPixel,
NULL);
hbmOld2 = SelectObject(hdcDst, hbmNew);
BitBlt(hdcDst, 0, 0, bm.bmWidth, bm.bmHeight, hdcSrc, 0, 0, SRCCOPY);
SelectObject(hdcSrc, hbmOld);
DeleteDC(hdcSrc);
DeleteDC(hdcDst);
return hbmNew;
}
备注
如果源device context正在旋转或者剪切,BitBlt将会返回错误。
If other transformations exist in the source device context (and a matching transformation is not in effect in the destination device context), the rectangle in the destination device context is stretched, compressed, or rotated as necessary.
If the color formats of the source and destination device contexts do not match, the BitBlt function converts the source color format to match the destination format.
When an enhanced metafile is being recorded, an error occurs if the source device context identifies an enhanced-metafile device context.
不是所有的设置都支持 BitBlt函数。
For more information, see the RC_BITBLT raster capability entry in the GetDeviceCaps function, as well as the MaskBlt and StretchBlt functions.
如果源device context 和目标device context 是不同的设备,BitBlt会返回错误。
For information about blitting to displays with right-to-left orientations, see Creating Bitmaps.
Creating Bitmaps (windows CE 5.0)
https://docs.microsoft.com/en-us/previous-versions/windows/embedded/ms906571%28v%3dmsdn.10%29
备注2
BitBlt only does clipping on the destination DC.
BitBlt只是在目标DC上执行粘贴。
If a rotation or shear transformation is in effect in the source device context, BitBlt returns an error. If other transformations exist in the source device context (and a matching transformation is not in effect in the destination device context), the rectangle in the destination device context is stretched, compressed, or rotated, as necessary.
If the color formats of the source and destination device contexts do not match, the BitBlt function converts the source color format to match the destination format.
When an enhanced metafile is being recorded, an error occurs if the source device context identifies an enhanced-metafile device context.
不是所有的设置都支持 BitBlt函数。
For more information, see the RC_BITBLT raster capability entry in the GetDeviceCaps function as well as the following functions: MaskBlt, PlgBlt, and StretchBlt.
如果源device context 和目标device context 是不同的设备,BitBlt会返回错误。
如果要在不同的设备DC之间传送数据,需要将内存位图(memory bitmap)转换为DIB,转换的方式是调用GetDIBits。在其他的设备上,显示DIB,需要调用SetDIBits 或者 stretchdibits 。
那么在 相同类型的设备的DC 之间传送数据,可以直接调用BitBlt 传送内存位图(memory bitmap)
ICM: No color management is performed when blits occur.
例子: Capturing an Image.
https://docs.microsoft.com/zh-cn/windows/desktop/gdi/capturing-an-image
bitmap 和 BMP文件 不是一个概念。
你可以使用bitmap来捕捉图像,可以存储该图像在内存中,在你的应用的窗口的不同位置显示该图像,或者在其他的窗口显示该图像。
有时候,你可能只是希望你的应用,捕捉图像(images),并且临时的保存它们。
比如,当你放大或者缩小绘图应用中的图片的时候,应用必须临时保存正常视图大小的图像,然后显示缩放的视图。
然后,当用户选择正常视图的时候,应用必须替换缩放的图像为临时保存的正常视图图像。
为了临时保存图像,应用,需要调用CreateCompatibleDC 来创建一个DC,这个DC是兼容当前窗口DC的。
当你创建一个compatible DC之后,你创建一个合适尺寸的bitmap,创建的方法是调用CreateCompatibleBitmap函数,
然后通过调用SelectObject函数,来选择该bitmap到当前的device context— compatible DC。
当创建了 compatible device context之后,并且合适的bitmap 已经选择到该 compatible device context之后,
你就可以进行图像的捕捉了。
使用BitBlt函数来捕捉图像。
This function performs a bit block transfer that is, it copies data from a source bitmap into a destination bitmap.
这个函数执行一个位块传输,它从一个源bitmap复制数据到一个目标bitmap。
但是,这个函数的两个参数不是bitmap的句柄。
BitBlt 使用句柄是两个不同的device contexts。
复制源DC中的bitmap对应的bitmap数据,到目标DC中的bitmap。
BitBlt receives handles that identify two device contexts and copies the bitmap data from a bitmap selected into the source DC into a bitmap selected into the target DC.
在这个例子中,目标DC 是一个compatible DC
所以当BitBlt 完成传输,图像数据已经保存在内存中了。
为了重新显示图像,再一次调用BitBlt,指定compatible DC 为源DC,一个窗口DC作为目标DC。
下面的例子代码来自一个应用,该应用捕捉整个桌面的图像。缩小到当前窗口的大小,然后保存到一个文件中。
在win7 64 位下面:
使用vs2010 创建一个 MFC 对话框工程,
添加一个按钮,并且为该按钮添加一个事件:
最终的工具界面如下:
点击 按钮之后的,界面如下:(捕捉的是整个桌面)
关键代码:
int CaptureAnImage(HWND hWnd);
void CCaptureImageDlg::OnBnClickedBtnCapture()
{
// TODO: 在此添加控件通知处理程序代码
HWND hWnd;
hWnd = AfxGetMainWnd()->m_hWnd;
CaptureAnImage(hWnd);
}
int CaptureAnImage(HWND hWnd)
{
HDC hdcScreen;
HDC hdcWindow;
HDC hdcMemDC = NULL;
HBITMAP hbmScreen = NULL;
BITMAP bmpScreen;
// Retrieve the handle to a display device context for the client
// area of the window.
hdcScreen = GetDC(NULL);
hdcWindow = GetDC(hWnd);
// Create a compatible DC which is used in a BitBlt from the window DC
hdcMemDC = CreateCompatibleDC(hdcWindow);
if(!hdcMemDC)
{
messageBox(hWnd, L"CreateCompatibleDC has failed",L"Failed", MB_OK);
goto done;
}
// Get the client area for size calculation
RECT rcClient;
GetClientRect(hWnd, &rcClient);
//This is the best stretch mode
SetStretchBltMode(hdcWindow,HALFTONE);
//The source DC is the entire screen and the destination DC is the current window (HWND)
if(!StretchBlt(hdcWindow,
0,0,
rcClient.right, rcClient.bottom,
hdcScreen,
0,0,
GetSystemMetrics (SM_CXSCREEN),
GetSystemMetrics (SM_CYSCREEN),
SRCCOPY))
{
MessageBox(hWnd, L"StretchBlt has failed",L"Failed", MB_OK);
goto done;
}
// Create a compatible bitmap from the Window DC
hbmScreen = CreateCompatibleBitmap(hdcWindow, rcClient.right-rcClient.left, rcClient.bottom-rcClient.top);
if(!hbmScreen)
{
MessageBox(hWnd, L"CreateCompatibleBitmap Failed",L"Failed", MB_OK);
goto done;
}
// Select the compatible bitmap into the compatible memory DC.
SelectObject(hdcMemDC,hbmScreen);
// Bit block transfer into our compatible memory DC.
if(!BitBlt(hdcMemDC,
0,0,
rcClient.right-rcClient.left, rcClient.bottom-rcClient.top,
hdcWindow,
0,0,
SRCCOPY))
{
MessageBox(hWnd, L"BitBlt has failed", L"Failed", MB_OK);
goto done;
}
// Get the BITMAP from the HBITMAP
GetObject(hbmScreen,sizeof(BITMAP),&bmpScreen);
BITMAPFILEHEADER bmfHeader;
BITMAPINFOHEADER bi;
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = bmpScreen.bmWidth;
bi.biHeight = bmpScreen.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = 32;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrimportant = 0;
DWORD dwBmpSize = ((bmpScreen.bmWidth * bi.biBitCount + 31) / 32) * 4 * bmpScreen.bmHeight;
// Starting with 32-bit Windows, GlobalAlloc and localAlloc are implemented as wrAPPer functions that
// call HeapAlloc using a handle to the process's default heap. Therefore, GlobalAlloc and LocalAlloc
// have greater overhead than HeapAlloc.
HANDLE hDIB = GlobalAlloc(GHND,dwBmpSize);
char *lpbitmap = (char *)GlobalLock(hDIB);
// Gets the "bits" from the bitmap and copies them into a buffer
// which is pointed to by lpbitmap.
GetDIBits(hdcWindow, hbmScreen, 0,
(UINT)bmpScreen.bmHeight,
lpbitmap,
(BITMAPINFO *)&bi, DIB_RGB_COLORS);
// A file is created, this is where we will save the screen capture.
HANDLE hFile = CreateFile(L"captureqwsx.bmp",
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
// Add the size of the headers to the size of the bitmap to get the total file size
DWORD dwSizeofDIB = dwBmpSize + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
//offset to where the actual bitmap bits start.
bmfHeader.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER);
//Size of the file
bmfHeader.bfSize = dwSizeofDIB;
//bfType must always be BM for Bitmaps
bmfHeader.bfType = 0x4D42; //BM
DWORD dwBytesWritten = 0;
WriteFile(hFile, (LPSTR)&bmfHeader, sizeof(BITMAPFILEHEADER), &dwBytesWritten, NULL);
WriteFile(hFile, (LPSTR)&bi, sizeof(BITMAPINFOHEADER), &dwBytesWritten, NULL);
WriteFile(hFile, (LPSTR)lpbitmap, dwBmpSize, &dwBytesWritten, NULL);
//Unlock and Free the DIB from the heap
GlobalUnlock(hDIB);
GlobalFree(hDIB);
//Close the handle for the file that was created
CloseHandle(hFile);
//Clean up
done:
DeleteObject(hbmScreen);
DeleteObject(hdcMemDC);
ReleaseDC(NULL,hdcScreen);
ReleaseDC(hWnd,hdcWindow);
return 0;
}
整体工程代码:如下:
https://download.csdn.net/download/wowocpp/10500454
使用GetDIBits直接读取位图数据
https://blog.csdn.net/iamshuke/article/details/5749948
#include <math.h>
void CDibtestDlg::OnOK()
{
// TODO: Add extra validation here
HDC hDesktopDC = ::GetDC(NULL);
HDC hTmpDC = CreateCompatibleDC(hDesktopDC);
HBITMAP hBmp = CreateCompatibleBitmap(hDesktopDC, 351, 250); //351x250, 示例数据
SelectObject(hTmpDC, hBmp);
BitBlt(hTmpDC, 0, 0, 351, 250, hDesktopDC, 0, 0, SRCCOPY);
DeleteObject(hTmpDC);
BITMAP bm;
PBITMAPINFO bmpInf;
if(GetObject(hBmp,sizeof(bm),&bm)==0)
{
::ReleaseDC(NULL,hDesktopDC);
return ;
}
int nPaletteSize=0;
if(bm.bmBitsPixel<16)
nPaletteSize=(int)pow(2,bm.bmBitsPixel);
bmpInf=(PBITMAPINFO)LocalAlloc(LPTR,sizeof(BITMAPINFOHEADER)+
sizeof(RGBQUAD)*nPaletteSize+(bm.bmWidth+7)/8*bm.bmHeight*bm.bmBitsPixel);
BYTE* buf=((BYTE*)bmpInf) +
sizeof(BITMAPINFOHEADER)+
sizeof(RGBQUAD)*nPaletteSize;
//-----------------------------------------------
bmpInf->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmpInf->bmiHeader.biWidth = bm.bmWidth;
bmpInf->bmiHeader.biHeight = bm.bmHeight;
bmpInf->bmiHeader.biPlanes = bm.bmPlanes;
bmpInf->bmiHeader.biBitCount = bm.bmBitsPixel;
bmpInf->bmiHeader.biCompression = BI_RGB;
bmpInf->bmiHeader.biSizeImage = (bm.bmWidth+7)/8*bm.bmHeight*bm.bmBitsPixel;
//-----------------------------------------------
if(!::GetDIBits(hDesktopDC,hBmp,0,(UINT)bm.bmHeight,buf,bmpInf,DIB_RGB_COLORS))
{
::ReleaseDC(NULL,hDesktopDC);
LocalFree(bmpInf);
return ;
}
::ReleaseDC(NULL,hDesktopDC);
CString sMsg;
sMsg.Format("BitsPixel:%d,width:%d,height:%d",
bm.bmBitsPixel,bm.bmWidth,bm.bmHeight);
AfxMessageBox(sMsg);
CClientDC dc(this);
int nOffset;
BYTE r,g,b;
int nWidth = bm.bmWidth*bm.bmBitsPixel/8;
nWidth = ((nWidth+3)/4)*4; //4字节对齐
if(bmpInf->bmiHeader.biBitCount == 8)
{
for(int i=0; i<bm.bmHeight; i++)
{
for(int j=0; j<bm.bmWidth; j++)
{
RGBQUAD rgbQ;
rgbQ = bmpInf->bmiColors[buf[i*nWidth+j]];
dc.SetPixel(j,bm.bmHeight-i,RGB(rgbQ.rgbRed,rgbQ.rgbGreen,rgbQ.rgbBlue)); //测试显示
}
}
}
else if(bmpInf->bmiHeader.biBitCount == 16)
{
for(int i=0; i<bm.bmHeight; i++)
{
nOffset = i*nWidth;
for(int j=0; j<bm.bmWidth; j++)
{
b = buf[nOffset+j*2]&0x1F;
g = buf[nOffset+j*2]>>5;
g |= (buf[nOffset+j*2+1]&0x03)<<3;
r = (buf[nOffset+j*2+1]>>2)&0x1F;
r *= 8;
b *= 8;
g *= 8;
dc.SetPixel(j, bm.bmHeight-i, RGB(r,g,b)); //测试显示
}
}
}
else if(bmpInf->bmiHeader.biBitCount == 24)
{
for(int i=0; i<bm.bmHeight; i++)
{
nOffset = i*nWidth;
for(int j=0; j<bm.bmWidth; j++)
{
b = buf[nOffset+j*3];
g = buf[nOffset+j*3+1];
r = buf[nOffset+j*3+2];
dc.SetPixel(j, bm.bmHeight-i, RGB(r,g,b)); //测试显示
}
}
}
else if(bmpInf->bmiHeader.biBitCount == 32)
{
for(int i=0; i<bm.bmHeight; i++)
{
nOffset = i*nWidth;
for(int j=0; j<bm.bmWidth; j++)
{
b = buf[nOffset+j*4];
g = buf[nOffset+j*4+1];
r = buf[nOffset+j*4+2];
dc.SetPixel(j, bm.bmHeight-i, RGB(r,g,b)); //测试显示
}
}
}
DeleteObject(hBmp);
LocalFree(bmpInf);
//CDialog::OnOK();
}
问题:
1,
在我的代码中,第二次调用GetDIBits()前所申请的内存,只考虑了DIB数据的大小,未考虑BITMAPINFO及COLOR TABLE的空间(因为前面已有专门的变量存放这些信息);
而正常的代码,第二次调用GetDIBits()前所申请的内存空间,包括了BITMAPINFO、COLOR TABLE以及实际DIB数据的内容(将前面获得的BITMAPINFO、COLOR TABLE都拷贝到此空间)。
2,
Windows GDI中有两个用来得到位图图像数据的API,分别是GetBitmapBits和GetDIBits;
按照MSDN的解释,前者是用来得到设备独立位图的BITS,
后者是得到兼容位图的BITS,
所以在调用该函数的时候,
第一个主要的区别是:GetDIBits需要提供一个设备内容,同时需要将位图的HANDLE选进这个设备内容(DC)才能能够得到位图的信息。
我想上面的区别大家可能都知道,
其实它还隐藏着另一个区别:就是对于同一个位图,得到的BITS内容的BUFFER不一样!
大家都知道BMP文件存储数据是倒叙的,也就是从图像的右下角开始存储,文件的最后是图像的左上角(这个来历可以看:WINDOWS编程中介绍);
使用GetBitmapBits取得的BUFFER,位图的右下角的内容为第一个字节,实际上和真正的图像字节应该是一样的,
而GetDIBits刚好相反,其BUFFER的顺序符合BMP文件中的顺序,如果按照正常的坐标,其存储顺序应该是倒叙。
所以在程序中要合理的使用这两个API来得到你想要的位图数据。
调用GDI+或CxImage或Image Magick或PhotoShop的图片放大缩小函数。
文章最后发布于: 2018-06-26 11:53:23
相关阅读
赵奕欢的淘宝店铺网址 shop107932235.taobao.com
店铺介绍: 赵奕欢对PUBE的品牌上线高度重视,深度参与,给出了指导性的建议!个性前卫的原创设计,赵奕欢深度参与指导。昨日奉行的最高美
搬到万达上课之后我的电脑就总是出现联网问题,Internet访问那里总是是一个黄色的感叹号,这可以排除网线的问题,所以应该是电脑出状
自动抄表项目中用到了Msflxgrd.ocx控件,该表格控件使用很方便,并在32位 XP系统下测试通过,但是客户的电脑是64位WIN7,点击对话框无法
一、为Windows选择正确的密钥。以下是Windows 10批量许可证密钥列表 Home: TX9XD-98N7V-6WMQ6-BX7FG-H8Q99 Home N: 3KHY7-WNT83
在cmd.exe中输入 netstat -ano 查看端口的占用情况: 根据进程号查找对应的进程 tasklist | findstr "13028" 从进程名上可以