在一个BITMAPINFO像素数据原始/直接接取(HBITMAP) [英] Raw/Direct acess on pixels data in a BITMAPINFO (HBITMAP)
问题描述
我试图找出我怎么接取从画面原始像素信息。到目前为止,我一直在捕捉画面到HBITMAP,填充BITMAPINFO然后创建这个BITMAPINFO变量的指针直接从内存中读取。
我知道,头必须从文件删除,所以我就直接推进指针(偏移添加的sizeof(MyBMInfo2-> bmiHeader)我的指针)的位图数据。我也知道,这个位图反转/自上而下,第一像素上的原始数据的结尾。我需要弄清楚如何提取从图像中的给定的X和Y R G和B字节,而这正是我是无法执行的。
所以我问你的先生们一盏灯,一个片段或任何暗示,可以帮助我的脏试图从GDI32重新Bitmap.GetPixel(X,Y)(这么慢,我需要一个更好的)。
I'm trying to figure out how do I acess raw pixel information from screen. So far I've been capturing the screen to a HBITMAP, populating a BITMAPINFO then creating a pointer of this BITMAPINFO variable to read directly from the memory. I know that the header must be "removed" from the file, so I advance the pointer directly to the bitmap data (adding sizeof(MyBMInfo2->bmiHeader) to my pointer offset). I also know that this bitmap is inversed/topdown, the first pixels are on the end of the raw data. I need to figure out how do I extract R G and B bytes from a given X and Y in the image, and that's what I'm being incapable of doing. So I asking you sirs a light, a snippet or any hint that can help my dirty attempt to recreate Bitmap.GetPixel(x,y) from gdi32 (so slow, I need a better one).
A 片段我的源$ C $的C 至今
...
HDC hCaptureDC = CreateCompatibleDC(hdc);
HBITMAP hBitmap = CreateCompatibleBitmap(hdc, nScreenWidth, nScreenHeight);
HGDIOBJ hOld = SelectObject(hCaptureDC, hBitmap);
BOOL bOK = BitBlt(hCaptureDC,0,0,nScreenWidth, nScreenHeight, hdc,0,0,SRCCOPY|CAPTUREBLT);
SelectObject(hCaptureDC, hOld); // always select the previously selected object once done
DeleteDC(hCaptureDC);
BITMAPINFO MyBMInfo = {0};
MyBMInfo.bmiHeader.biSize = sizeof(MyBMInfo.bmiHeader);
// Get the MyBMInfo structure from the bitmap
if(0 == GetDIBits(hdc, hBitmap, 0, 0, NULL, &MyBMInfo, DIB_RGB_COLORS)) {
printf("error\n");
}
BITMAPINFO* MyBMInfo2 = &MyBMInfo;
BYTE* bitmapBits=(BYTE*)MyBMInfo2+sizeof(MyBMInfo2->bmiHeader);
//So... how do I acess X and Y RGB bytes now? xD
...
顺便说一句....还有其他更直接的方式做到这一点,没有抛出内存保护的错吗?还是......另一种更快捷的方式呢?
谢谢你。
By the way.... There are any other more direct way to do this without throwing an memory protection fault? Or... another faster way at all? Thank you.
- 编辑 -
使用Barmak code我已经弄清楚如何根据当前光标位置访问X和Y RGB,这里沿用了源$ C $ C:
Using Barmak code i've figure out how to access X and Y rgb based on current cursor position, here follows the source code:
#include <windows.h>
int main()
{
HWND hwnd = GetDesktopWindow();
RECT rc;
GetClientRect(hwnd, &rc);
int width = rc.right;
int height = rc.bottom;
if (width < 1 || height < 1)
{
OutputDebugStringA("error\n");
return 0;
}
HDC hdc = GetDC(hwnd);
HDC hCaptureDC = CreateCompatibleDC(hdc);
HBITMAP hBitmap = CreateCompatibleBitmap(hdc, width, height);
HGDIOBJ hOld = SelectObject(hCaptureDC, hBitmap);
BitBlt(hCaptureDC, 0, 0, width, height, hdc, 0, 0, SRCCOPY | CAPTUREBLT);
SelectObject(hCaptureDC, hOld);
BITMAPINFO MyBMInfo = { 0 };
MyBMInfo.bmiHeader.biSize = sizeof(MyBMInfo.bmiHeader);
BITMAPINFOHEADER bmpInfoHeader = { sizeof(BITMAPINFOHEADER) };
bmpInfoHeader.biWidth = width;
bmpInfoHeader.biHeight = height;
bmpInfoHeader.biPlanes = 1;
bmpInfoHeader.biBitCount = 32;
DWORD size = ((width * bmpInfoHeader.biBitCount + 31) / 32) * 4 * height;
BYTE *bits = malloc(size);
if (GetDIBits(hdc, hBitmap, 0, height, bits, (BITMAPINFO*)&bmpInfoHeader, DIB_RGB_COLORS))
{
OutputDebugStringA("success\n");
//you can use bits here
//access bits from upper-left to lower-right corner
POINT p;
GetCursorPos(&p);
int x = p.x;
int y = p.y;
int col = x;
int row = height - y - 1;
int index = (row * width + col) * 4;
BYTE b = bits[index + 0];
BYTE g = bits[index + 1];
BYTE r = bits[index + 2];
printf("r:%i g:%i b:%i \n",r,g,b);
}
else
{
OutputDebugStringA("error\n");
}
free(bits);
DeleteDC(hCaptureDC);
DeleteObject(hBitmap);
ReleaseDC(hwnd, hdc);
return 0;
}
非常感谢你Shemirani先生。为了谁downvoted我的回答,请考虑撤回它吗? :)
和平。
Thank you very much Mr Shemirani. To who downvoted my answer, please, consider the withdrawn of it please? :) Peace.
推荐答案
GetDibBits
需要一个缓冲区以接收位。你要分配缓冲区,然后在不再需要时删除。
GetDibBits
requires a buffer to receive the bits. You have to allocate the buffer, then delete when no longer needed.
#include <windows.h>
int WINAPI wWinMain(HINSTANCE, HINSTANCE, LPTSTR, int)
{
HWND hwnd = GetDesktopWindow();
RECT rc;
GetClientRect(hwnd, &rc);
int width = rc.right;
int height = rc.bottom;
if (width < 1 || height < 1)
{
OutputDebugStringA("error\n");
return 0;
}
HDC hdc = GetDC(hwnd);
HDC hCaptureDC = CreateCompatibleDC(hdc);
HBITMAP hBitmap = CreateCompatibleBitmap(hdc, width, height);
HGDIOBJ hOld = SelectObject(hCaptureDC, hBitmap);
BitBlt(hCaptureDC, 0, 0, width, height, hdc, 0, 0, SRCCOPY | CAPTUREBLT);
SelectObject(hCaptureDC, hOld);
BITMAPINFO MyBMInfo = { 0 };
MyBMInfo.bmiHeader.biSize = sizeof(MyBMInfo.bmiHeader);
BITMAPINFOHEADER bmpInfoHeader = { sizeof(BITMAPINFOHEADER) };
bmpInfoHeader.biWidth = width;
bmpInfoHeader.biHeight = height;
bmpInfoHeader.biPlanes = 1;
bmpInfoHeader.biBitCount = 32;
DWORD size = ((width * bmpInfoHeader.biBitCount + 31) / 32) * 4 * height;
BYTE *bits = malloc(size);
if (GetDIBits(hdc, hBitmap, 0, height, bits, (BITMAPINFO*)&bmpInfoHeader, DIB_RGB_COLORS))
{
OutputDebugStringA("success\n");
//you can use bits here
//access bits from lower-left to upper-right corner
for (int row = 0; row < height; row++)
{
for (int col = 0; col < width; col++)
{
//for 32 bit image only:
int index = (row * width + col) * 4;
BYTE blue = bits[index + 0];
BYTE green = bits[index + 1];
BYTE red = bits[index + 2];
}
}
//access bits from upper-left to lower-right corner
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
int col = x;
int row = height - y - 1;
int index = (row * width + col) * 4;
BYTE b = bits[index + 0];
BYTE g = bits[index + 1];
BYTE r = bits[index + 2];
}
}
}
else
{
OutputDebugStringA("error\n");
}
free(bits);
DeleteDC(hCaptureDC);
DeleteObject(hBitmap);
ReleaseDC(hwnd, hdc);
return 0;
}
这篇关于在一个BITMAPINFO像素数据原始/直接接取(HBITMAP)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!