Mouse cursor bitmap - c

I am trying to get bitmap from mouse cursor, but with next code, i just can't get colors.
CURSORINFO cursorInfo = { 0 };
cursorInfo.cbSize = sizeof(cursorInfo);
if (GetCursorInfo(&cursorInfo)) {
ICONINFO ii = {0};
int p = GetIconInfo(cursorInfo.hCursor, &ii);
// get screen
HDC dc = GetDC(NULL);
HDC memDC = CreateCompatibleDC(dc);
//SelectObject(memDC, ii.hbmColor);
int counter = 0;
//
byte* bits[1000];// = new byte[w * 4];
BITMAPINFO bmi;
memset(&bmi, 0, sizeof(BITMAPINFO));
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = 16;
bmi.bmiHeader.biHeight = 16;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biSizeImage = 0;
bmi.bmiHeader.biXPelsPerMeter = 0;
bmi.bmiHeader.biYPelsPerMeter = 0;
bmi.bmiHeader.biClrUsed = 0;
bmi.bmiHeader.biClrImportant = 0;
int rv = ::GetDIBits(memDC, ii.hbmColor, 0, 1, (void**)&bits, &bmi, DIB_RGB_COLORS);
}

Start by getting the parameters of the bitmap as recorded by Windows:
BITMAP bitmap = {0};
GetObject(ii.hbmColor, sizeof(bitmap), &bitmap);
You can use the returned values to populate the bmi structure.
And about the bmi structure: BITMAPINFO does not reserve enough space for a palette. You should create your own structure for this:
struct BitmapPlusPalette
{
BITMAPINFOHEADER bmiHeader;
RGBQUAD palette[256];
};
Calculating the number of bytes needed for the bitmap is a bit tricky because it needs to be rounded up:
w = ((bitmap.bmWidth * bitmap.bmBitsPixel) + 31) / 8;
byte* bits = new byte[w * bitmap.bmHeight];
And here's a corrected version of your final line:
int rv = ::GetDIBits(dc, ii.hbmColor, 0, bitmap.bmHeight, bits, (BITMAPINFO *)&bmi, DIB_RGB_COLORS);

The problem with your code I think is in the way you allocated memory for 'bits' variable and how you used it then in GetDIBits function.
Firstly, the commented part byte* bits = new byte[w*4] was better than byte* bits[1000]. When you write byte* bits[1000] computer allocates 1000 POINTERS to byte. Each of these pointers doesn't point to anything.
Secondly, GetDIBits accepts LPVOID lpvBits as a 5th param. So, its a pointer to void.
In most platforms sizeof(void *) > sizeof(byte), so you can't just pass it a byte array, probably it would be better to pass a pointer to int or unsigned int (I'm not good at Windows types, so maybe something more appropriate should be better, sorry).
So, my guess is this:
unsigned bits[1000];
memset(bits, 0, sizeof(bits));
//...
int tv = GetDIBits(memDC, ii.hmbColor, 0, 1, (LPVOID)bits, /* ... */);

Related

How to grab raw buffer from bitmap in GDI?

If I understand GDI correctly then the function GetDIBits retreives the raw pixel data from a captured bitmap image in windows
The GetDIBits function retrieves the bits of the specified compatible bitmap and copies them into a buffer as a DIB using the specified format.
so the following code should grab the pixel data only
HDC srcd , memdc;
HBITMAP hbmp;
BITMAP bmp;
DWORD dwBytesWritten = 0;
DWORD dwSizeofDIB = 0;
HANDLE hFile = NULL;
char* lpbitmap = NULL;
HANDLE hDIB = NULL;
DWORD dwBmpSize = 0;
BITMAPFILEHEADER bmfHeader;
BITMAPINFOHEADER bi;
int Height = GetSystemMetrics(SM_CYSCREEN);
int Width = GetSystemMetrics(SM_CXSCREEN);
srcd = GetDC(NULL);
if (!srcd)
printf("failed to obtain screen");
memdc = CreateCompatibleDC(srcd); // creates memory device context
hbmp = CreateCompatibleBitmap(srcd, Width, Height);
SelectObject(memdc, hbmp);
BitBlt(memdc, 0, 0, Width, Height, srcd, 0, 0, SRCCOPY);
BITMAP bmpScreen;
GetObject(hbmp, sizeof(bmpScreen), (LPVOID)&bmpScreen);
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = bmpScreen.bmWidth;
bi.biHeight = bmpScreen.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = 32;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
dwBmpSize = ((bmpScreen.bmWidth * bi.biBitCount + 31) / 32) * 4 * bmpScreen.bmHeight;
hDIB = GlobalAlloc(GHND, dwBmpSize);
lpbitmap = (char*)GlobalLock(hDIB);
GetDIBits(memdc, hbmp, 0,
(UINT)bmpScreen.bmHeight,
lpbitmap,
(BITMAPINFO*)&bi, DIB_RGB_COLORS);
printf("dwBmpSize: %ld\n", dwBmpSize);
printf("Strlen(lpbitmap): %lld\n", strlen(lpbitmap));
In my case I have a single screen with size (1920,1080) with a 32 bit value for each pixel then I should have around 66 mega bits but the output that I get does not make sense
dwBmpSize: 8294400
Strlen(lpbitmap): 103614
with that said I have couple of confusions:
Why does strlen return this small number
Why does the lpbitmap buffer contain garbage values (mostly A letters)
Why does strlen return this small number?
The strlen function is for textual strings, not bitmap data. This is binary data. The strlen simply reports the offset of where the first 0 value is found (usually the string terminator).
Why does the lpbitmap buffer contain garbage values (mostly A letters)?
None of the data is garbage. If you see a lot of one particular value, it is probably the background colour of the image you grabbed. It is meaningless when viewed with a text editor.

C: Trouble when trying to comvert HBITMAP into .bmp file

I am creating a function to save a screenshot into a .bmp file, I've managed to save the screen into an HBITMAP but I'm having trouble when saving it. I would appreciate some help.
Here is the header with the function:
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <stdbool.h>
#include <wingdi.h>
#include <winuser.h>
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned long u32;
typedef unsigned long long u64;
void getScreen()
{
u16 screenHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
u16 screenWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN);
HDC hdc = GetDC(NULL); //get a desktop dc (NULL for entire screen)
HDC hDest = CreateCompatibleDC(hdc); //create a dc for capture
ReleaseDC(NULL, hdc);
HBITMAP hbCapture = CreateCompatibleBitmap(hdc, screenWidth, screenHeight);
SelectObject(hDest, hbCapture);
//Copy screen to bitmap
BitBlt(hDest, 0, 0, screenWidth, screenHeight, hdc, 0, 0, SRCCOPY);
//test
ReleaseDC(NULL, hdc);
char memBuffer[10000];
BITMAPINFO bitmapInfo;
bitmapInfo.bmiHeader.biHeight = screenHeight;
bitmapInfo.bmiHeader.biWidth = screenWidth;
bitmapInfo.bmiHeader.biSize = screenWidth * screenHeight * 3;
bitmapInfo.bmiHeader.biCompression = BI_RGB;//NOT SURE
bitmapInfo.bmiHeader.biPlanes = 1;
bitmapInfo.bmiHeader.biBitCount = 8; //NOT SURE
bitmapInfo.bmiHeader.biClrImportant = 0;
GetDIBits(hDest, hbCapture, 0, screenHeight, &memBuffer, &bitmapInfo, DIB_RGB_COLORS);
FILE * fPointer = fopen("screen.png", "wb");//TO CHANGE
WriteFile(fPointer, &memBuffer, (WORD) sizeof(memBuffer), 0, NULL);
fclose(fPointer);
//test
//Clean up
ReleaseDC(NULL, hdc);
DeleteDC(hDest);
DeleteObject(hbCapture);
}
And here is also the main.c:
#include "main.h"
int main()
{
getScreen();
return 0;
}
I've already read all the questions about this topic in StackOverflow and none of them has clarified the issue for me.
bitmapInfo.bmiHeader.biSize = screenWidth * screenHeight * 3;
biSize is not the total pixel count, it's the size of bitmap info structure, it's always sizeof(BITMAPINFOHEADER).
You want to set bitmapInfo.bmiHeader.biSizeImage instead. This value is roughly (width * height * bits_per_pixel/8) but it has to be adjusted because each row is padded. Also don't mix fopen handle with CreateFile handle as noted in comments.
fopen("screen.png", "wb");
You cannot save to png format using this method. You need a different library like Gdiplus for png format.
To save as bitmap, you have to setup BITMAFILEHEADER, BITMAPINFOHEADER and write them to file, and then write the bits obtained from GetDIBits
You may want to avoid using typedef unsigned char u8; etc. You can include <stdint.h> and use standard types uint8_t, uint16_t, uint32_t etc. Or you can use standard Windows types like BYTE
void getScreen()
{
int screenWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN);
int screenHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
HDC hdc = GetDC(NULL);
HDC hDest = CreateCompatibleDC(hdc);
HBITMAP hbCapture = CreateCompatibleBitmap(hdc, screenWidth , screenHeight );
HBITMAP oldbmp = (HBITMAP)SelectObject(hDest, hbCapture);
BitBlt(hDest, 0, 0, screenWidth , screenHeight , hdc, 0, 0, SRCCOPY);
WORD bpp = 24; //<- bits per pixel
int size = ((screenWidth * bpp + 31) / 32) * 4 * screenHeight ;
BITMAPINFOHEADER bmp_info_hdr;
bmp_info_hdr.biSize = sizeof(bmp_info_hdr);
bmp_info_hdr.biHeight = screenHeight ;
bmp_info_hdr.biWidth = screenWidth ;
bmp_info_hdr.biPlanes = 1;
bmp_info_hdr.biBitCount = bpp;
bmp_info_hdr.biCompression = BI_RGB;
bmp_info_hdr.biSizeImage = size;
BITMAPFILEHEADER bmp_file_hdr;
bmp_file_hdr.bfType = (WORD)'MB';
bmp_file_hdr.bfOffBits = sizeof(bmp_file_hdr) + sizeof(bmp_info_hdr);
bmp_file_hdr.bfSize = bmp_file_hdr.bfOffBits + size;
char *buffer = malloc(size);
GetDIBits(hDest, hbCapture, 0, screenHeight , buffer,
(BITMAPINFO*)&bmp_info_hdr, DIB_RGB_COLORS);
FILE * fPointer = fopen("screen.bmp", "wb");
fwrite((char*)&bmp_file_hdr, sizeof(bmp_file_hdr), 1, fPointer);
fwrite((char*)&bmp_info_hdr, sizeof(bmp_info_hdr), 1, fPointer);
fwrite(buffer, size, 1, fPointer);
fclose(fPointer);
free(buffer);
SelectObject(hDest, oldbmp);
DeleteObject(hbCapture);
DeleteDC(hDest);
ReleaseDC(NULL, hdc);
}

how to split the image and save it in one-dimensional arrays

I'm making a sliding puzzle using image.
And in the process, I'm going to bring up the images, and divide them into tiles of a certain size, and put them in one-dimensional arrays in order.
I will register the image file as a resource, or I will import the image file using the HBITMAP and LoadImage functions.
But I just can't think of how we're going to divide this image file into a certain size (rectangular) and store it in a one-dimensional array.
Would it be OK to save the segmented tiles to each image file and then save the path of the files in a one-dimensional array?
*Note: One-dimensional array and double buffering must be used.
You don't need to serialize the pieces to files. If you want to, that is a separate issue.
You can load the image as one image and split it in memory. Basically create correctly sized bitmaps for the piece images in memory and paint a section of the main bitmap into each one. You also do not need to fool around with CreateDIBSection to do it this way -- can just do it all with compatible bitmaps and device contexts.
Something like the following (I did not test this)
std::vector<HBITMAP> SplitBitmap(HBITMAP bmp, int columns, int rows)
{
// get the bitmap dimensions
BITMAP bm;
GetObject(bmp, sizeof(BITMAP), &bm);
int wd = bm.bmWidth, hgt = bm.bmHeight;
int piece_wd = wd / columns;
int piece_hgt = hgt / rows;
// Select the given bitmap into a device context.
auto hdcScreen = GetDC(NULL);
auto hdcBitmap = CreateCompatibleDC(hdcScreen);
auto hbmOldBmp = SelectObject(hdcBitmap, bmp);
std::vector<HBITMAP> pieces(columns*rows);
for (int row = 0; row < rows; row++) {
for (int col = 0; col < columns; col++) {
// create a device context for a piece and select an appropriately sized bitmap into it
auto hdcPiece = CreateCompatibleDC(hdcScreen);
auto hbmPiece = CreateCompatibleBitmap(hdcScreen, piece_wd, piece_hgt);
auto hbmOldPiece = SelectObject(hdcPiece, hbmPiece);
// paint a piece of the whole bitmap into the piece bitmap
BitBlt(hdcPiece, 0, 0, piece_wd, piece_hgt, hdcBitmap, col * piece_wd, row * piece_hgt, SRCCOPY);
// cleanup per piece resources we dont need.
SelectObject(hdcPiece, hbmOldPiece);
DeleteDC(hdcPiece);
pieces[row * columns + col] = hbmPiece;
}
}
SelectObject(hdcBitmap, hbmOldBmp);
DeleteDC(hdcBitmap);
ReleaseDC(NULL, hdcScreen);
return pieces;
}
...
auto hbm = (HBITMAP)LoadImage(NULL, L"C:\\work\\test.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
auto pieces = SplitBitmap(hbm, 4, 4);
You can do this.
Here are some simplified codes for your reference.
int Spilt(HWND hWnd)
{
BYTE* bitPointer;
HBITMAP g_BitMap = (HBITMAP)LoadImage(NULL, L"C:\\Users\\strives\\Desktop\\timg.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
HDC dc = GetDC(hWnd);
HDC dc_1 = GetDC(hWnd);
HDC hdcMemDC = CreateCompatibleDC(dc);
HDC hdcTemp = CreateCompatibleDC(dc);
HDC hdcMemDC_1 = GetDC(hWnd);
BITMAP bmp;
BITMAP bmp_3;
GetObject(g_BitMap, sizeof(BITMAP), &bmp);
static BITMAPINFO bitmap;
bitmap.bmiHeader.biSize = sizeof(bitmap.bmiHeader);
bitmap.bmiHeader.biWidth = bmp.bmWidth / 2;
bitmap.bmiHeader.biHeight = bmp.bmHeight;
bitmap.bmiHeader.biPlanes = 1;
bitmap.bmiHeader.biBitCount = 24;
bitmap.bmiHeader.biCompression = BI_RGB;
bitmap.bmiHeader.biSizeImage = bmp.bmWidth / 2 * bmp.bmHeight * 4;
bitmap.bmiHeader.biClrUsed = 0;
bitmap.bmiHeader.biClrImportant = 0;
HBITMAP hBitmap2 = CreateDIBSection(hdcTemp, &bitmap, DIB_RGB_COLORS, (void**)(&bitPointer), NULL, NULL);
HBITMAP bmp_1 = CreateCompatibleBitmap(hdcMemDC_1, bmp.bmWidth / 2, bmp.bmHeight );
SelectObject(hdcMemDC, g_BitMap);
SelectObject(hdcTemp, bmp_1);
BitBlt(hdcTemp, 0, 0, bmp.bmWidth / 2, bmp.bmHeight, hdcMemDC, 0, 0, SRCCOPY);
GetObject(bmp_1, sizeof(BITMAP), &bmp_3);
BITMAPFILEHEADER bmfHeader;
BITMAPINFOHEADER bi;
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = bmp_3.bmWidth;
bi.biHeight = bmp_3.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = 24;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
DWORD dwBmpSize = ((bmp_3.bmWidth * bi.biBitCount + 31) / 32) * 4 * bmp_3.bmHeight;
// Starting with 24-bit Windows, GlobalAlloc and LocalAlloc are implemented as wrapper functions that
// call HeapAlloc using a handle to the process's default heap. Therefore, GlobalAlloc and LocalAlloc
// have greater overhead than HeapAlloc.
HANDLE hDIB = GlobalAlloc(GHND, dwBmpSize);
char *lpbitmap = (char *)GlobalLock(hDIB);
GetDIBits(hdcMemDC, bmp_1, 0,
(UINT)bmp_3.bmHeight,
lpbitmap,
(BITMAPINFO *)&bi,
DIB_RGB_COLORS);
// A file is created, this is where we will save the screen capture.
HANDLE hFile = CreateFile(L"spilt_1.bmp",
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
DWORD dwSizeofDIB = dwBmpSize + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
bmfHeader.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER);
bmfHeader.bfSize = dwSizeofDIB;
bmfHeader.bfType = 0x4D42; //BM
DWORD dwBytesWritten = 0;
WriteFile(hFile, (LPSTR)&bmfHeader, sizeof(BITMAPFILEHEADER), &dwBytesWritten, NULL);
WriteFile(hFile, (LPSTR)&bi, sizeof(BITMAPINFOHEADER), &dwBytesWritten, NULL);
WriteFile(hFile, (LPSTR)lpbitmap, dwBmpSize, &dwBytesWritten, NULL);
//Unlock and Free the DIB from the heap
GlobalUnlock(hDIB);
GlobalFree(hDIB);
//Close the handle for the file that was created
CloseHandle(hFile);
DeleteObject(hdcTemp);
DeleteObject(hdcMemDC);
DeleteObject(hBitmap2);
DeleteObject(bmp_1);
return 0;
}
For convenience of understanding, I divide the bitmap into two pieces and save them as image files. Finally, I can save the file path to a one-dimensional array.
Code reference: Capturing an Image and consulted #Jonathan Potter advice.

How to read a BMP file into a grid of pixels in C?

I'm trying to read in a given BMP file and store it in an image. I'm confused about the syntax since I'm struggling to understand the .h files given to me. Here's how I'm going about reading in the image:
BMPImage * readImage(FILE * fp) {
// FILL IN
BMPHeader * hp = malloc(sizeof(BMPHeader);
Pixel * p = malloc(sizeof(Pixel));
p -> pixels = malloc(p -> height_px * sizeof(Pixel *));
for(int i = 0; i < p -> height_px; i++){
p -> pixels[i] = malloc(p -> width_px * sizeof(Pixel));
}
for (i = 0; i < p -> height_px; i++){
for(int j = 0; j < p -> width_px; j++){
Pixel px = fread(hp, sizeof(Pixel), 1, fp);
p -> pixels[i][j] = px;
}
}
return p;
}
Here's the .h file:
typedef struct __attribute__((packed)) BMPHeader { // Total: 54 bytes
uint16_t type; // Magic identifier: 0x4d42
uint32_t size; // File size in bytes
uint16_t reserved1; // Not used
uint16_t reserved2; // Not used
uint32_t offset; // Offset to image data in bytes from beginning of file (54 bytes)
uint32_t dib_header_size; // DIB Header size in bytes (40 bytes)
int32_t width_px; // Width of the image
int32_t height_px; // Height of image
uint16_t num_planes; // Number of color planes
uint16_t bits_per_pixel; // Bits per pixel
uint32_t compression; // Compression type
uint32_t image_size_bytes; // Image size in bytes
int32_t x_resolution_ppm; // Pixels per meter
int32_t y_resolution_ppm; // Pixels per meter
uint32_t num_colors; // Number of colors
uint32_t important_colors; // Important colors
} BMPHeader;
typedef struct __attribute__((packed)) Pixel {
uint8_t blue;
uint8_t green;
uint8_t red;
uint8_t alpha;
} Pixel;
typedef struct BMPImage {
BMPHeader header;
int norm_height; //normalized height
Pixel * * pixels;
} BMPImage;
How should I correct my reading method?
Given how you're struggling with structs, lists, and basic I/O, reading in a BMP is probably over your head right now. I'd suggest trying to populate a simpler struct. If this is for a production code, please use an existing library.
I'm going to do some basic fixups so your code at least compiles, hopefully you can take it from there.
BMPImage *readImage(FILE * fp) {
// Allocate space for the image.
// This also covers BMPHeader, since it's not a pointer.
BMPImage *bmp = malloc(sizeof(BMPImage));
BMPHeader *bmph = &(bmp->header);
The basic unit is the BMPImage struct. That contains the BMPHeader as well as a pointer to list of Pixels. The BMPHeader is not a pointer, the actual memory is contained in the BMPImage struct, so malloc(sizeof(BMPImage)) also allocates memory for the BMPHeader. I've taken a pointer to the BMPHeader to make it easier to work with, otherwise the code is sprinkled with bmp.header->height_x.
I'll leave populating the BMPHeader to you. Once you've done that...
// Allocate space for the pixels.
bmp->pixels = malloc( bmph->height_px * sizeof(Pixel *) );
for(int i = 0; i < bmph->height_px; i++){
bmp->pixels[i] = malloc(bmph->width_px * sizeof(Pixel));
}
I think you've basically got the memory allocation right. Your problem was trying to use the Pixel struct when you should have been using BMPImage. While the height and width comes from the BMPHeader.
That isn't really how you should be reading in a BMP since the size of the pixels are variable according to the bits_per_pixel header. Your structs only support the 8bpp format. It also might be compressed. I'm going to assume this is an exercise and not production code, so I'll avoid going further into the details of BMP.
// Read in each pixel
for (int i = 0; i < bmph->height_px; i++){
for(int j = 0; j < bmph->width_px; j++){
Pixel px;
if( fread(&px, sizeof(Pixel), 1, fp) < 1 ) {
fprintf(stderr, "Error while reading bmp: %s", strerror(errno));
return NULL;
}
bmp->pixels[i][j] = px;
}
}
Again, you had the BMPImage and BMPHeader mixed up with Pixel. Furthermore, fopen does not return the structure to be read. Instead, you're responsible for allocating the necessary memory (a theme in C). fopen returns the number of items read. It's very important to do error checking on all file operations, else you'll be left with difficult to understand garbage.
I suspect you can do this much simpler by reading in all the pixels in one big chunk, but I don't know the details of the BMP format.
This is by no means 100% correct, I'm not even sure it's 80% correct, but it'll at least clean up the worst of the confusion.
Here is untested code.
void readImage(FILE * fp, BMPImage *bpp) {
Pixel pixel;
for (i = 0; i < p -> height_px; i++){
for(int j = 0; j < p -> width_px; j++){
fread(&pixel, sizeof(Pixel), 1, fp);
bpp->pixels[i][j] = pixel;
}
}
int
main()
{
BMPHeader *hp = malloc(sizeof(* hp));
FILE *fp;
int i;
... read header info and stored into hp->header
... open fp file
hp->pixels = malloc(bpp->header.width_px * sizeof(Pixel *));
for( i=0; i<hp->header.width_px; i++ )
hp->pixels[i] = malloc(bpp->header.height_px * sizeof(Pixel));
//Send in pointers.
readImage(fp, hp);
... need to free up memory.
}
.
First, need to follow composite data structure.
Second, need to free up memory since it looks like it will need a lot of memory.
It is a good practice to allocate/free up memory in one area.

Add imagedata to Bitmap in raw bytes

I am trying to add imagedata to an existing bitmap.
The existing bitmap is stored in an byte array:
That's how the image looks like:
If I want to add, let's say 2 lines of blue to the bottom, how could I do that?
#include <Windows.h>
const char tred[] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC8,0xD1,0xF8,0x95,0xA7,0xF4,0x65,0x80,0xED,0xB0,0xBC,0xF6,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xD0,0xD7,0xFA,0x48,0x68,0xEB,0x01,0x2E,0xE2,0x06,0x30,0xE4,
0x12,0x3A,0xE4,0x0D,0x36,0xE5,0x71,0x8A,0xEF,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF4,
0xF6,0xFD,0x35,0x58,0xE9,0x00,0x2B,0xE3,0x19,0x40,0xE6,0x21,0x46,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x17,0x3E,0xE6,0x78,0x90,0xF0,0x00,
0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xAD,0xBA,0xF6,0x00,0x27,0xE3,0x1A,0x41,0xE6,0x21,0x47,0xE7,0x21,0x47,
0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x17,0x3E,0xE6,0x78,0x90,0xF0,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0x94,0xA6,0xF2,0x00,0x28,0xE3,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,
0x17,0x3E,0xE6,0x78,0x90,0xF0,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xBB,0xC6,0xF7,0x00,0x27,0xE2,0x22,0x47,0xE7,0x21,0x47,0xE7,0x21,
0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x17,0x3E,0xE6,0x78,0x90,0xF0,0x00,0x00,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0x00,0x2C,0xE3,0x20,0x46,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,
0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x17,0x3E,0xE6,0x78,0x90,0xF0,0x00,0x00,0xFF,0xFF,0xFF,0x67,0x82,0xEE,0x13,0x3C,0xE5,0x21,0x47,0xE7,
0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x17,0x3E,0xE6,
0x78,0x90,0xF0,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x2C,0xE3,0x20,0x46,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,
0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x17,0x3E,0xE6,0x78,0x90,0xF0,0x00,0x00,0xC3,0xCD,0xF8,0x07,0x31,
0xE4,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,
0xE7,0x21,0x47,0xE7,0x17,0x3E,0xE6,0x78,0x90,0xF0,0x00,0x00,0x8B,0x9F,0xF1,0x13,0x3B,0xE5,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,
0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x17,0x3E,0xE6,0x78,0x90,0xF0,
0x00,0x00,0x78,0x90,0xF0,0x17,0x3E,0xE5,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,
0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x17,0x3E,0xE6,0x78,0x90,0xF0,0x00,0x00,0x79,0x8F,0xF0,0x17,0x3E,0xE5,0x21,0x47,
0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,
0xE7,0x17,0x3E,0xE6,0x78,0x90,0xF0,0x00,0x00,0x8E,0xA2,0xF2,0x12,0x3A,0xE5,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,
0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x17,0x3E,0xE6,0x78,0x90,0xF0,0x00,0x00,0xC9,
0xD1,0xF9,0x05,0x30,0xE4,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,
0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x17,0x3E,0xE6,0x78,0x90,0xF0,0x00,0x00,0xFF,0xFF,0xFF,0x04,0x2F,0xE3,0x20,0x46,0xE6,0x21,0x47,
0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x17,0x3E,
0xE6,0x78,0x90,0xF0,0x00,0x00,0xFF,0xFF,0xFF,0x75,0x8C,0xEF,0x11,0x3A,0xE5,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,
0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x17,0x3E,0xE6,0x78,0x90,0xF0,0x00,0x00,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0x05,0x2F,0xE3,0x20,0x46,0xE6,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,
0x47,0xE7,0x21,0x47,0xE7,0x17,0x3E,0xE6,0x78,0x90,0xF0,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xD0,0xD7,0xF9,0x00,0x25,0xE3,0x21,0x47,
0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x17,0x3E,0xE6,0x78,0x90,
0xF0,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xAE,0xBC,0xF6,0x00,0x26,0xE3,0x20,0x46,0xE6,0x21,0x47,0xE7,0x21,0x47,0xE7,
0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x17,0x3E,0xE6,0x78,0x90,0xF0,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xC8,0xD1,0xF8,0x02,0x2D,0xE3,0x15,0x3D,0xE6,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,
0x47,0xE7,0x17,0x3E,0xE6,0x78,0x90,0xF0,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFE,0x51,0x6F,0xEB,0x00,0x27,0xE3,0x16,0x3D,0xE6,0x1F,0x46,0xE6,0x22,0x47,0xE7,0x21,0x47,0xE7,0x17,0x3E,0xE6,0x78,0x90,0xF0,0x00,0x00,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xEB,0xEF,0xFC,0x65,0x7E,0xEE,
0x0C,0x36,0xE3,0x00,0x2A,0xE3,0x0D,0x36,0xE4,0x0A,0x34,0xE4,0x70,0x89,0xEF,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE4,0xE8,0xFC,0xAE,0xBC,0xF6,0x7E,
0x94,0xF0,0xBD,0xC7,0xF7,0x00,0x00 };
int main(int argc, char* argv[]) {
BITMAPFILEHEADER bmfh;
BITMAPINFOHEADER bmih;
bmih.biSize = sizeof(BITMAPINFOHEADER);;
bmih.biWidth = 14;
bmih.biHeight = 96;
bmih.biPlanes = 1;
bmih.biBitCount = 24;
bmih.biCompression = 0;
bmih.biSizeImage = 0;
bmih.biXPelsPerMeter = 0;
bmih.biYPelsPerMeter = 0;
bmih.biClrUsed = 0;
bmih.biClrImportant = 0;
bmfh.bfType = 19778;
bmfh.bfSize = ((bmih.biWidth * bmih.biBitCount + 31) / 32) * 4 * bmih.biHeight;
bmfh.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER); // 54
bmfh.bfReserved1 = 0;
bmfh.bfReserved2 = 0;
char* bmpData = (char*)malloc(bmfh.bfSize);
memcpy(bmpData, tred, sizeof(tred));
HANDLE h = CreateFile("C:\\tmp\\a.bmp", GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
DWORD d;
WriteFile(h, &bmfh, sizeof(bmfh), &d, 0);
WriteFile(h, &bmih, sizeof(bmih), &d, 0);
WriteFile(h, bmpData, bmfh.bfSize, &d, 0);
CloseHandle(h);
delete[] bmpData;
return 0;
}
What I do not understand: Original file is 14px*24px = 366px in total. In a 24bit Bitmap, there is RGB (3 Bytes) for each pixel, so that would be 366*3=1008bytes. The original file (without header) has 1056bytes.
Maybe that's the reason why my approach, by adding 14*3=42bytes of 0xFF did not add an extra line?

Resources