#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("timg.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 size1 = (info.width * (info.bpp / 8) + pa) * info.height; 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); } }
拓展:
将屏幕数据保存为数组:
使用CreateDIBSection的原因是创建相同尺寸的位图后,使用BitBlt将屏幕位图复制过去,从而可以得到屏幕位图的数据,最终借助Copy函数将位图保存为数组。
我的一个想法是,借助第一个例子,将这个例子获得位图数组再转换为位图,比如只用RGB数组,使用SetPixel将RGB填入上面的控制台的hdc中,再通过创建DIB文件,使用BitBlt,最终将hdc复制给一个新的memdc,从而得到位图句柄,也就可以得到位图文件了。
void WINAPI CaptureScreenIntoByteArray( BYTE*& screen_bytes, DWORD& screen_bytes_size) { BITMAPFILEHEADER bfHeader; BITMAPINFOHEADER biHeader; BITMAPINFO bInfo; HGDIOBJ hTempBitmap; HBITMAP hBitmap; BITMAP bAllDesktops; HDC hDC, hMemDC; LONG lWidth, lHeight; BYTE* sb = NULL; ZeroMemory(&bfHeader, sizeof(BITMAPFILEHEADER)); ZeroMemory(&biHeader, sizeof(BITMAPFILEHEADER)); ZeroMemory(&bInfo, sizeof(BITMAPINFO)); ZeroMemory(&bAllDesktops, sizeof(BITMAP)); hDC = GetDC(NULL); hTempBitmap = GetCurrentObject(hDC, OBJ_BITMAP); GetObjectW(hTempBitmap, sizeof(BITMAP), &bAllDesktops); lWidth = bAllDesktops.bmWidth; lHeight = bAllDesktops.bmHeight; DeleteObject(hTempBitmap); bfHeader.bfType = (WORD)('B' | ('M' << 8)); bfHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); biHeader.biSize = sizeof(BITMAPINFOHEADER); biHeader.biBitCount = 24; biHeader.biCompression = BI_RGB; biHeader.biPlanes = 1; biHeader.biWidth = lWidth; biHeader.biHeight = lHeight; bInfo.bmiHeader = biHeader; screen_bytes_size = (((24 * lWidth + 31) & ~31) / 8) * lHeight; hMemDC = CreateCompatibleDC(hDC); hBitmap = CreateDIBSection(hDC, &bInfo, DIB_RGB_COLORS, (VOID**)&sb, NULL, 0); SelectObject(hMemDC, hBitmap); int x = GetSystemMetrics(SM_XVIRTUALSCREEN); int y = GetSystemMetrics(SM_YVIRTUALSCREEN); BitBlt(hMemDC, 0, 0, lWidth, lHeight, hDC, x, y, SRCCOPY); // Need to also copy bfHeader & biHeader bytes somehow... screen_bytes = new BYTE[sizeof(BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER) + screen_bytes_size]; std::copy(&bfHeader, &bfHeader + 1, (BITMAPFILEHEADER*)screen_bytes); std::copy(&biHeader, &biHeader + 1, (BITMAPINFOHEADER*)(screen_bytes + sizeof(BITMAPFILEHEADER))); std::copy(sb, sb + screen_bytes_size, screen_bytes + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)); DeleteDC(hMemDC); ReleaseDC(NULL, hDC); DeleteObject(hBitmap); }
在C++中,使用GetDIBits读取像素
#include <Windows.h> #include <iostream> #include <math.h> #include <stdio.h> using namespace std; HBITMAP GetScreenBmp( HDC hdc) { // Get screen dimensions int nScreenWidth = GetSystemMetrics(SM_CXSCREEN); int nScreenHeight = GetSystemMetrics(SM_CYSCREEN); // Create compatible DC, create a compatible bitmap and copy the screen using BitBlt() 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); return hBitmap; } int main() { HDC hdc = GetDC(0); HBITMAP hBitmap = GetScreenBmp(hdc); BITMAPINFO MyBMInfo = {0}; MyBMInfo.bmiHeader.biSize = sizeof(MyBMInfo.bmiHeader); // Get the BITMAPINFO structure from the bitmap if(0 == GetDIBits(hdc, hBitmap, 0, 0, NULL, &MyBMInfo, DIB_RGB_COLORS)) { cout << "error" << endl; } // create the bitmap buffer BYTE* lpPixels = new BYTE[MyBMInfo.bmiHeader.biSizeImage]; // Better do this here - the original bitmap might have BI_BITFILEDS, which makes it // necessary to read the color table - you might not want this. MyBMInfo.bmiHeader.biCompression = BI_RGB; // get the actual bitmap buffer if(0 == GetDIBits(hdc, hBitmap, 0, MyBMInfo.bmiHeader.biHeight, (LPVOID)lpPixels, &MyBMInfo, DIB_RGB_COLORS)) { cout << "error2" << endl; } for(int i = 0; i < 100; i++) { cout << (int)lpPixels[i]; } DeleteObject(hBitmap); ReleaseDC(NULL, hdc); delete[] lpPixels; return 0; }