win32 - 关于GDI的RGB的数据分析
此文章为小结,仅供参考。
第一种情况,从桌面DC获取RGBA的数据。 32位
HDC hdc, hdcTemp;
RECT rect;
BYTE* bitPointer;
int x, y;
int red, green, blue, alpha; while(true)
{
hdc = GetDC(HWND_DESKTOP);
GetWindowRect(hWND_Desktop, &rect);
int MAX_WIDTH = rect.right;
int MAX_HEIGHT = rect.bottom; hdcTemp = CreateCompatibleDC(hdc);
BITMAPINFO bitmap;
bitmap.bmiHeader.biSize = sizeof(bitmap.bmiHeader);
bitmap.bmiHeader.biWidth = MAX_WIDTH;
bitmap.bmiHeader.biHeight = MAX_HEIGHT;
bitmap.bmiHeader.biPlanes = 1;
bitmap.bmiHeader.biBitCount = 32;
bitmap.bmiHeader.biCompression = BI_RGB;
bitmap.bmiHeader.biSizeImage = MAX_WIDTH * 4 * MAX_HEIGHT;
bitmap.bmiHeader.biClrUsed = 0;
bitmap.bmiHeader.biClrImportant = 0;
HBITMAP hBitmap2 = CreateDIBSection(hdcTemp, &bitmap, DIB_RGB_COLORS, (void**)(&bitPointer), NULL, NULL);
SelectObject(hdcTemp, hBitmap2);
BitBlt(hdcTemp, 0, 0, MAX_WIDTH, MAX_HEIGHT, hdc, 0, 0, SRCCOPY); for (int i=0; i<(MAX_WIDTH * 4 * MAX_HEIGHT); i+=4)
{
red = (int)bitPointer[i];
green = (int)bitPointer[i+1];
blue = (int)bitPointer[i+2];
alpha = (int)bitPointer[i+3]; }
}
第二种情况,从文件中获取RGB数据,此处为24位
#include <Windows.h>
#include <vector>
#include <iostream>
#include <fstream> using namespace std; void main()
{
HBITMAP hbitmap = (HBITMAP)LoadImage(0, L"panda.bmp",
IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE); BITMAP bm;
GetObject(hbitmap, sizeof(bm), &bm); //don't continue for hi color bitmaps
if (bm.bmBitsPixel > 24) return; int ncolors = 1 << bm.bmBitsPixel;
HDC memdc = CreateCompatibleDC(NULL);
int bmpinfo_size = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * ncolors;
std::vector<BYTE> buf(bmpinfo_size);
BITMAPINFO* bmpinfo = (BITMAPINFO*)buf.data();
bmpinfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
if (!GetDIBits(memdc, hbitmap, 0, bm.bmHeight, NULL, bmpinfo, DIB_RGB_COLORS))
{
DWORD err = GetLastError();
//...
} int dibsize = ((bm.bmWidth * bm.bmBitsPixel + 31) / 32) * 4 * bm.bmHeight;
std::vector<BYTE> dib(dibsize);
if (!GetDIBits(memdc, hbitmap, 0, (UINT)bm.bmHeight, &dib[0], bmpinfo, DIB_RGB_COLORS))
{
DWORD err = GetLastError(); } int dibsize1 = bm.bmWidth * 4 * bm.bmHeight; //这适用于32位 的bmp
//此后将得到的RGB数据写入File中用于对比
std::ofstream myfile("myoutput.txt");
for (int i = 0; i < dibsize; i += 3)
{
blue = (int)dib[i];
green = (int)dib[i + 1];
red = (int)dib[i + 2];
std::cout << red << " " << green << " " << blue << std::endl;
myfile << red << " " << green << " " << blue << endl;
}
myfile.close();
//可以借助第四个例子,查看dib是否有效(测试是有效的)
//比如: HBITMAP hbmp = CreateDIBitmap(hdc, &bmih, CBM_INIT, &dib[0], &dbmi, DIB_RGB_COLORS); 图片是镜像的,还需要一些其他处理,可以参考我的另外一篇文章:https://www.cnblogs.com/strive-sun/p/11975384.html // HWND consoleWindow = GetConsoleWindow();
// HDC hdc = GetDC(consoleWindow);
// int k = 0;
// for (int i = 0; i < bm.bmHeight; i++)
// {
// for (int j = 0; j < bm.bmWidth; j++)
// {
// SetPixel(hdc, j, i, RGB((int)dib[k+2], (int)dib[k + 1], (int)dib[k]));
// k++;
// }
// } getchar(); }
第三种情况, 将32位的RGBA数据写入bmp文件中,此处没有写入文件,而是复制到hdc用于直接查看
#include <windows.h> LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{ MSG msg = { 0 };
WNDCLASS wc = { 0 };
wc.lpfnWndProc = WndProc;
wc.hInstance = hInstance;
wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND);
wc.lpszClassName = L"createdibsection_example";
if (!RegisterClass(&wc))
return 1; if (!CreateWindow(wc.lpszClassName,
L"createdibsection example",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
0, 0, 640, 480, 0, 0, hInstance, NULL))
return 2; while (GetMessage(&msg, NULL, 0, 0) > 0)
DispatchMessage(&msg); return 0;
} HBITMAP CreateBitmapAndFillPtrToItsData(unsigned char** ptr_data, int wd, int hgt)
{
HDC hdcScreen = GetDC(NULL); BITMAPINFO bmi;
memset(&bmi, 0, sizeof(BITMAPINFO));
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = wd;
bmi.bmiHeader.biHeight = -hgt; // top-down
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB; auto bmp = CreateDIBSection(hdcScreen, &bmi, DIB_RGB_COLORS, (void**)ptr_data, NULL, NULL); ReleaseDC(NULL, hdcScreen);
return bmp;
} void CopyInPixelData(unsigned char* ptr_data, int wd, int hgt)
{
// this is just an example for tutorial purposes ... generate a red circle
// in a white field ... real code would load from a file, etc. int c_x = wd / 2;
int c_y = hgt / 2;
int radius = c_x;
int i = 0;
for (int y = 0; y < hgt; y++) {
for (int x = 0; x < wd; x++) {
if ((x - c_x) * (x - c_x) + (y - c_y) * (y - c_y) <= radius * radius) {
ptr_data[i++] = 0;
ptr_data[i++] = 0;
ptr_data[i++] = 255;
ptr_data[i++] = 0;
}
else {
ptr_data[i++] = 255;
ptr_data[i++] = 255;
ptr_data[i++] = 255;
ptr_data[i++] = 0;
}
}
}
} HBITMAP CreateBitmapFromPixelDataExample(int wd, int hgt)
{
// create a bitmap such that we get a pointer to where its data is stored
unsigned char* ptr_data;
auto bitmap = CreateBitmapAndFillPtrToItsData(&ptr_data, wd, hgt); // fill in some pixel data...
CopyInPixelData(ptr_data, wd, hgt); return bitmap;
} LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HBITMAP bitmap; switch (message)
{
case WM_CREATE: {
bitmap = CreateBitmapFromPixelDataExample(85, 85);
} break; case WM_CLOSE:
PostQuitMessage(0);
break; case WM_PAINT: {
RECT r;
GetClientRect(hWnd, &r); auto hdc_bitmap = CreateCompatibleDC(NULL);
auto hbm_old = (HBITMAP)SelectObject(hdc_bitmap, bitmap); PAINTSTRUCT ps;
auto hdc = BeginPaint(hWnd, &ps);
// clear bkgd
FillRect(hdc, &r, (HBRUSH)GetStockObject(WHITE_BRUSH));
// paint in the bitmap we generated from pixel data...
BitBlt(hdc, 10, 10, 85, 85, hdc_bitmap, 0, 0, SRCCOPY);
EndPaint(hWnd, &ps); SelectObject(hdc_bitmap, hbm_old);
DeleteDC(hdc_bitmap); } break; default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
第四种情况,将24位的RGB数据写入bmp文件
// creating input
unsigned char pixels[160*120*3];
for (int i=0; i<160*120*3; i++)
pixels[i] = (i%4==1)*255; // An BGR (not RGB) 160x120 image.
// at this point we have some input
BITMAPINFOHEADER bmih;
bmih.biSize = sizeof(BITMAPINFOHEADER);
bmih.biWidth = 160;
bmih.biHeight = -120;
bmih.biPlanes = 1;
bmih.biBitCount = 24;
bmih.biCompression = BI_RGB ;
bmih.biSizeImage = 0;
bmih.biXPelsPerMeter = 10;
bmih.biYPelsPerMeter = 10;
bmih.biClrUsed =0;
bmih.biClrImportant =0;
BITMAPINFO dbmi;
ZeroMemory(&dbmi, sizeof(dbmi));
dbmi.bmiHeader = bmih;
dbmi.bmiColors->rgbBlue = 0;
dbmi.bmiColors->rgbGreen = 0;
dbmi.bmiColors->rgbRed = 0;
dbmi.bmiColors->rgbReserved = 0;
HDC hdc = ::GetDC(NULL);
HBITMAP hbmp = CreateDIBitmap(hdc, &bmih, CBM_INIT, pixels, &dbmi, DIB_RGB_COLORS);
if (hbmp == NULL) {
::MessageBox(NULL, L"Could not load the desired image image", L"Error", MB_OK);
return;
}
::ReleaseDC(NULL, hdc);
// a little test if everything is OK
OpenClipboard(NULL);
EmptyClipboard();
SetClipboardData(CF_BITMAP, hbmp);
CloseClipboard();
// cleanup
DeleteObject(hbmp);
第五种情况, 使用SetPixel将bmp(24bit)的RGB写到hdc中
#include<iostream>
#include<fstream>
#include <string>
#include<windows.h>
using namespace std; #pragma pack(1)
struct header
{
char header[2];
int32_t filesize;
int16_t reser;
int16_t reser1;
int32_t dataoffset;
}; struct infoheader
{
int32_t headersize;
int32_t width;
int32_t height;
int16_t plans;
int16_t bpp;
int32_t compression;
int32_t datasize;
int32_t re;
int32_t ve;
int32_t color;
int32_t importantcolor;
}; struct PIxel
{
unsigned char G;
unsigned char B;
unsigned char R;
}; int main()
{
header h;
infoheader info;
PIxel* p;
ifstream file("panda.bmp", ios::binary);
if (file.is_open())
{
cout << "true" << endl;
file.read((char*)&h, sizeof(h));
file.read((char*)&info, sizeof(info));
cout << info.width << " " << info.height << " " << h.filesize << " " << info.bpp << endl;
int pa = info.width % 4;
int size = (((24 * info.width + 31) & ~31) / 8)* info.height;
char* arr = new char[size];
file.read(arr, size);
char* temp = arr;
int sizep = info.height * info.width;
p = new PIxel[sizep]; for (int i = info.height - 1; i >= 0; i--)
{
for (int j = 0; j < info.width; j++)
{
int index = i * (info.width) + j;
p[index].B = *(temp++);
p[index].G = *(temp++);
p[index].R = *(temp++);
}
temp += pa;
} HWND consoleWindow = GetConsoleWindow();
HDC hdc = GetDC(consoleWindow); for (int i = 0; i < info.height; i++)
{
for (int j = 0; j < info.width; j++)
{
int index = i * (info.width) + j;
PIxel m = p[index];
SetPixel(hdc, j, i, RGB(m.R, m.G, m.B));
}
}
ReleaseDC(consoleWindow, hdc); } return 0;
}
学习bmp这部分需要长时间的积累,我虽然看了很多文档以及很多例子。 到现在头脑都没完全理过来,希望这后面的学习中能够慢慢领悟吧。
一些有意思的链接: 从HBITMAP获取字节
注意:
- 获取位图的颜色数据最快的方法不是逐像素获取(GetPixel),而是使用创建一个DIB(使用
CreateDIBSectionAPI或类似工具)并在那里复制原始位图,或者首先分别创建原始位图。
类似地,GetDIBits将获得位图数据的副本。这样使用CreateDIBSection的好处是,我们可以同时使用位图和指向实际数据的指针,而不必在使用位图时同时进行两种转换。 (需要在实践中体会)
Link: 如何从HBITMAP获取RGBQUAD?
- 通常我们的位图是24或32位,即每个像素3个字节,如果需要alpha透明通道,则是4个字节(1个字节8位)。数据需要逐行布置,并且必须与DWORD对齐。如果将每个像素设置为32位,则不必担心填充行/对齐方式。如果是24位,则需要计算。
参考上面第二个例子
更新:
使用GetDIBits获取的位图数据,其颜色格式是以BGR写入的(lpPixels参数),如果需要将数据分配给使用RGB格式的字节数组,我们需要进行一些转换
比如:
for (size_t i = 0; i < myWidth * myHeight; i++)
{
size_t tempIndex = (i * 4); // The colors are in BGR-format (windows format)
// Hence, the order is reversed
rgbPixels[tempIndex] = bgrPixels[tempIndex + 2]; // r
rgbPixels[tempIndex + 1] = bgrPixels[tempIndex + 1]; // g
rgbPixels[tempIndex + 2] = bgrPixels[tempIndex]; // b
rgbPixels[tempIndex + 3] = 255; // a (always 255)
}
但是这种方法的效率比较慢,所以我们可以使用SSE寄存器改组来实现。
一个好的例子: 从RGB到BGRA的快速矢量化转换
win32 - 关于GDI的RGB的数据分析的更多相关文章
- Win32中GDI+应用(五)--GDI与GDI+编程模型的区别
在GDI里面,你要想开始自己的绘图工作,必须先获取一个device context handle,然后把这个handle作为绘图复方法的一个参数,才能完成任务.同时,device context ha ...
- Win32中GDI+应用(四)--- 位图的打开与显示
显示位图,你应该使用GDI+里面的Bitmap类或者Image类,这两个类都提供了方法从硬盘上的一个文件打开文件,创建相应的内存中的位图对象的工作.然后你可以使用Graphics类的DrawImage ...
- Win32中GDI+应用(三)---Graphics类
在我理解看来,Graphics是一个device context和你的drawing conetent之间的一个中介.它存储了device context的相关属性,以及drawing content ...
- Win32中GDI+应用(二)--初始化与清理
GDI+提供了GdiplusStartup和 GdiplusShutdown 函数来进行初始化和完成清理工作.你必须在调用其他的GDI+函数之前,调用GdiplusStartup函数,在完成GDI+工 ...
- Win32中GDI+应用(一)
GDI+, Microsoft Graphics Device Interface Plus, 是微软在继GDI(Microsoft Graphics Device Interface)后推出的图形编 ...
- win32用GDI+加载png图片作为背景图
#include <windows.h> #include <gdiplus.h> /* GDI+ startup token */ ULONG_PTR gdiplusStar ...
- 最简单的视音频播放示例2:GDI播放YUV, RGB
前一篇文章对“Simplest Media Play”工程作了概括性介绍.后续几篇文章打算详细介绍每个子工程中的几种技术.在记录Direct3D,OpenGL这两种相对复杂的技术之前,打算先记录一种和 ...
- Win32 GDI 非矩形区域剪裁,双缓冲技术
传统的Win32通过GDI提供图形显示的功能,包括了基本的绘图功能,如画线.方块.椭圆等等,高级功能包括了多边形和Bezier的绘制.这样app就不用关心那些图形学的细节了,有点类似于UNIX上的X- ...
- 最简单的视音频播放示例5:OpenGL播放RGB/YUV
本文记录OpenGL播放视频的技术.OpenGL是一个和Direct3D同一层面的技术.相比于Direct3D,OpenGL具有跨平台的优势.尽管在游戏领域,DirectX的影响力已渐渐超越OpenG ...
- 最简单的视音频播放示例4:Direct3D播放RGB(通过Texture)
本文接着上一篇文章继续记录Direct3D(简称D3D)播放视频的技术.上一篇文章中已经记录了使用Direct3D中的Surface渲染视频的技术.本文记录一种稍微复杂但是更加灵活的渲染视频的方式:使 ...
随机推荐
- 【转帖】linux 内核分析工具 Dtrace、SystemTap、火焰图、crash等
<< System语言详解 >> 关于 SystemTap 的书. 我们在分析各种系统异常和故障的时候,通常会用到 pstack(jstack) /pldd/ lsof/ tc ...
- [转帖]ansible小结(七)常用模块
ansible小结(七)常用模块 http://www.361way.com/ansible-modules/4415.html 在上一篇中介绍了commands部分模块,本篇承接上篇介绍下常用的 ...
- [转帖][问题已处理]-kubernetes中2次不同的oom处理
https://dandelioncloud.cn/article/details/1598699030236577793 起因: 同事反馈 服务挂了,kuboard上查看是服务挂掉了,livenes ...
- [换帖]Linux命令之iconv命令
一.命令简介 日常工作中我们需要将windows生成的文件上传到Linux系统,有时候会因为编码问题出现显示乱码.例如我上传了一个csv文件到Linux服务器上,默认编码为GB2312,在Linu ...
- 简单监控Tomcat连接池大小的命令以及其他简单命令
while true ; do date && echo "当前数据库连接池大小为:" $(jmap -histo `jps |grep caf |awk '{pr ...
- NLP国内外大模型汇总列表[文心一言、智谱、百川、星火、通义千问、盘古等等]
NLP国内外大模型汇总列表[文心一言.智谱.百川.星火.通义千问.盘古等等] 中国大模型列表大全,全面收集有明确来源的大模型情况,包括机构.来源信息和分类等,随时更新. Awesome family ...
- 大语言模型的预训练[3]之Prompt Learning:Prompt Engineering、Answer engineering、Multi-prompt learning、Training strategy详解
大语言模型的预训练[3]之Prompt Learning:Prompt Engineering.Answer engineering.Multi-prompt learning.Training st ...
- Exadata健康检查工具EXAchk
本文根据MOS文章:Oracle Exadata Database Machine EXAchk (Doc ID 1070954.1)整理关键步骤. 注:通常都会要求使用当前最新可用的EXAchk版本 ...
- 正则表达式,JSON.stringify() 去除 所有 key的下划线!!一句顶很多句。
最终的结论: JSON.stringify(userInfo).replace(/([{,]\")_(\w*\":)/g, "$1$2"); 开头锁定<以 ...
- DbgridEh表格框的【可连续点击两次编辑设置,和不允许点击两次编辑的设置】