-
Processing Bitmap Data
hello, I have made a function that loops through a bitmap, converts each pixel to a HLS value, alters the values, then converts back to RGB, then sets the new pixel value.
Here is some rough test code I'm using at the moment:
Code:
#pragma comment(lib, "shlwapi.lib")
#include <windows.h>
#include "shlwapi.h"
HBITMAP dBitmap;
void ColorizeBitmap(HWND hwnd)
{
BITMAP bitty;
GetObject(dBitmap,sizeof(BITMAP),&bitty);
HDC hdc = GetDC(hwnd);
HDC BitDC = CreateCompatibleDC(hdc);
HBITMAP oldBitmap = (HBITMAP)SelectObject(BitDC,dBitmap);
COLORREF col;
WORD hue,light,sat;
int CurBXpos = 0, CurBYpos = 0;
while(CurBYpos < bitty.bmHeight)
{
while(CurBXpos < bitty.bmWidth)
{
col = GetPixel(BitDC,CurBXpos,CurBYpos);
ColorRGBToHLS(col,&hue,&light,&sat);
hue= 0; //makes it red-ish
sat = 200;
col = ColorHLSToRGB(hue,light,sat);
SetPixel(BitDC,CurBXpos,CurBYpos,col);
CurBXpos++;
}
if(CurBXpos == bitty.bmWidth)
CurBXpos = 0;
CurBYpos++;
}
SelectObject(BitDC,oldBitmap);
DeleteDC(BitDC);
ReleaseDC(hwnd,hdc);
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_PAINT:
{
PAINTSTRUCT ps;
BeginPaint(hwnd,&ps);
HDC BitDC = CreateCompatibleDC(ps.hdc);
HBITMAP oldState = (HBITMAP)SelectObject(BitDC,dBitmap);
BitBlt(ps.hdc,0,0,200,200,BitDC,0,0,SRCCOPY);
SelectObject(BitDC,oldState);
EndPaint(hwnd,&ps);
return 0;
}
case WM_CLOSE:
DestroyWindow(hwnd); break;
case WM_DESTROY:
PostQuitMessage(0); break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
HWND hwnd;
MSG Msg;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = "WindowCls";
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if(!RegisterClassEx(&wc))
{
MessageBox(NULL, "Window Registration Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
"WindowCls",
"Window",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 400, 400,
NULL, NULL, hInstance, NULL);
if(hwnd == NULL)
{
MessageBox(NULL, "Window Creation Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
dBitmap = (HBITMAP)LoadImage(0,"Bitmap.bmp",IMAGE_BITMAP,0,0,LR_LOADFROMFILE|LR_DEFAULTSIZE);
ColorizeBitmap(hwnd);
InvalidateRect(hwnd,0,true);
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
DeleteObject(dBitmap);
return Msg.wParam;
}
now, although this code 'works' it doesn't work very good. the conversion is quite slow (relatively speaking of course). so, my question to you is, is there any way to make it faster? if there is, would you please explain how.
thanks guys
-
SetPixel is slow - for better performance you should get a hold of the image bits themselves, change them and then blit the image once you've made whatever changes you're going to. Check out GetDIBits - search the boards as I'm fairly certain there are examples of its use to be found here.
-
I'm having trouble finding an example that works or even understand.
here is what I have so far:
Code:
void ColorizeBitmap(HWND hwnd, WORD Hue, WORD Saturation)
{
BITMAP bitty;
GetObject(dBitmap,sizeof(BITMAP),&bitty);
BITMAPINFO info;
BITMAPINFOHEADER header;
header.biSize = sizeof(BITMAPINFOHEADER);
header.biWidth = bitty.bmWidth;
header.biHeight = bitty.bmHeight;
header.biPlanes = bitty.bmPlanes;
header.biBitCount = 8;
header.biCompression = BI_RGB;
header.biSizeImage = 0;
header.biClrUsed = 0;
header.biClrImportant = 0;
info.bmiHeader = header;
info.bmiColors->rgbRed = NULL;
info.bmiColors->rgbGreen = NULL;
info.bmiColors->rgbBlue = NULL;
info.bmiColors->rgbReserved = NULL;
unsigned char * data = new unsigned char[bitty.bmWidth * bitty.bmHeight];
HDC hdc = GetDC(hwnd);
HDC BitDC = CreateCompatibleDC(hdc);
GetDIBits(hdc, dBitmap, 0, bitty.bmHeight, &data, &info, DIB_RGB_COLORS);
DeleteDC(BitDC);
ReleaseDC(hwnd,hdc);
delete[] data;
}
I don't know where to go from here. The first parameter of GetDIBits() is a device context, what is this for? is the supposed to have my HBITMAP selected into it?
I'm having a real hard time, please, I would be ever so greatful if you would help me out.
-
It is easier to retrieve a 32bpp bitmap so as to avoid dealing with alignment padding or the bmiColors array. You're also incorrectly using the addressof (&) operator on the buffer you are passing to GetDIBits.
Here is a set of functions to retrieve and set pixel data in 32bpp format:
Code:
/*
* Helper function that fills out a pbmi struct for a 32bpp bitmap.
*/
static BOOL CompleteBitmapInfo(HBITMAP hBmp, BITMAPINFO* pbmi)
{
BITMAP bmo;
if (GetObject(hBmp, sizeof(BITMAP), &bmo))
{
ZeroMemory(pbmi, sizeof(BITMAPINFO));
pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pbmi->bmiHeader.biWidth = bmo.bmWidth;
pbmi->bmiHeader.biHeight = -bmo.bmHeight;
pbmi->bmiHeader.biPlanes = 1;
pbmi->bmiHeader.biBitCount = 32; /* Request a 32bpp bitmap. */
pbmi->bmiHeader.biCompression = BI_RGB;
return TRUE;
}
return FALSE;
}
/*
* Returns a buffer containing the pixels of a bitmap in 32bpp format.
*
* Parameters:
* hBmp The source bitmap.
* hdc A matching device context. Typically a device
* context from a window or the screen.
*
* Returns:
* A pointer to a buffer containing the pixel data or NULL on failure.
* A pixel can be indexed with the following syntax: pixels[(y * width) + x]
* The buffer should be released with free when no longer needed.
*/
PDWORD GetBitmapPixels(HBITMAP hBmp, HDC hdc)
{
BITMAPINFO bmi;
PDWORD pixels = NULL;
if (CompleteBitmapInfo(hBmp, &bmi))
{
pixels = (PDWORD) malloc(-bmi.bmiHeader.biHeight * bmi.bmiHeader.biWidth * sizeof(DWORD));
if (pixels)
{
if (GetDIBits(hdc, hBmp, 0, -bmi.bmiHeader.biHeight, pixels, &bmi, DIB_RGB_COLORS))
{
return pixels;
}
}
}
free(pixels);
return NULL;
}
/*
* Set the pixels of a bitmap in 32bpp format.
*
* Parameters:
* hBmp The target bitmap.
* hdc A matching device context. Typically a device
* context from a window or the screen.
* pixels Pointer to a buffer containing the pixel data. The pixel data
* must be in 32bpp and match the dimensions of the bitmap. Pixel data is
* typically returned by GetBitmapPixels, modified and then copied back to
* the bitmap with SetBitmapPixels.
*
* Returns:
* A non-zero value on success. FALSE on failure.
*/
BOOL SetBitmapPixels(HBITMAP hBmp, HDC hdc, PDWORD pixels)
{
BITMAPINFO bmi;
if (CompleteBitmapInfo(hBmp, &bmi))
{
if (SetDIBits(hdc, hBmp, 0, -bmi.bmiHeader.biHeight, pixels, &bmi, DIB_RGB_COLORS))
{
return TRUE;
}
}
return FALSE;
}
And here is an example of how you would use them in your function:
Code:
void ColorizeBitmap(HWND hwnd)
{
HDC hdc = GetDC(hwnd);
PDWORD pixels = NULL;
int CurBXpos = 0;
int CurBYpos = 0;
BITMAP bmp;
COLORREF col;
pixels = GetBitmapPixels(hdc, dBitmap);
GetObject(dBitmap, sizeof(BITMAP), &bmp);
while (CurBYpos < bmp.bmHeight)
{
while (CurBXpos < bmp.bmWidth)
{
col = pixels[(CurBYpos * bmp.bmWidth) + CurBXpos];
/* Do stuff here. */
CurBXpos++;
}
CurBYpos++;
}
SetBitmapPixels(hdc, dBitmap, pixels);
free(pixels);
ReleaseDC(hwnd, hdc);
}
-
I connot tell you how much that helped me, thanks a lot man.