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

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.

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);
}

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?

HDF5: How to append data to a dataset (extensible array)

By following this tutorial, I've tried to extend my HDF5 dataset. The code is the following, however the data is not properly written to the dataset (the dataset has the proper final size but contains only zeros). The only difference from the tutorial is that I have to use dynamic arrays. Any idea?
int main()
{
hsize_t dims[1], max_dims[1], newdims[1], chunk_dims[1], offset[1];
hid_t file, file_space, plist, dataset, mem_space;
int32_t *buffer1, *buffer2;
file = H5Fcreate("test.h5", H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
// Create dataspace with initial dim = 0 and final = UNLIMITED
dims[0] = 0;
max_dims[0] = H5S_UNLIMITED;
file_space = H5Screate_simple(RANK, dims, max_dims);
// Create dataset creation property list to have chunks
plist = H5Pcreate(H5P_DATASET_CREATE);
H5Pset_layout(plist, H5D_CHUNKED);
chunk_dims[0] = 2;
H5Pset_chunk(plist, RANK, chunk_dims);
// Create the dataset
dataset = H5Dcreate(file, "Test", H5T_NATIVE_INT32, file_space, H5P_DEFAULT, plist, H5P_DEFAULT);
H5Pclose(plist);
H5Sclose(file_space);
//## FIRST BUFFER
int length = 6;
buffer1 = new int32_t[length];
for (hsize_t i = 0; i < length; i++)
buffer1[i] = i;
// Extend the dataset by getting previous size and adding current length
file_space = H5Dget_space(dataset);
H5Sget_simple_extent_dims(file_space, dims, NULL);
newdims[0] = dims[0] + length;
H5Dset_extent(dataset, newdims);
// Select hyperslab on the file dataset
offset[0] = dims[0];
dims[0] = length;
H5Sselect_hyperslab(file_space, H5S_SELECT_SET, offset, NULL, dims, NULL);
// Dataspace for buffer in memory
mem_space = H5Screate_simple(RANK, dims, NULL);
// Append buffer to dataset
H5Dwrite(dataset, H5T_NATIVE_INT32, mem_space, file_space, H5P_DEFAULT, buffer1);
H5Sclose(file_space);
H5Sclose(mem_space);
//## SECOND BUFFER
length = 4;
buffer2 = new int32_t[length];
for (hsize_t i = 0; i < length; i++)
buffer2[i] = i;
// Extend the dataset by getting previous size and adding current length
file_space = H5Dget_space(dataset);
H5Sget_simple_extent_dims(file_space, dims, NULL);
newdims[0] = dims[0] + length;
H5Dset_extent(dataset, newdims);
// Select hyperslab on the file dataset
offset[0] = dims[0];
dims[0] = length;
H5Sselect_hyperslab(file_space, H5S_SELECT_SET, offset, NULL, dims, NULL);
// Dataspace for buffer in memory
mem_space = H5Screate_simple(RANK, dims, NULL);
// Append buffer to dataset
H5Dwrite(dataset, H5T_NATIVE_INT32, mem_space, file_space, H5P_DEFAULT, buffer2);
H5Sclose(file_space);
H5Sclose(mem_space);
H5Dclose(dataset);
H5Fclose(file);
delete[] buffer1;
delete[] buffer2;
}
I've figured out how to solve the problem. It has nothing to do with the dynamic arrays. The problem is that after calling H5Sget_simple_extent_dims the dataspace id gets somehow invalidated (I do not understand why...a bug?) and you need to get it again before reusing it, e.g. before selecting the hyperslab:
// Select hyperslab on the file dataset
offset[0] = dims[0];
dims[0] = length;
H5Dclose(file_space); // --ADDED-- CLOSE THE PREVIOUSLY OPENED
file_space = H5Dget_space(dataset); // --ADDED-- REOPEN
H5Sselect_hyperslab(file_space, H5S_SELECT_SET, offset, NULL, dims, NULL);

Mouse cursor bitmap

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, /* ... */);

Resources