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 DChdcMemDC = CreateCompatibleDC(hdcWindow); if(!hdcMemDC){MessageBox(hWnd, L"CreateCompatibleDC has failed",L"Failed", MB_OK);goto done;}// Get the client area for size calculationRECT rcClient;GetClientRect(hWnd, &rcClient);//This is the best stretch modeSetStretchBltMode(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 DChbmScreen = 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 HBITMAPGetObject(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 sizeDWORD 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 filebmfHeader.bfSize = dwSizeofDIB; //bfType must always be BM for BitmapsbmfHeader.bfType = 0x4D42; //BMDWORD 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 heapGlobalUnlock(hDIB);    GlobalFree(hDIB);//Close the handle for the file that was createdCloseHandle(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 hereHDC 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的图片放大缩小函数。

win32 Bitblt And Capturing an Image相关推荐

  1. WIN32:参考文章

    Win32API参考手册(汉化超全) http://www.yfvb.com/help/win32sdk/index.htm?page=html/5ro3kj.htm vc++ win32项目添加文本 ...

  2. 游戏编程入门(4):绘制图形图像

    接上文 游戏编程入门(3):绘制基本 GDI 图形 除了经典的矢量图形游戏之外,游戏开发人员都使用图形图像来在视觉上展示游戏的图形部分.本文将介绍如何加载和显示图形图像. 本章内容包括: 位图图像的基 ...

  3. Win32 位图 - BitBlt,内存兼容DC,LoadBitmap

    注:以下内容为学习笔记,多数是从书本.资料中得来,只为加深印象,及日后参考.然而本人表达能力较差,写的不好.因非翻译.非转载,只好选原创,但多数乃摘抄,实为惭愧.但若能帮助一二访客,幸甚! 学了一周左 ...

  4. win32的BitBlt和StretchBlt

    参考 https://blog.csdn.net/baidu_37503452/article/details/73484646 https://www.cnblogs.com/fwycmengsof ...

  5. Win32 多线程学习总结

    Win32多线程编程学习心得 http://blog.csdn.net/jonathan321/article/details/50782832 博客原文地址:http://jerkwisdom.gi ...

  6. 射击的乐趣:WIN32诠释打飞机游戏

    一楼留给链接http://blog.csdn.net/crocodile__/article/details/11860129 楼上神贴,膜拜片刻...... 一.游戏玩法和已经实现的功能 1.打开游 ...

  7. win32开发(绘制bitmap)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途. 联系信箱:feixiaoxing @163.com] win32平台支持直接绘制bitmap图片,所以同学们可以从网上直接找一张图片来绘制.一般来说, ...

  8. win32开发(图形绘制)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途. 联系信箱:feixiaoxing @163.com] 在win32上面绘制图形其实是比较简单的.要想进行图形绘制,关键是找到设备上下文.就我目前所知道 ...

  9. win32 API函数大全

    [1]. API之网络函数  WNetAddConnection :创建同一个网络资源的永久性连接  WNetAddConnection2 :创建同一个网络资源的连接  WNetAddConnecti ...

最新文章

  1. 会计有必要学python吗-工作三年却被实习生抢了饭碗,学会Python到底有多吃香?...
  2. 图结构练习——DFS——判断可达性
  3. 自定义服务器控件ImageButton
  4. 百度翻译接口测试(2)
  5. 用户请求队列化_爬虫架构消息队列应用场景及ActiveMQ、RabbitMQ、RocketMQKafka
  6. nmon 安装和使用
  7. 粉丝福利,送10个程序员专用机械键盘
  8. 如何迁移mac电脑上的itunes备份iphone的文件
  9. 基于Ajax+div的“左边菜单、右边内容”页面效果实现
  10. 一题多解 —— linux 日志文件(log)reload 重新载入
  11. 使用java的io流编写日志类
  12. python竞赛内存_python的内存机制
  13. golang版微信小程序图片上传,服务器保存
  14. 中国雅虎首页改版彻底与口碑网剥离
  15. android系统修改开机动画效果,Android手机开机动画的修改
  16. 无法识别 移动固态硬盘_SSD固态硬盘才装上确找不到盘怎么办-原来要初始化
  17. matlab 画温度分布,matlab画温度分布图
  18. 立波 iphone3gs越狱教程:成功把iphone3gs手机升级成ios6.1.3系统,完美解决no service和耗电量大的问题...
  19. ios ping服务器
  20. 2013年12月新四六级翻译相关词汇汇总

热门文章

  1. 网康防火墙--上线指南_在线付款接受指南-第4部分
  2. 要毕业了,自学实现SSM开发房屋租赁系统
  3. 汇聚能量,元气弹发射 | PingCAP Special Week - Tools matter 有感
  4. 4月18号软件更新资讯合集
  5. iOS 将图片保存到iPhone本地相册
  6. 关闭腾讯windows10的免费升级,checkmewin10.exe
  7. dnf手游体验服不显示服务器,DNF手游:体验服低调更新,服务器无法进入,玩家对此看法不同...
  8. python安装(Ubuntu)
  9. mysql fulltext_MySQL(FullText)
  10. PCL点云处理之基于八叉树的三种邻近点搜索接口详细解释(八十九)