Thread: Processing Bitmap Data

  1. #1
    Registered User
    Join Date
    Jul 2004
    Posts
    24

    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

  2. #2
    erstwhile
    Join Date
    Jan 2002
    Posts
    2,227
    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.
    CProgramming FAQ
    Caution: this person may be a carrier of the misinformation virus.

  3. #3
    Registered User
    Join Date
    Jul 2004
    Posts
    24
    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.

  4. #4
    Yes, my avatar is stolen anonytmouse's Avatar
    Join Date
    Dec 2002
    Posts
    2,544
    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);
    }

  5. #5
    Registered User
    Join Date
    Jul 2004
    Posts
    24
    I connot tell you how much that helped me, thanks a lot man.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Bitmasking Problem
    By mike_g in forum C++ Programming
    Replies: 13
    Last Post: 11-08-2007, 12:24 AM
  2. singly linked circular list
    By DarkDot in forum C++ Programming
    Replies: 0
    Last Post: 04-24-2007, 08:55 PM
  3. simultaneously waiting for data on FIFO and UDP using select call
    By yogesh3073 in forum Networking/Device Communication
    Replies: 2
    Last Post: 01-05-2007, 09:53 AM
  4. OpenGL -- Bitmaps
    By HQSneaker in forum Game Programming
    Replies: 14
    Last Post: 09-06-2004, 04:04 PM
  5. bitmap not going onto screen
    By stallion in forum Windows Programming
    Replies: 4
    Last Post: 02-22-2003, 10:07 AM