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(使用
CreateDIBSection
API或类似工具)并在那里复制原始位图,或者首先分别创建原始位图。
类似地,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渲染视频的技术.本文记录一种稍微复杂但是更加灵活的渲染视频的方式:使 ...
随机推荐
- 申威下单盘SSD与四块盘RAID5的性能测试结果
申威下单盘SSD与四块盘RAID5的性能测试结果 背景 背景不在说了 申威服务器.. 结论 天坑 做了raid写入性能下降明显. 充分怀疑驱动不行. 四快盘的raid5 跟单盘的读几乎没区别. 感觉这 ...
- [转帖]NVMe 与 AHCI
https://www.cnblogs.com/zengkefu/p/5634345.html http://elf8848.iteye.com/blog/1731274 AHCI: NCQ技术,60 ...
- [转帖]Web性能优化工具WebPageTest(三)——本地部署(Windows 7版本)
http://www.zlprogram.com/Show/30/30117.shtml 这次先能够使用PC端的浏览器测试,首先需要下载官方的发布版本"WebPageTest 3.0&quo ...
- [转帖]一次fork引发的惨案!
https://www.cnblogs.com/xuanyuan/p/15502289.html "你还有什么要说的吗?没有的话我就要动手了",kill程序最后问道. 这一次,我没 ...
- [转帖]耗时几个月,终于找到了JVM停顿十几秒的原因
https://www.cnblogs.com/codelogs/p/16060792.html 原创:打码日记(微信公众号ID:codelogs),欢迎分享,转载请保留出处. 简介# 最近我们系 ...
- 【码农教程】手把手教你学会Mockito使用
作者:京东零售 秦浩然 一.前期准备- 1.准备工作 <!--mockito依赖--> <dependency> <groupId>org.mockito</ ...
- Golang并发控制方式有几种?
Go语言中的goroutine是一种轻量级的线程,其优点在于占用资源少.切换成本低,能够高效地实现并发操作.但如何对这些并发的goroutine进行控制呢? 一提到并发控制,大家最先想到到的是锁.Go ...
- vim 从嫌弃到依赖(7)——可视模式
vim 的可视模式下可以选择一个区域,然后针对区域进行操作.可视模式有点类似于在其他编辑器上使用鼠标选中一块区域然后针对区域进行操作. vim中有3种可视模式,分别用来处理不同范围的文本: 处理字符的 ...
- TienChin-课程管理-课程更新接口
更改包名 将之前的 entity 更改为 domain: 将之前的 validator 包当中的校验分组接口移动到 common 模块当中,因为其它模块也需要使用就放到公共当中进行存储. 更改完毕之后 ...
- 【三】多智能体强化学习(MARL)近年研究概览 {Analysis of emergent behaviors(行为分析)_、Learning communication(通信学习)}
相关文章: [一]最新多智能体强化学习方法[总结] [二]最新多智能体强化学习文章如何查阅{顶会:AAAI. ICML } [三]多智能体强化学习(MARL)近年研究概览 {Analysis of e ...