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渲染视频的技术.本文记录一种稍微复杂但是更加灵活的渲染视频的方式:使 ...
随机推荐
- [转帖]PostgreSQL 慢查询SQL跟踪
https://www.cnblogs.com/VicLiu/p/12017704.html PostgreSQL 开启慢SQL捕获在排查问题时是个很有效的手段.根据慢SQL让我在工作中真正解决了实际 ...
- [转帖]iptables开放指定端口
https://www.jianshu.com/p/5b44dd20484c 由于业务的需要, MySQL,Redis,mongodb等应用的端口需要我们手动操作开启 下面以 MySQL 为例,开启 ...
- K8S多节点情况下使用nginx负载ingress或者是istio域名服务的处理
K8S多节点情况下使用nginx负载ingress或者是istio域名服务的处理 背景 公司内部有一个自建的K8S测试集群.同事这边使用istio或者是ingress发布了一个域名服务. 公司这边的D ...
- firewall-cmd 命令简单总结
最近进行相关网络设置, 发现需要总结一下不然总是会忘记. # 1. 开放IP地址访问 firewall-cmd --zone=trusted --add-source=yourip --permane ...
- MySQL查询排序和分页
连接数据库 mysql -hlocalhost -uroot -proot 排序查询语法: select 字段列表 from 表名 order by 字段1 排序方式1, 字段3 排序方式2,字段3 ...
- file文件转为base64
场景描述 在工作中,我们经常需要进行文件上传. 比如在进行图片上传的时候, 我们需要将上传的图片展示出来. 这个时候我们就需要将file文件转化为base64. 将file文件转化为base64 // ...
- RN 表单TextInput的用法
你要注意安卓和苹果是不同的哈 有些属性是苹果才有的,有些是安卓独有的 有些两个都有哈 // 边框要设置两个属性哈 borderColor: 'pink', marginTop: 10, 具体看地址 h ...
- 01 vue子组件调用父组件中的方法
vue子组件,调用父组件中有三种方法哈!下面我们一起来讲解. 第一种使用 直接在子组件中通过this.$parent.父组件中的方法.来调用父组件的方法 第一种的缺点是不能够传递参数哈.它只能够调用方 ...
- 【0基础学爬虫】爬虫基础之自动化工具 Playwright 的使用
大数据时代,各行各业对数据采集的需求日益增多,网络爬虫的运用也更为广泛,越来越多的人开始学习网络爬虫这项技术,K哥爬虫此前已经推出不少爬虫进阶.逆向相关文章,为实现从易到难全方位覆盖,特设[0基础学爬 ...
- 【K哥爬虫普法】微信公众号爬虫构成不正当竞争,爬虫er面对金山,如何避免滥用爬虫?
我国目前并未出台专门针对网络爬虫技术的法律规范,但在司法实践中,相关判决已屡见不鲜,K 哥特设了"K哥爬虫普法"专栏,本栏目通过对真实案例的分析,旨在提高广大爬虫工程师的法律意识, ...