How to take a screenshot with a maximum resolution in C - c

I am using the following code to take a screenshot in C on Windows (from https://learn.microsoft.com/en-us/windows/win32/gdi/capturing-an-image).
int captureImage(HWND hWnd, char * filename){
HDC hdcScreen;
HDC hdcWindow;
HDC hdcMemDC = NULL;
HBITMAP hbmScreen = NULL;
BITMAP bmpScreen;
DWORD dwBytesWritten = 0;
DWORD dwSizeofDIB = 0;
HANDLE hFile = NULL;
char* lpbitmap = NULL;
HANDLE hDIB = NULL;
DWORD dwBmpSize = 0;
// retrieve handle to display device content
hdcScreen = GetDC(NULL);
hdcWindow = GetDC(hWnd);
// Create a compatible DC (domain controller)
hdcMemDC = CreateCompatibleDC(hdcWindow);
if (!hdcMemDC){
printf("Error creating hdcMemDC\n");
return 1;
}
// Make process DPI aware to avoid wrongly sized screenshots when screen resolution changes
SetProcessDPIAware();
// get area for size calculations
RECT rcClient;
GetClientRect(hWnd, &rcClient);
// use this stretch mode
SetStretchBltMode(hdcWindow, HALFTONE);
// the source DC is the entire screen, and the destination in the current window (for now)
StretchBlt(hdcWindow, 0, 0, rcClient.right, rcClient.bottom, hdcScreen, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), SRCCOPY);
// create a compatible bitmap from the Window DC
hbmScreen = CreateCompatibleBitmap(hdcWindow, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top);
if (!hbmScreen){
printf("Error creating hmbScreen\n");
return 1;
}
// Select the compatible bitmap into the memory DC
SelectObject(hdcMemDC, hbmScreen);
// transfer bits into the memory DC
BitBlt(hdcMemDC, 0, 0, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top, hdcWindow, 0 , 0, SRCCOPY);
// get the bitmap from the hbitmap
GetObject(hbmScreen, sizeof(BITMAP), &bmpScreen);
// bitmap file header and info header
BITMAPFILEHEADER bmfHeader;
BITMAPINFOHEADER bi;
// set all values for info header
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);
// get the bits from the bitmap and copy them into the buffer
GetDIBits(hdcWindow, hbmScreen, 0, (UINT)bmpScreen.bmHeight, lpbitmap, (BITMAPINFO*)&bi, DIB_RGB_COLORS);
// create a file to save the capture into
hFile = CreateFile(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
// get the total size of the file
dwSizeofDIB = dwBmpSize + (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER);
// offset to where our bitmap actually starts
bmfHeader.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER);
// size of the file
bmfHeader.bfSize = dwSizeofDIB;
// always set bfType to BM for bitmaps
bmfHeader.bfType = 0x4D42; // that's BM
// write data to the file
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 stuff
GlobalUnlock(hDIB);
GlobalFree(hDIB);
// close file handle
CloseHandle(hFile);
// Clean everything up
DeleteObject(hbmScreen);
DeleteObject(hdcMemDC);
ReleaseDC(NULL, hdcScreen);
ReleaseDC(hWnd, hdcWindow);
return 0; // for normal exit
}
Passing in the return value of GetDesktopWindow() will take a screenshot of the entire screen and save it a to a file with filename. The screenshot is the size of and has the resolution of the screen. So, if used on a 4k screen, that will be the resolution of the screenshot. I was wondering what the best way was to cap this at, say, 1080p. So even if the resolution is greater than 1080x1920, the screenshot will not go higher.

use such code
ULONG captureImage(_In_ ULONG cx, _In_ PCWSTR filename)
{
struct BMEX
{
USHORT ForAlign;
BITMAPFILEHEADER bfh;
BITMAPINFOHEADER bih;
UCHAR Bits[];
};
ULONG cxScreen = GetSystemMetrics(SM_CXSCREEN), cyScreen = GetSystemMetrics(SM_CYSCREEN);
ULONG cy = cyScreen * cx / cxScreen;
ULONG size = ((3 * cx + sizeof(ULONG) - 1) & ~(sizeof(ULONG) - 1)) * cy;
ULONG dwError;
if (HANDLE hSection = CreateFileMappingW(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, size + sizeof(BMEX), 0))
{
BITMAPINFO bi = {
{ sizeof(BITMAPINFOHEADER), cx, cy, 1, 24, BI_RGB, size }
};
PVOID Bits;
if (HBITMAP hbmp = CreateDIBSection(0, &bi, DIB_RGB_COLORS, &Bits, hSection, __builtin_offsetof(BMEX, Bits)))
{
if (HDC hdc = GetDC(0))
{
if (HDC hMemDC = CreateCompatibleDC(0))
{
HGDIOBJ h = SelectObject(hMemDC, hbmp);
if (StretchBlt(hMemDC, 0, 0, cx, cy, hdc, 0, 0, cxScreen, cyScreen, SRCCOPY))
{
HANDLE hFile = CreateFileW(filename, FILE_APPEND_DATA, 0, 0, CREATE_ALWAYS, 0, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
BMEX* p = CONTAINING_RECORD(Bits, BMEX, Bits);
p->bfh.bfType = 'MB';
p->bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
p->bfh.bfSize = size += sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
p->bfh.bfReserved1 = 0;
p->bfh.bfReserved2 = 0;
memcpy(&p->bih, &bi.bmiHeader, sizeof(BITMAPINFOHEADER));
dwError = WriteFile(hFile, &p->bfh, size, &size, 0) ? NOERROR : GetLastError();
CloseHandle(hFile);
}
else
{
dwError = GetLastError();
}
}
else
{
dwError = GetLastError();
}
SelectObject(hMemDC, h);
DeleteDC(hMemDC);
}
else
{
dwError = GetLastError();
}
ReleaseDC(0, hdc);
}
else
{
dwError = GetLastError();
}
DeleteObject(hbmp);
}
else
{
dwError = GetLastError();
}
CloseHandle(hSection);
return dwError;
}
return GetLastError();
}

Related

I composed sending bitmap using C [duplicate]

I'm trying to send a bitmap image to server but server can't receive a bitmap file.
I've checked sending byte in client and receiving byte in server.
Before this Question, I asked similar problem in stack overflow.
And I know I don't check sending byte and receiving byte.
so I check those, but server can't receive a bitmap. server just print gray.
send function returns 3244104 and receive function returns 3244104
Those are same. help me.........
here is my server code.
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg,
WPARAM wParam, LPARAM lParam)
{
HDC hdcWindow;
HDC hdcbuffer;
HBITMAP hbm = NULL;
static BITMAPINFOHEADER bi;
static WSADATA wsadata;
static SOCKET s, cs;
static SOCKADDR_IN addr = { 0 }, c_addr;
int size;
static char* buffer;
switch (iMsg)
{
case WM_CREATE:
WSAStartup(MAKEWORD(2, 2), &wsadata);
s = socket(AF_INET, SOCK_STREAM, 0);
addr.sin_family = AF_INET;
addr.sin_port = 20;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
bind(s, (LPSOCKADDR)&addr, sizeof(addr));
WSAAsyncSelect(s, hwnd, WM_ASYNC, FD_ACCEPT);
if (listen(s, 5) == -1)
return 0;
break;
case WM_ASYNC:
switch (lParam)
{
case FD_ACCEPT:
size = sizeof(c_addr);
cs = accept(s, (LPSOCKADDR)&c_addr, &size);
WSAAsyncSelect(cs, hwnd, WM_ASYNC, FD_READ);
break;
case FD_READ:
hdcWindow = GetDC(hwnd);
hdcbuffer = CreateCompatibleDC(hdcWindow);
recv(cs, (char*)&bi, sizeof(bi), 0);
buffer = (char*)malloc(bi.biSizeImage);
int i = recv(cs, buffer, bi.biSizeImage, 0);
hbm = CreateCompatibleBitmap(hdcWindow, bi.biWidth, bi.biHeight);
SelectObject(hdcbuffer, hbm);
SetDIBits(hdcbuffer, hbm, 0, bi.biHeight, buffer, (BITMAPINFO*)&bi, DIB_RGB_COLORS);
BitBlt(hdcWindow,
0, 0,
bi.biWidth, bi.biHeight,
hdcbuffer,
0, 0,
SRCCOPY);
free(buffer);
DeleteObject(hbm);
ReleaseDC(hwnd, hdcWindow);
DeleteDC(hdcbuffer);
break;
}
break;
case WM_DESTROY:
closesocket(cs);
closesocket(s);
WSACleanup();
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, iMsg, wParam, lParam);
}
this is my client code.
HINSTANCE hinst;
char* lpbitmap = NULL;
SOCKET s;
RECT rcClient;
HDC hdcScreen;
HDC hdcWindow;
int CaptureAnImage(HWND hWnd)
{
static HDC hdcMemDC;
static HBITMAP hbmScreen;
static BITMAP bmpScreen;
hdcScreen = GetDC(NULL);
hdcWindow = GetDC(hWnd);
hdcMemDC = CreateCompatibleDC(hdcWindow);
GetClientRect(hWnd, &rcClient);
SetStretchBltMode(hdcWindow, HALFTONE);
StretchBlt(hdcWindow,
0, 0,
rcClient.right, rcClient.bottom,
hdcScreen,
0, 0,
GetSystemMetrics(SM_CXSCREEN),
GetSystemMetrics(SM_CYSCREEN),
SRCCOPY);
hbmScreen = CreateCompatibleBitmap(hdcWindow, rcClient.right - rcClient.left, rcClient.bottom
- rcClient.top);
SelectObject(hdcMemDC, hbmScreen);
BitBlt(hdcMemDC,
0, 0,
rcClient.right - rcClient.left, rcClient.bottom - rcClient.top,
hdcWindow,
0, 0,
SRCCOPY);
GetObject(hbmScreen, sizeof(BITMAP), &bmpScreen);
BITMAPINFOHEADER bi;
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;
GetDIBits(hdcWindow, hbmScreen, 0, bmpScreen.bmHeight, NULL, (BITMAPINFO*)&bi,
DIB_RGB_COLORS);
if (!bi.biSizeImage)
{
bi.biSizeImage = (((bi.biWidth*bi.biBitCount + 0x1F)&~0x1F) >> 3)*bi.biHeight;
}
lpbitmap = (char*)malloc(bi.biSizeImage);
GetDIBits(hdcWindow, hbmScreen, 0,
(UINT)bmpScreen.bmHeight,
lpbitmap,
(BITMAPINFO*)&bi, DIB_RGB_COLORS);
send(s, (char*)&bi, sizeof(bi), 0);
send(s, lpbitmap, bi.biSizeImage, 0);
free(lpbitmap);
DeleteObject(hbmScreen);
DeleteObject(hdcMemDC);
ReleaseDC(NULL, hdcScreen);
ReleaseDC(hWnd, hdcWindow);
return 0;
}
help me......
I can't solve this problem......

how to send a bitmap to server? using C

I'm trying to send a bitmap image to server but server can't receive a bitmap file.
I've checked sending byte in client and receiving byte in server.
Before this Question, I asked similar problem in stack overflow.
And I know I don't check sending byte and receiving byte.
so I check those, but server can't receive a bitmap. server just print gray.
send function returns 3244104 and receive function returns 3244104
Those are same. help me.........
here is my server code.
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg,
WPARAM wParam, LPARAM lParam)
{
HDC hdcWindow;
HDC hdcbuffer;
HBITMAP hbm = NULL;
static BITMAPINFOHEADER bi;
static WSADATA wsadata;
static SOCKET s, cs;
static SOCKADDR_IN addr = { 0 }, c_addr;
int size;
static char* buffer;
switch (iMsg)
{
case WM_CREATE:
WSAStartup(MAKEWORD(2, 2), &wsadata);
s = socket(AF_INET, SOCK_STREAM, 0);
addr.sin_family = AF_INET;
addr.sin_port = 20;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
bind(s, (LPSOCKADDR)&addr, sizeof(addr));
WSAAsyncSelect(s, hwnd, WM_ASYNC, FD_ACCEPT);
if (listen(s, 5) == -1)
return 0;
break;
case WM_ASYNC:
switch (lParam)
{
case FD_ACCEPT:
size = sizeof(c_addr);
cs = accept(s, (LPSOCKADDR)&c_addr, &size);
WSAAsyncSelect(cs, hwnd, WM_ASYNC, FD_READ);
break;
case FD_READ:
hdcWindow = GetDC(hwnd);
hdcbuffer = CreateCompatibleDC(hdcWindow);
recv(cs, (char*)&bi, sizeof(bi), 0);
buffer = (char*)malloc(bi.biSizeImage);
int i = recv(cs, buffer, bi.biSizeImage, 0);
hbm = CreateCompatibleBitmap(hdcWindow, bi.biWidth, bi.biHeight);
SelectObject(hdcbuffer, hbm);
SetDIBits(hdcbuffer, hbm, 0, bi.biHeight, buffer, (BITMAPINFO*)&bi, DIB_RGB_COLORS);
BitBlt(hdcWindow,
0, 0,
bi.biWidth, bi.biHeight,
hdcbuffer,
0, 0,
SRCCOPY);
free(buffer);
DeleteObject(hbm);
ReleaseDC(hwnd, hdcWindow);
DeleteDC(hdcbuffer);
break;
}
break;
case WM_DESTROY:
closesocket(cs);
closesocket(s);
WSACleanup();
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, iMsg, wParam, lParam);
}
this is my client code.
HINSTANCE hinst;
char* lpbitmap = NULL;
SOCKET s;
RECT rcClient;
HDC hdcScreen;
HDC hdcWindow;
int CaptureAnImage(HWND hWnd)
{
static HDC hdcMemDC;
static HBITMAP hbmScreen;
static BITMAP bmpScreen;
hdcScreen = GetDC(NULL);
hdcWindow = GetDC(hWnd);
hdcMemDC = CreateCompatibleDC(hdcWindow);
GetClientRect(hWnd, &rcClient);
SetStretchBltMode(hdcWindow, HALFTONE);
StretchBlt(hdcWindow,
0, 0,
rcClient.right, rcClient.bottom,
hdcScreen,
0, 0,
GetSystemMetrics(SM_CXSCREEN),
GetSystemMetrics(SM_CYSCREEN),
SRCCOPY);
hbmScreen = CreateCompatibleBitmap(hdcWindow, rcClient.right - rcClient.left, rcClient.bottom
- rcClient.top);
SelectObject(hdcMemDC, hbmScreen);
BitBlt(hdcMemDC,
0, 0,
rcClient.right - rcClient.left, rcClient.bottom - rcClient.top,
hdcWindow,
0, 0,
SRCCOPY);
GetObject(hbmScreen, sizeof(BITMAP), &bmpScreen);
BITMAPINFOHEADER bi;
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;
GetDIBits(hdcWindow, hbmScreen, 0, bmpScreen.bmHeight, NULL, (BITMAPINFO*)&bi,
DIB_RGB_COLORS);
if (!bi.biSizeImage)
{
bi.biSizeImage = (((bi.biWidth*bi.biBitCount + 0x1F)&~0x1F) >> 3)*bi.biHeight;
}
lpbitmap = (char*)malloc(bi.biSizeImage);
GetDIBits(hdcWindow, hbmScreen, 0,
(UINT)bmpScreen.bmHeight,
lpbitmap,
(BITMAPINFO*)&bi, DIB_RGB_COLORS);
send(s, (char*)&bi, sizeof(bi), 0);
send(s, lpbitmap, bi.biSizeImage, 0);
free(lpbitmap);
DeleteObject(hbmScreen);
DeleteObject(hdcMemDC);
ReleaseDC(NULL, hdcScreen);
ReleaseDC(hWnd, hdcWindow);
return 0;
}
help me......
I can't solve this problem......

How to resize/rescale an image loaded into microsoft visual studio 2019 using the win32 library?

I have an image to load into my GUI, using the win32 library. It's too large and so the entire image does not get displayed.
Below is the code for the window and painting the image onto the window.
The target image is 1600 pixels wide and 1140 pixels tall.
LRESULT CALLBACK WndProc (HWND hWnd, UINT uMsg,
WPARAM wParam, LPARAM lParam)
{
HMENU hMenu;
OPENFILENAME ofn;
FILE *fpt;
HDC hDC;
char header[320],text[320];
int BYTES,xPos,yPos;
switch (uMsg)
{
case WM_COMMAND:
switch (LOWORD(wParam))
{
case ID_FILE_CLEARIMAGE:
//Clear image
PaintImage();
break;
case ID_FILE_LOAD:
if (OriginalImage != NULL || image_loaded == 1)
{
for (int i = 0; i < 1500; i++)
{
for (int j = 0; j < 1500; j++)
{
OriginalImage[i * COLS + j] = 255;
}
}
OriginalImage = NULL;
free(OriginalImage);
}
memset(&(ofn),0,sizeof(ofn));
ofn.lStructSize=sizeof(ofn);
ofn.lpstrFile=filename;
filename[0]=0;
ofn.nMaxFile=MAX_FILENAME_CHARS;
ofn.Flags=OFN_EXPLORER | OFN_HIDEREADONLY;
ofn.lpstrFilter = "PNM files\0*.pnm\0All files\0*.*\0\0";
if (!( GetOpenFileName(&ofn)) || filename[0] == '\0')
break; /* user cancelled load */
if ((fpt=fopen(filename,"rb")) == NULL)
{
MessageBox(NULL,"Unable to open file",filename,MB_OK | MB_APPLMODAL);
break;
}
fscanf(fpt,"%s\n%d %d\n%d",header,&COLS,&ROWS,&BYTES);
if (strcmp(header,"P6") != 0 || BYTES != 255)
{
MessageBox(NULL,"Not a PNM image",filename,MB_OK | MB_APPLMODAL);
fclose(fpt);
break;
}
OriginalImage=(unsigned char *)calloc(ROWS*COLS*3,1);
header[0]=fgetc(fpt); /* whitespace character after header */
fread(OriginalImage,1,ROWS*COLS*3,fpt);
for (int i = 0; i < ROWS; i++)
{
for (int j = 0; j < COLS; j++)
{
OriginalImage[i * COLS + j] = (int)(OriginalImage[i * (COLS * 3) + (j * 3)] +
OriginalImage[i * (COLS * 3) + (j * 3) + 1] +
OriginalImage[i * (COLS * 3) + (j * 3) + 2])/3.0;
}
}
image_loaded = 1;
fclose(fpt);
SetWindowText(hWnd,filename);
PaintImage();
break;
case ID_FILE_QUIT:
DestroyWindow(hWnd);
break;
}
break;
case WM_SIZE: /* could be used to detect when window size changes */
PaintImage();
return(DefWindowProc(hWnd,uMsg,wParam,lParam));
break;
case WM_PAINT:
PaintImage();
return(DefWindowProc(hWnd,uMsg,wParam,lParam));
break;
Below is the paint function
void PaintImage()
{
PAINTSTRUCT Painter;
HDC hDC;
BITMAPINFOHEADER bm_info_header;
BITMAPINFO *bm_info;
int i,r,c,DISPLAY_ROWS,DISPLAY_COLS;
unsigned char *DisplayImage;
HDC hdcScaled;
HBITMAP hbmScaled;
if (OriginalImage == NULL)
return; /* no image to draw */
/* Windows pads to 4-byte boundaries. We have to round the size up to 4 in each dimension, filling with black. */
DISPLAY_ROWS=ROWS;
DISPLAY_COLS=COLS;
if (DISPLAY_ROWS % 4 != 0)
DISPLAY_ROWS=(DISPLAY_ROWS/4+1)*4;
if (DISPLAY_COLS % 4 != 0)
DISPLAY_COLS=(DISPLAY_COLS/4+1)*4;
DisplayImage=(unsigned char *)calloc(DISPLAY_ROWS*DISPLAY_COLS,1);
for (r=0; r<ROWS; r++)
for (c=0; c<COLS; c++)
DisplayImage[r*DISPLAY_COLS+c] = OriginalImage[r*COLS+c];
BeginPaint(MainWnd,&Painter);
hDC=GetDC(MainWnd);
bm_info_header.biSize=sizeof(BITMAPINFOHEADER);
bm_info_header.biWidth=DISPLAY_COLS;
bm_info_header.biHeight=-DISPLAY_ROWS;
bm_info_header.biPlanes=1;
bm_info_header.biBitCount=8;
bm_info_header.biCompression=BI_RGB;
bm_info_header.biSizeImage=0;
bm_info_header.biXPelsPerMeter=0;
bm_info_header.biYPelsPerMeter=0;
bm_info_header.biClrUsed=256;
bm_info_header.biClrImportant=256;
bm_info=(BITMAPINFO *)calloc(1,sizeof(BITMAPINFO) + 256*sizeof(RGBQUAD));
bm_info->bmiHeader=bm_info_header;
for (i=0; i<256; i++)
{
bm_info->bmiColors[i].rgbBlue = bm_info->bmiColors[i].rgbGreen = bm_info->bmiColors[i].rgbRed = i;
bm_info->bmiColors[i].rgbReserved=0;
}
SetDIBitsToDevice(hDC,0,0,DISPLAY_COLS,DISPLAY_ROWS,0,0,
0, /* first scan line */
DISPLAY_ROWS, /* number of scan lines */
DisplayImage,bm_info,DIB_RGB_COLORS);
hdcScaled = CreateCompatibleDC(hDC);
hbmScaled = CreateCompatibleBitmap(hDC, GetDeviceCaps(hDC, HORZRES) * 0.5, GetDeviceCaps(hDC, VERTRES) * 0.5);
ReleaseDC(MainWnd,hDC);
EndPaint(MainWnd,&Painter);
free(DisplayImage);
free(bm_info);
}
The following is a link I found on resizing/rescaling images, but I don't understand how to implement it using my code.
C++ WIN32: Rescaling Bitmaps/Giving Bitmaps HDC's
Please advise.
The StretchBlt method is pointed out in the link.
Add the following code in PaintImage(),
void PaintImage()
{
for (i=0; i<256; i++)
{
bm_info->bmiColors[i].rgbBlue = bm_info->bmiColors[i].rgbGreen = bm_info->bmiColors[i].rgbRed = i;
bm_info->bmiColors[i].rgbReserved=0;
}
...
RECT rc;
GetClientRect(MainWnd, &rc);
hdcScaled = CreateCompatibleDC(hDC);
hbmScaled = CreateCompatibleBitmap(hDC, DISPLAY_COLS, DISPLAY_ROWS);
SelectObject(hdcScaled, hbmScaled);
SetDIBitsToDevice(hdcScaled, 0, 0, DISPLAY_COLS, DISPLAY_ROWS, 0, 0,
0, /* first scan line */
DISPLAY_ROWS, /* number of scan lines */
DisplayImage, bm_info, DIB_RGB_COLORS);
SetStretchBltMode(hDC, HALFTONE);
StretchBlt(hDC, 0, 0, rc.right - rc.left, rc.bottom - rc.top, hdcScaled, 0, 0, DISPLAY_COLS, DISPLAY_ROWS, SRCCOPY);
DeleteObject(hdcScaled);
DeleteObject(hbmScaled);
...
}
Note: Delete objects to avoid memory leaks
You could use the CAPI library. It has a very easy to use image stretch functions
capi_DrawImageEx
capi_DrawImageExA
Here is a simple example program that demonstrates stretching an image to fit into a window.
#include <Windows.h>
#include <CAPI.h>
#define WinClassName STR("ExampleProgram")
#define WinTitle STR("Example Program")
#ifdef UNICODE
#define app_fopen _wfopen_s
#define app_printf wprintf
#define ApplicationEntryPoint wWinMain
#else
#define app_fopen fopen_s
#define app_printf printf
#define ApplicationEntryPoint WinMain
#endif // UNICODE
static HWND Window_hWnd = 0;
static HDC BufferHDC = 0;
static BITMAPINFO* pDisplayBitmap = 0;
static HBITMAP hBitmap = 0;
static int ClientWidth;
static int ClientHeight;
static IMAGE FrameBuffer;
static IMAGE exampleImage;
void* LoadFile(const STRING* FilePath, U64* pFileSize)
{
FILE* Stream;
size_t BufferLength;
void* pThisFile;
void* pNewBlock;
if ((FilePath == 0) || (pFileSize == 0)) return 0;
*pFileSize = 0;
if (app_fopen(&Stream, FilePath, STR("rb")) != 0) return 0;
if (Stream == 0) return 0;
pThisFile = 0;
BufferLength = 0;
do
{
BufferLength += 0x1000;
pNewBlock = capi_realloc(pThisFile, BufferLength);
if (pNewBlock == 0)
{
if (pThisFile != 0) capi_free(pThisFile);
fclose(Stream);
return 0;
}
pThisFile = pNewBlock;
*pFileSize += fread(&((U8*)pThisFile)[*pFileSize], 1, 0x1000, Stream);
} while (!(feof(Stream)));
fclose(Stream);
return pThisFile;
}
I32 SaveFile(const STRING* FilePath, void* pFilePointer, U64 FileSize)
{
FILE* Stream;
size_t nBytesWrite;
I32 ErrorCode;
if ((FilePath == 0) || (pFilePointer == 0) || (FileSize == 0)) return CAPI_ERROR_INVALID_PARAMETER;
ErrorCode = CAPI_ERROR_NONE;
if (app_fopen(&Stream, FilePath, STR("w+b")) != 0) return CAPI_ERROR_ACCESS_DENIED;
if (Stream == 0) return CAPI_ERROR_ACCESS_DENIED;
nBytesWrite = fwrite(pFilePointer, 1, (size_t)FileSize, Stream);
if (nBytesWrite != FileSize)
{
ErrorCode = CAPI_ERROR_ACCESS_DENIED;
goto exit_func;
}
exit_func:
fclose(Stream);
return ErrorCode;
}
void FreeSysInternal()
{
if (BufferHDC != 0)
{
DeleteDC(BufferHDC);
BufferHDC = 0;
}
if (pDisplayBitmap != 0)
{
capi_free(pDisplayBitmap);
pDisplayBitmap = 0;
}
if (hBitmap != 0)
{
DeleteObject(hBitmap);
hBitmap = 0;
}
}
U32 SetupWindowFrameBuffer(HDC WindowHDC, RECT* ClientRt)
{
FreeSysInternal();
pDisplayBitmap = (BITMAPINFO*)capi_malloc(sizeof(BITMAPINFOHEADER));
if (pDisplayBitmap == 0) return 1;
pDisplayBitmap->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pDisplayBitmap->bmiHeader.biWidth = ClientRt->right;
pDisplayBitmap->bmiHeader.biHeight = -ClientRt->bottom;
pDisplayBitmap->bmiHeader.biPlanes = 1;
pDisplayBitmap->bmiHeader.biBitCount = 32;
pDisplayBitmap->bmiHeader.biCompression = 0;
pDisplayBitmap->bmiHeader.biSizeImage = 0;
pDisplayBitmap->bmiHeader.biXPelsPerMeter = 0;
pDisplayBitmap->bmiHeader.biYPelsPerMeter = 0;
pDisplayBitmap->bmiHeader.biClrUsed = 0;
pDisplayBitmap->bmiHeader.biClrImportant = 0;
BufferHDC = CreateCompatibleDC(WindowHDC);
if (BufferHDC == 0)
{
capi_free(pDisplayBitmap);
return 2;
}
hBitmap = CreateDIBSection(BufferHDC, pDisplayBitmap, 0,
(void**)&FrameBuffer.Pixels, 0, 0);
if (hBitmap == 0)
{
DeleteDC(BufferHDC);
capi_free(pDisplayBitmap);
return 3;
}
GdiFlush();
FrameBuffer.ScanLine = ClientRt->right;
FrameBuffer.Width = ClientRt->right;
FrameBuffer.Height = ClientRt->bottom;
SelectObject(BufferHDC, hBitmap);
return 0;
}
void Window_Paint_Handler(IMAGE* pDisplay)
{
// Fill the background of our window.
capi_FillImage(pDisplay, COLOR(195, 195, 195, 255));
// Now we stretch our test image to the size of the window.
// Note: The last parameter (Alpha) must be 255 for the image to be displayed normally.
capi_DrawImageExA(pDisplay, &exampleImage, 0, 0, DRAW_RESIZE_BOXSAMP, pDisplay->Width, pDisplay->Height, 255);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
HDC WinDC;
PAINTSTRUCT ps;
RECT WinArea;
RECT ClientArea;
int BorderWidth;
int BorderHeight;
switch (uMsg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_ERASEBKGND:
return TRUE;
case WM_PAINT:
{
WinDC = BeginPaint(hWnd, &ps);
GetClientRect(hWnd, &ClientArea);
if ((ClientArea.right == 0) || (ClientArea.bottom == 0)) goto exit_paint_message;
if ((ClientArea.right != FrameBuffer.Width) || (ClientArea.bottom != FrameBuffer.Height))
{
if (SetupWindowFrameBuffer(WinDC, &ClientArea) != 0) goto exit_paint_message;
}
Window_Paint_Handler(&FrameBuffer);
SetDIBits(BufferHDC, hBitmap, 0,
pDisplayBitmap->bmiHeader.biHeight, FrameBuffer.Pixels, pDisplayBitmap, 0);
BitBlt(WinDC, 0, 0, ClientArea.right, ClientArea.bottom, BufferHDC, 0, 0, 0x00CC0020);
exit_paint_message:
EndPaint(hWnd, &ps);
break;
}
case WM_CREATE:
{
Window_hWnd = hWnd;
GetWindowRect(hWnd, &WinArea);
GetClientRect(hWnd, &ClientArea);
BorderWidth = WinArea.right - ClientArea.right;
BorderHeight = WinArea.bottom - ClientArea.bottom;
SetWindowPos(hWnd, NULL,
0, 0,
BorderWidth + ClientWidth, BorderHeight + ClientHeight, SWP_NOMOVE | SWP_NOZORDER);
GetWindowRect(hWnd, &WinArea);
SetWindowPos(hWnd, NULL,
(GetSystemMetrics(SM_CXSCREEN) - (WinArea.right - WinArea.left)) / 2,
(GetSystemMetrics(SM_CYSCREEN) - (WinArea.bottom - WinArea.top)) / 2,
0, 0, SWP_NOSIZE | SWP_NOZORDER);
break;
}
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}
int WINAPI ApplicationEntryPoint(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ STRING* pCmdLine, _In_ int nCmdShow)
{
MSG msg;
WNDCLASSEX wcex;
void* myLoadedFile;
U64 FileSize;
I32 ErrorCode;
// Load our image to draw to the window frame buffer.
myLoadedFile = LoadFile(STR("C:/Users/Public/myTestImage.ico"), &FileSize);
if (myLoadedFile == 0)
{
MessageBox(0, STR("LoadFile Failed."), STR("Error!"), MB_OK);
return 0;
}
ErrorCode = capi_LoadImageFromMemory(&exampleImage, 1, myLoadedFile, FileSize);
if (ErrorCode != CAPI_ERROR_NONE)
{
MessageBox(0, STR("capi_LoadImageFromMemory Failed."), STR("Error!"), MB_OK);
return 0;
}
// The client area of our window will be the same size as our test image.
ClientWidth = exampleImage.Width;
ClientHeight = exampleImage.Height;
// Create the display window and enter the thread/window message loop.
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = NULL;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = WinClassName;
wcex.hIconSm = NULL;
if (!RegisterClassEx(&wcex))
{
MessageBox(0, STR("Failed to register the window class."), STR("Error!"), MB_OK);
return 0;
}
// Note: The 700 (Width) and 500 (Height) values are just dummy values. The Width and Height get set in the WM_CREATE message handler.
CreateWindowEx(0, WinClassName, WinTitle,
WS_VISIBLE | WS_CLIPCHILDREN | WS_BORDER | WS_MINIMIZEBOX | WS_SYSMENU | WS_SIZEBOX | WS_MAXIMIZEBOX,
0, 0, 700, 500, NULL, NULL, hInstance, NULL);
if (!Window_hWnd)
{
MessageBox(0, STR("Failed to create the window."), STR("Error!"), MB_OK);
return 0;
}
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
FreeSysInternal();
return 0;
}

Inserting text item into Listview without an associated icon

I have a simple list view which has an image list added to it. Displaying image items is fine, but when I just want one piece of text, no icon or image, one pure text item into my list view, the thing drops an image on me. I can't add any item without it having an icon/image next to it.
Here's the code
case WM_CREATE:{
HBITMAP hbmp_o, hbmp;
COLORREF crMask;
// listview view is LVS_ICON by default
hWndListView = CreateWindowEx(0, WC_LISTVIEW, TEXT("ListView1"), WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL, 0, 0, 400, 500, hwnd, NULL, GetModuleHandle(NULL), NULL);
hbmp_o = (HBITMAP)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_BITMAP3), IMAGE_BITMAP, 0, 0, 0);
BITMAP bm_o = { 0 };
GetObject(hbmp_o, sizeof(bm_o), &bm_o);
HDC dc_o = CreateCompatibleDC(NULL), dc = CreateCompatibleDC(NULL);
HBITMAP old_o = (HBITMAP)SelectObject(dc_o, hbmp_o);
unsigned char *Data;
BITMAPINFO BitmapInfo;
memset(&BitmapInfo.bmiHeader, 0, sizeof(BitmapInfo.bmiHeader));
BitmapInfo.bmiHeader.biWidth = lv_bmp_width;
BitmapInfo.bmiHeader.biHeight = lv_bmp_height;
BitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
BitmapInfo.bmiHeader.biPlanes = 1;
BitmapInfo.bmiHeader.biBitCount = 32;
BitmapInfo.bmiHeader.biCompression = BI_RGB;
hbmp = CreateDIBSection(dc_o, &BitmapInfo, DIB_RGB_COLORS, (void **)&Data, 0, 0);
HBITMAP old = (HBITMAP)SelectObject(dc, hbmp);
SetStretchBltMode(dc, HALFTONE);
StretchBlt(dc, 0, 0, lv_bmp_width, lv_bmp_height, dc_o, 0, 0, bm_o.bmWidth, bm_o.bmHeight, SRCCOPY);
SelectObject(dc_o, old_o);
hbmp = (HBITMAP)SelectObject(dc, old);
BITMAP bm = { 0 };
GetObject(hbmp, sizeof(bm), &bm);
hImageList_small = ImageList_Create(lv_bmp_width, lv_bmp_height, ILC_COLOR32 | ILC_MASK, 3, 0);
ImageList_Add(hImageList_small, hbmp, (HBITMAP)NULL);
ListView_SetImageList(hWndListView, hImageList_small, LVSIL_NORMAL);
LVITEM lv;
lv = { LVIF_IMAGE, itm_count, 0, 0, 0, NULL, 0, img_count, 0, 0, 0, 0, 0 };
ListView_InsertItem(hWndListView, &lv); img_count++; itm_count++;
hwndNextViewer = SetClipboardViewer(hwnd);
break;
}
/*********************************************************************************************/
case WM_DRAWCLIPBOARD:{
static UINT auPriorityList[] = {
CF_OWNERDISPLAY,
CF_TEXT,
CF_OEMTEXT,
CF_UNICODETEXT,
CF_ENHMETAFILE,
CF_BITMAP,
CF_DIB
};
if (!OpenClipboard(hwnd)) lasterror(L"Clipboard not opening");
UINT uformat = GetPriorityClipboardFormat(auPriorityList, 7);
HGLOBAL hnd;
LPWSTR wstr = NULL;
LPWSTR str = NULL;
switch (uformat)
{
case CF_OEMTEXT:
case CF_TEXT:
case CF_UNICODETEXT:{
if((hnd = GetClipboardData(CF_UNICODETEXT)) == NULL) lasterror(L"hbmp_o is NULL");
wstr = (LPWSTR)GlobalLock(hnd);
str = (LPWSTR)malloc(wcslen(wstr) * sizeof(WCHAR) + sizeof(WCHAR));
wcscpy(str, wstr);
GlobalUnlock(hnd);//GlobalFree(hnd); fuck global free. makes crash
CloseClipboard();
LVITEM lv;
lv = { LVIF_TEXT, itm_count++, 0, 0, 0, str, 0, 0, 0, 0, 0, 0, 0 };
int a = ListView_InsertItem(hWndListView, &lv); itm_count++;
free(str);
break;
}
//etc..
Aside from dropping the image list and custom drawing the bitmap into it, I have no solutions to this.

C Win32: save .bmp image from HBITMAP

I am working with a framegrabber and need to get the images from computer memory and save them on an image file. after trying for couple of days I end up with the following 2 functions, which creates a file and windows OS is able to run the .bmp file, but the bitmap file is black (the image size is 900KB , 640*480). does any body has any idea why, the picture is in black?
here are the two functions :
LPSTR CreateBMP( HWND hAppWnd, int nImageType )
{
void * pWinGBits = NULL;
int i;
Z_BITMAPINFO zWinGHeader; // bitmapinfo for cerating the DIB
// create DC for bitmap.
hDCBits = CreateCompatibleDC( ghDCMain );
switch ( nImageType )
{
case bayer_filter:
zWinGHeader.bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
zWinGHeader.bmiHeader.biPlanes = 1;
zWinGHeader.bmiHeader.biClrImportant = 0;
zWinGHeader.bmiHeader.biHeight = -lYSize;
zWinGHeader.bmiHeader.biWidth = lXSize;
zWinGHeader.bmiHeader.biBitCount = 32;
zWinGHeader.bmiHeader.biClrUsed = 0;//3;
zWinGHeader.bmiHeader.biCompression = BI_BITFIELDS;
zWinGHeader.bmiHeader.biSizeImage = 0;
zWinGHeader.bmiColors[0].rgbBlue = 0x00;
zWinGHeader.bmiColors[0].rgbGreen = 0x00;
zWinGHeader.bmiColors[0].rgbRed = 0xFF;
zWinGHeader.bmiColors[0].rgbReserved = 0x00;
zWinGHeader.bmiColors[1].rgbBlue = 0x00;
zWinGHeader.bmiColors[1].rgbGreen = 0xFF;
zWinGHeader.bmiColors[1].rgbRed = 0x00;
zWinGHeader.bmiColors[1].rgbReserved = 0x00;
zWinGHeader.bmiColors[2].rgbBlue = 0xFF;
zWinGHeader.bmiColors[2].rgbGreen = 0x00;
zWinGHeader.bmiColors[2].rgbRed = 0x00;
zWinGHeader.bmiColors[2].rgbReserved = 0x00;
break;
case color32:
zWinGHeader.bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
zWinGHeader.bmiHeader.biPlanes = 1;
zWinGHeader.bmiHeader.biClrImportant = 0;
zWinGHeader.bmiHeader.biHeight = -lYSize;
zWinGHeader.bmiHeader.biWidth = lXSize/4;
zWinGHeader.bmiHeader.biBitCount = 32;
zWinGHeader.bmiHeader.biClrUsed = 0;
zWinGHeader.bmiHeader.biCompression = BI_BITFIELDS;
zWinGHeader.bmiHeader.biSizeImage = 0;
zWinGHeader.bmiColors[0].rgbBlue = 0x00;
zWinGHeader.bmiColors[0].rgbGreen = 0x00;
zWinGHeader.bmiColors[0].rgbRed = 0xFF;
zWinGHeader.bmiColors[0].rgbReserved = 0x00;
zWinGHeader.bmiColors[1].rgbBlue = 0x00;
zWinGHeader.bmiColors[1].rgbGreen = 0xFF;
zWinGHeader.bmiColors[1].rgbRed = 0x00;
zWinGHeader.bmiColors[1].rgbReserved = 0x00;
zWinGHeader.bmiColors[2].rgbBlue = 0xFF;
zWinGHeader.bmiColors[2].rgbGreen = 0x00;
zWinGHeader.bmiColors[2].rgbRed = 0x00;
zWinGHeader.bmiColors[2].rgbReserved = 0x00;
break;
case color24:
zWinGHeader.bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
zWinGHeader.bmiHeader.biPlanes = 1;
zWinGHeader.bmiHeader.biClrImportant = 0;
zWinGHeader.bmiHeader.biHeight = -lYSize;
zWinGHeader.bmiHeader.biWidth = lXSize/3;
zWinGHeader.bmiHeader.biBitCount = 24;
zWinGHeader.bmiHeader.biClrUsed = 0;
zWinGHeader.bmiHeader.biCompression = BI_RGB;
zWinGHeader.bmiHeader.biSizeImage = 0;
break;
case color3x16:
zWinGHeader.bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
zWinGHeader.bmiHeader.biPlanes = 1;
zWinGHeader.bmiHeader.biClrImportant = 0;
zWinGHeader.bmiHeader.biHeight = -lYSize;
zWinGHeader.bmiHeader.biWidth = lXSize/6;
zWinGHeader.bmiHeader.biBitCount = 32;
zWinGHeader.bmiHeader.biClrUsed = 0;
zWinGHeader.bmiHeader.biCompression = BI_BITFIELDS;
zWinGHeader.bmiHeader.biSizeImage = 0;
zWinGHeader.bmiColors[0].rgbBlue = 0x00;
zWinGHeader.bmiColors[0].rgbGreen = 0x00;
zWinGHeader.bmiColors[0].rgbRed = 0xFF;
zWinGHeader.bmiColors[0].rgbReserved = 0x00;
zWinGHeader.bmiColors[1].rgbBlue = 0x00;
zWinGHeader.bmiColors[1].rgbGreen = 0xFF;
zWinGHeader.bmiColors[1].rgbRed = 0x00;
zWinGHeader.bmiColors[1].rgbReserved = 0x00;
zWinGHeader.bmiColors[2].rgbBlue = 0xFF;
zWinGHeader.bmiColors[2].rgbGreen = 0x00;
zWinGHeader.bmiColors[2].rgbRed = 0x00;
zWinGHeader.bmiColors[2].rgbReserved = 0x00;
break;
case bw1x10:
// create bitmap-infoheader.
zWinGHeader.bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
zWinGHeader.bmiHeader.biPlanes = 1;
zWinGHeader.bmiHeader.biBitCount = 8;
zWinGHeader.bmiHeader.biCompression = BI_RGB;
zWinGHeader.bmiHeader.biSizeImage = 0;
zWinGHeader.bmiHeader.biClrUsed = 256;
zWinGHeader.bmiHeader.biClrImportant= 0;
zWinGHeader.bmiHeader.biHeight = -lYSize;
zWinGHeader.bmiHeader.biWidth = lXSize/2;
// create colortable fot bitmap (grayvalues).
for (i = 0; i < 256; i++)
{
zWinGHeader.bmiColors[i].rgbGreen = i;
zWinGHeader.bmiColors[i].rgbBlue = i;
zWinGHeader.bmiColors[i].rgbRed = i;
zWinGHeader.bmiColors[i].rgbReserved = 0;
}
break;
default:
case bw8:
// create bitmap-infoheader.
zWinGHeader.bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
zWinGHeader.bmiHeader.biPlanes = 1;
zWinGHeader.bmiHeader.biBitCount = 8;
zWinGHeader.bmiHeader.biCompression = BI_RGB;
zWinGHeader.bmiHeader.biSizeImage = 0;
zWinGHeader.bmiHeader.biClrUsed = (1<<8);
zWinGHeader.bmiHeader.biClrImportant= 0;
zWinGHeader.bmiHeader.biHeight = -lYSize;
zWinGHeader.bmiHeader.biWidth = lXSize;
//zWinGHeader.bmiHeader.biSizeImage = ((zWinGHeader.bmiHeader.biWidth * 8 +31) & ~31) /8
// * zWinGHeader.bmiHeader.biHeight;
// create colortable fot bitmap (grayvalues).
for (i = 0; i < 256; i++)
{
zWinGHeader.bmiColors[i].rgbGreen = i;
zWinGHeader.bmiColors[i].rgbBlue = i;
zWinGHeader.bmiColors[i].rgbRed = i;
zWinGHeader.bmiColors[i].rgbReserved = 0;
}
break;
}
// cerate identity palette
hPal = CreateIdentityPalette( zWinGHeader.bmiColors );
// get new palette into DC and map into physical palette register.
hOldPal = SelectPalette( ghDCMain, hPal, FALSE);
RealizePalette( ghDCMain );
// cerate DIB-Section f黵 direct access of image-data.
hBitmap = CreateDIBSection(
hDCBits, // handle of device context
(BITMAPINFO *)&zWinGHeader, // address of structure containing
// bitmap size, format and color data
DIB_RGB_COLORS, // color data type indicator: RGB values
// or palette indices
&pWinGBits, // pointer to variable to receive a pointer
// to the bitmap's bit values
NULL, // optional handle to a file mapping object
0 // offset to the bitmap bit values within
// the file mapping object
);
// get bitmap into DC .
hOldBitmap = (HBITMAP)SelectObject( hDCBits, hBitmap );
return pWinGBits; // return pointer to DIB
}
and here is the function for saving into .bmp :
BOOL SaveToFile(HBITMAP hBitmap3, LPCTSTR lpszFileName)
{
HDC hDC;
int iBits;
WORD wBitCount;
DWORD dwPaletteSize=0, dwBmBitsSize=0, dwDIBSize=0, dwWritten=0;
BITMAP Bitmap0;
BITMAPFILEHEADER bmfHdr;
BITMAPINFOHEADER bi;
LPBITMAPINFOHEADER lpbi;
HANDLE fh, hDib, hPal,hOldPal2=NULL;
hDC = CreateDC("DISPLAY", NULL, NULL, NULL);
iBits = GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES);
DeleteDC(hDC);
if (iBits <= 1)
wBitCount = 1;
else if (iBits <= 4)
wBitCount = 4;
else if (iBits <= 8)
wBitCount = 8;
else
wBitCount = 24;
GetObject(hBitmap3, sizeof(Bitmap0), (LPSTR)&Bitmap0);
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = Bitmap0.bmWidth;
bi.biHeight =-Bitmap0.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = wBitCount;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrImportant = 0;
bi.biClrUsed = 256;
dwBmBitsSize = ((Bitmap0.bmWidth * wBitCount +31) & ~31) /8
* Bitmap0.bmHeight;
hDib = GlobalAlloc(GHND,dwBmBitsSize + dwPaletteSize + sizeof(BITMAPINFOHEADER));
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib);
*lpbi = bi;
hPal = GetStockObject(DEFAULT_PALETTE);
if (hPal)
{
hDC = GetDC(NULL);
hOldPal2 = SelectPalette(hDC, (HPALETTE)hPal, FALSE);
RealizePalette(hDC);
}
GetDIBits(hDC, hBitmap3, 0, (UINT) Bitmap0.bmHeight, (LPSTR)lpbi + sizeof(BITMAPINFOHEADER)
+dwPaletteSize, (BITMAPINFO *)lpbi, DIB_RGB_COLORS);
if (hOldPal2)
{
SelectPalette(hDC, (HPALETTE)hOldPal2, TRUE);
RealizePalette(hDC);
ReleaseDC(NULL, hDC);
}
fh = CreateFile(lpszFileName, GENERIC_WRITE,0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (fh == INVALID_HANDLE_VALUE)
return FALSE;
bmfHdr.bfType = 0x4D42; // "BM"
dwDIBSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwPaletteSize + dwBmBitsSize;
bmfHdr.bfSize = dwDIBSize;
bmfHdr.bfReserved1 = 0;
bmfHdr.bfReserved2 = 0;
bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER) + dwPaletteSize;
WriteFile(fh, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER), &dwWritten, NULL);
WriteFile(fh, (LPSTR)lpbi, dwDIBSize, &dwWritten, NULL);
GlobalUnlock(hDib);
GlobalFree(hDib);
CloseHandle(fh);
counter=1;
return TRUE;
}
I CAN Draw the images from memory perfectly with the following function, so for sure I dont have any problem for reading the image data :
void DrawPicture( HDC hDC, PBYTE pDest, PBYTE pSrc, LONG lXSize, LONG lYSize )
{
LONG lXSizeDiv, lYSizeDiv;
LONG lX, lY;
DWORD dwMax;
RECT rect;
HDC hdc;
PBYTE pTmpDest;
double fXFactor, fYFactor;
// HBRUSH hBrush;
// POINT Point;
switch( gzMvfgKamDef.iImageType )
{
case bayer_filter:
lXSizeDiv = 1;
lYSizeDiv = 1;
BayerToRGB( (PDWORD) pDest, pSrc, lXSize, lYSize,
gzMvfgKamDef.iBayerQuadrant, gzMvfgKamDef.iBayerQuality );
break;
case color24:
lXSizeDiv = 3;
lYSizeDiv = 1;
memcpy( pDest, pSrc, (size_t)( lXSize * lYSize ) );
break;
case color32:
lXSizeDiv = 4;
lYSizeDiv = 1;
memcpy( pDest, pSrc, (size_t)( lXSize * lYSize ) );
break;
case color3x16:
lXSizeDiv = 6;
lYSizeDiv = 1;
Conv3x16To3x8( pDest, pSrc, 4, lXSize, lYSize );
break;
case bw1x10:
lXSizeDiv = 2;
lYSizeDiv = 1;
Conv1x10To1x8( pDest, pSrc, 2, lXSize, lYSize );
break;
case bw6Tap:
lXSizeDiv = 1;
lYSizeDiv = 1;
Conv6TapTo1x8( pDest, pSrc, 1, lXSize, lYSize );
break;
default:
case bw8:
lXSizeDiv = 1;
lYSizeDiv = 1;
memcpy( pDest, pSrc, (size_t)( lXSize * lYSize ) );
break;
}
if( gahIniDlg[ NdxHistogramDlg ].hWnd )
{
memset( gadwHistogram, 0, sizeof( gadwHistogram) );
pTmpDest = pDest;
for ( lY = 0; lY < lYSize; lY++ )
{
for ( lX = 0; lX < lXSize; lX++ )
{
gadwHistogram[ *pTmpDest ]++;
pTmpDest++;
}
}
GetClientRect ( gahIniDlg[ NdxHistogramDlg ].hWnd, &rect) ;
hdc = GetDC ( gahIniDlg[ NdxHistogramDlg ].hWnd );
dwMax = 0;
for ( lX = 0 ; lX <= 0xff; lX++ )
dwMax = ( gadwHistogram[ lX ] > dwMax ) ? gadwHistogram[ lX ] : dwMax;
fYFactor = (double) dwMax / (double) rect.bottom;
fXFactor = (double) ( rect.right - 100 ) / (double) 0x100;
/*
SelectObject (hdc, GetStockObject (BLACK_PEN)) ;
for( lX = 0; lX <= 0xff; lX+=8 )
{
MoveToEx( hdc, lX * fXFactor, rect.bottom, &Point );
LineTo( hdc, lX * fXFactor, rect.bottom-10 );
}
*/
SelectObject (hdc, GetStockObject (WHITE_PEN)) ;
// hBrush = CreateSolidBrush( GetSysColor( COLOR_WINDOW ));
// hBrush = CreateSolidBrush( 0xffffff );
// SelectObject (hdc, hBrush);
Polyline( hdc, gaHistogram, 0x100 );
// DeleteObject( hBrush );
for ( lX = 0 ; lX <= 0xff; lX++ )
{
gaHistogram[ lX ].x = (DWORD)( fXFactor * (double)lX );
gaHistogram[ lX ].y = rect.bottom - (DWORD)( (double) gadwHistogram[ lX ] / fYFactor );
}
SelectObject (hdc, GetStockObject (BLACK_PEN)) ;
Polyline( hdc, gaHistogram, 0x100 );
ReleaseDC ( gahIniDlg[ NdxHistogramDlg ].hWnd , hdc ) ;
}
// display the bitmap
StretchBlt( hDC, rcWin.left, rcWin.top, lXSize / lXSizeDiv, lYSize / lYSizeDiv,
hDCBits, 0, 0, lXSize / lXSizeDiv, lYSize / lYSizeDiv, SRCCOPY );
//BitBlt( hDC, rcWin.left, rcWin.top, lXSize / lXSizeDiv, lYSize / lYSizeDiv,
//hDCBits, 0, 0, SRCCOPY );
}
I just find out I had a silly mistake in another part of my code I was using :
// Convert Image to bitmap and display it
DrawPicture( ghDCMain, pWinGBitmap, gpbImageData, lXSize, lYSize );
if(counter!=1) {
hBitmap2 = CreateCompatibleBitmap (hDCBits, lXSize, lYSize);
SaveToFile(hBitmap2, "c:\\t.bmp");
OutputDebugString("tested !!!!");
}
by deleting the hBitmap2 = CreateCompatibleBitmap (hDCBits, lXSize, lYSize); line, and changing the hBitmap2 to hBitmap the result of CreateDIBSection(), it saved the image beautifully. THANK YOU EVERYONE FOR YOUR HELP.
FORMAT_INFO sFormat;
mvfg_getparam( MVFGPAR_DATAFORMAT, &sFormat, giCurrentGrabberID);
long lFrameSize = sFormat.lFrameSize;
BYTE *pBitmap = (BYTE*)malloc(FrameSize);
memcpy( pBitmap, CamGetPicture(), FrameSize );
writeBitmapToFile(pBitmap, FrameSize, "tmp.bmp");
/*
* write our raw data into a bitmap file
* adding the correct header and put it all
* together in a single file
*/
int
writeBitmapToFile(void *data, unsigned long size, const char *filename)
{
bmpFileHeader_t header;
bmpInfoHeader_t info;
bmpRGBQuad_t rgb = { 0, 0, 0, 0};
FILE *out;
size_t len;
int i;
header.type = 0x4d42; // magic sequence 'BM'
header.size = 0;
header.res0 = 0;
header.res1 = 0;
/* 256 different colors, each is defined by an bmpRBQuad type */
header.offset = 256 * sizeof(bmpRGBQuad_t) +
sizeof(bmpInfoHeader_t) + sizeof(bmpFileHeader_t);
info.size = sizeof(bmpInfoHeader_t);
info.width = WIDTH;
info.height = HEIGHT;
info.planes = 1;
info.cDepth = 8; /* 8 Bit */
info.compression = 0;
info.rawSize = size;
info.hRes = 0;
info.vRes = 0;
info.nrColors = 0x100;
info.impColors = 0;
out = fopen(filename, "wb");
if (out == NULL) {
printf("error cannot open %s for writing\n", filename);
return -1;
}
len = fwrite(&header, 1, sizeof(header), out);
if (len != sizeof(header)) {
printf("error while writing header\n");
return -1;
}
len = fwrite(&info, 1, sizeof(info), out);
if (len != sizeof(info)) {
printf("error while writing info header\n");
return -1;
}
/* stupid try and error programming leads to this */
for (i = 0; i < 256; i++) {
rgb.red = i;
rgb.green = i;
rgb.blue = i;
len = fwrite(&rgb, 1, sizeof(rgb), out);
if (len != sizeof(rgb)) {
printf("error while writing rgb header\n");
return -1;
}
}
len = fwrite(data, 1, size, out);
if (len != size ) {
printf("error while writing bitmap data\n");
return -1;
}
return 0;
}
Reference - mikrotron
Reference - write bitmap
Are you sure there is proper data in there?
I would try extract the RGB data and save it in some very simple format "manually", just to see what is in there. If you are looking for a dead simple but still standard image format, look at PPM images.
From the documentation for CreateCompatibleDC:
When the memory DC is created, its display surface is exactly one monochrome pixel wide and one monochrome pixel high. Before an application can use a memory DC for drawing operations, it must select a bitmap of the correct width and height into the DC.
Since you're using CreateDIBSection with that DC, the resulting DIB section will be 1-bit monochrome as well.

Resources