Thread: drawing on bitmaps

  1. #1
    Registered User eth0's Avatar
    Join Date
    Dec 2003
    Posts
    164

    drawing on bitmaps

    Hi all.

    I’ve been reading Petzold about DIB’s and been playing about with some ideas. One problem I’m having trouble with at the moment is drawing on the same bitmap where an image has been loaded.

    The code below (mostly pulled in from various parts of Petzolds book) loads a bitmap using a DIB section. Drawing on top of this bitmap with the cursor and then resizing the screen results in the sketch being erased on a repaint.

    How do I draw directly onto the memory set aside via the DIB section?

    Code:
    #include <windows.h>
    
    #define IDM_FILE_OPEN 40001
    
    LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
    
    TCHAR szAppName[] = TEXT ("DibSect") ;
    
    int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                        PSTR szCmdLine, int iCmdShow)
    {
         HWND     hwnd ;
         MSG      msg ;
         WNDCLASS wndclass ;
         wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
         wndclass.lpfnWndProc   = WndProc ;
         wndclass.cbClsExtra    = 0 ;
         wndclass.cbWndExtra    = 0 ;
         wndclass.hInstance     = hInstance ;
         wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
         wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
         wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
         wndclass.lpszMenuName  = szAppName ;
         wndclass.lpszClassName = szAppName ;
    
         if (!RegisterClass (&wndclass))
         {
              MessageBox (NULL, TEXT ("This program requires Windows NT!"),
                          szAppName, MB_ICONERROR) ;
              return 0 ;
         }
    
         hwnd = CreateWindow (szAppName, TEXT ("DIB Section Display"),
                              WS_OVERLAPPEDWINDOW,
                              CW_USEDEFAULT, CW_USEDEFAULT,
                              CW_USEDEFAULT, CW_USEDEFAULT,
                              NULL, NULL, hInstance, NULL) ;
    
         ShowWindow (hwnd, iCmdShow) ;
         UpdateWindow (hwnd) ;
    
         while (GetMessage (&msg, NULL, 0, 0))
         {
              TranslateMessage (&msg) ;
              DispatchMessage (&msg) ;
    
         }
         return msg.wParam ;
    }
    HBITMAP CreateDibSectionFromDibFile (PTSTR szFileName)
    {
         BITMAPFILEHEADER bmfh ;
         BITMAPINFO     * pbmi ;
         BYTE           * pBits ;
         BOOL             bSuccess ;
         DWORD            dwInfoSize, dwBytesRead ;
         HANDLE           hFile ;
         HBITMAP          hBitmap = NULL;
              // Open the file: read access, prohibit write access
    
         hFile = CreateFile (szFileName, GENERIC_READ, FILE_SHARE_READ,
                             NULL, OPEN_EXISTING, 0, NULL) ;
    
         if (hFile == INVALID_HANDLE_VALUE)
              return NULL ;
    
              // Read in the BITMAPFILEHEADER
    
         bSuccess = ReadFile (hFile, &bmfh, sizeof (BITMAPFILEHEADER),
                              &dwBytesRead, NULL) ;
    
         if (!bSuccess || (dwBytesRead != sizeof (BITMAPFILEHEADER))
                       || (bmfh.bfType != * (WORD *) "BM"))
         {
              CloseHandle (hFile) ;
              return NULL ;
         }
    
              // Allocate memory for the BITMAPINFO structure & read it in
    
         dwInfoSize = bmfh.bfOffBits - sizeof (BITMAPFILEHEADER) ;
    
         pbmi = malloc (dwInfoSize) ;
    
         bSuccess = ReadFile (hFile, pbmi, dwInfoSize, &dwBytesRead, NULL) ;
    
         if (!bSuccess || (dwBytesRead != dwInfoSize))
         {
              free (pbmi) ;
              CloseHandle (hFile) ;
              return NULL ;
         }
              // Create the DIB Section
    
         hBitmap = CreateDIBSection (NULL, pbmi, DIB_RGB_COLORS, (VOID *)&pBits, NULL, 0) ;
    
         if (hBitmap == NULL)
         {
              free (pbmi) ;
              CloseHandle (hFile) ;
              return NULL ;
         }
    
              // Read in the bitmap bits
    
         ReadFile (hFile, pBits, bmfh.bfSize - bmfh.bfOffBits, &dwBytesRead, NULL) ;
    
         free (pbmi) ;
         CloseHandle (hFile) ;
    
         return hBitmap ;
    }
    
    LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
         static HBITMAP      hBitmap;
         static BOOL         fLeftButtonDown, fRightButtonDown ;
         static int          cxClient, cyClient, xMouse, yMouse ;
         static OPENFILENAME ofn ;
         static TCHAR        szFileName [MAX_PATH], szTitleName [MAX_PATH] ;
         static TCHAR        szFilter[] = TEXT ("Bitmap Files (*.BMP)\0*.bmp\0")
                                          TEXT ("All Files (*.*)\0*.*\0\0") ;
         BITMAP              bitmap ;
         HDC                 hdc, hdcMem ;
         PAINTSTRUCT         ps ;
    
         switch (message)
         {
         case WM_CREATE:
              ZeroMemory(&ofn, sizeof(OPENFILENAME));
              ofn.lStructSize       = sizeof (OPENFILENAME) ;
              ofn.hwndOwner         = hwnd ;
              ofn.lpstrFilter       = szFilter ;
              ofn.lpstrFile         = szFileName ;
              ofn.nMaxFile          = MAX_PATH ;
              ofn.lpstrFileTitle    = szTitleName ;
              ofn.nMaxFileTitle     = MAX_PATH ;
              ofn.lpstrDefExt       = TEXT ("bmp") ;
    
              return 0 ;
    
         case WM_SIZE:
              cxClient = LOWORD (lParam) ;
              cyClient = HIWORD (lParam) ;
              return 0 ;
    
         case WM_COMMAND:
              switch (LOWORD (wParam))
              {
              case IDM_FILE_OPEN:
    
                        // Show the File Open dialog box
    
                   if (!GetOpenFileName (&ofn))
                        return 0 ;
    
                        // If there's an existing bitmap, delete it
    
                   if (hBitmap)
                   {
                        DeleteObject (hBitmap);
                        hBitmap = NULL ;
                   }
                        // Create the DIB Section from the DIB file
    
                   SetCursor (LoadCursor (NULL, IDC_WAIT)) ;
                   ShowCursor (TRUE) ;
    
                   hBitmap = CreateDibSectionFromDibFile (szFileName) ;
                   ShowCursor (FALSE) ;
                   SetCursor (LoadCursor (NULL, IDC_ARROW)) ;
    
                        // Invalidate the client area for later update
    
                   InvalidateRect (hwnd, NULL, TRUE) ;
    
                   if (hBitmap == NULL)
                   {
                        MessageBox (hwnd, TEXT ("Cannot load DIB file"),
                                    szAppName, MB_OK | MB_ICONEXCLAMATION) ;
                   }
                   return 0 ;
              }
              break ;
    
        case WM_LBUTTONDOWN:
              if (!fRightButtonDown)
                   SetCapture (hwnd) ;
    
              xMouse = LOWORD (lParam) ;
              yMouse = HIWORD (lParam) ;
              fLeftButtonDown = TRUE ;
              return 0 ;
    
         case WM_LBUTTONUP:
              if (fLeftButtonDown)
                   SetCapture (NULL) ;
    
              fLeftButtonDown = FALSE ;
              return 0 ;
    
         case WM_RBUTTONDOWN:
              if (!fLeftButtonDown)
                   SetCapture (hwnd) ;
    
              xMouse = LOWORD (lParam) ;
              yMouse = HIWORD (lParam) ;
              fRightButtonDown = TRUE ;
              return 0 ;
    
         case WM_RBUTTONUP:
              if (fRightButtonDown)
                   SetCapture (NULL) ;
    
              fRightButtonDown = FALSE ;
              return 0 ;
    
         case WM_MOUSEMOVE:
              if (!fLeftButtonDown && !fRightButtonDown)
                   return 0 ;
    
              hdc = GetDC (hwnd) ;
    
              SelectObject (hdcMem, hBitmap);
              SelectObject (hdc, hBitmap);
    
              SelectObject (hdc,
                   GetStockObject (fLeftButtonDown ? BLACK_PEN : WHITE_PEN)) ;
    
              SelectObject (hdcMem,
                   GetStockObject (fLeftButtonDown ? BLACK_PEN : WHITE_PEN)) ;
    
              MoveToEx (hdc,    xMouse, yMouse, NULL) ;
              MoveToEx (hdcMem, xMouse, yMouse, NULL) ;
    
              xMouse = (short) LOWORD (lParam) ;
              yMouse = (short) HIWORD (lParam) ;
    
              LineTo (hdc,    xMouse, yMouse) ;
              LineTo (hdcMem, xMouse, yMouse) ;
    
              ReleaseDC (hwnd, hdc) ;
              return 0 ;
    
         case WM_PAINT:
              hdc = BeginPaint (hwnd, &ps) ;
    
              if (hBitmap)
              {
                   GetObject (hBitmap, sizeof (BITMAP), &bitmap) ;
    
                   hdcMem = CreateCompatibleDC (hdc) ;
                   SelectObject (hdcMem, hBitmap) ;
    
                   BitBlt (hdc,    0, 0, bitmap.bmWidth, bitmap.bmHeight,
                           hdcMem, 0, 0, SRCCOPY) ;
    
                   DeleteDC (hdcMem) ;
              }
    
              EndPaint (hwnd, &ps) ;
              return 0 ;
    
         case WM_DESTROY:
              if (hBitmap)
                   DeleteObject (hBitmap) ;
    
              PostQuitMessage (0) ;
              return 0 ;
         }
         return DefWindowProc (hwnd, message, wParam, lParam) ;
    }
    Code:
    #define IDM_FILE_OPEN 40001
    
    DIBSECT MENU DISCARDABLE
    BEGIN
        POPUP "&File"
        BEGIN
            MENUITEM "&Open", IDM_FILE_OPEN
        END
    END
    Open source isn't a matter of life or death......
    .......its much more important than that!!


    SuSE Linux - GCC 3.4.2
    XP Pro - Visual Studio 2005 TS, MinGW 3.4.2

  2. #2
    Registered /usr
    Join Date
    Aug 2001
    Location
    Newport, South Wales, UK
    Posts
    1,273
    The first thing you've got to understand is that you can't select the same bitmap into more than one DC. Selecting into your memory DC and then the window's DC means that it's not in the memory DC anymore.

    Also, you should create your memory DC once, in your WM_CREATE handler, then delete it in WM_DESTROY (like your bitmap there). Forget about using GetObject to grab your bitmap's dimensions in WM_PAINT, they're not important. Instead use the update rectangle provided for you in PAINTSTRUCT by BeginPaint:-
    Code:
    BitBlt (ps.hdc, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left,
    ps.rcPaint.bottom - ps.rcPaint.top, hdcMem, ps.rcPaint.left, ps.rcPaint.top, SRCCOPY) ;
    You don't need to select the bitmap into the window DC in your WM_MOUSEMOVE handler, it'll already be visible thanks to WM_PAINT. All you want it to do is draw your lines, by doing them to hdcMem at the same time with your bitmap selected, the changes will be "saved".

    P.S. Make sure that you keep the handle returned by SelectObject when you first select your bitmap into your memory DC! A 1x1 bitmap is created for every DC you created, select it back into the DC before you delete it to prevent memory leakage!
    Last edited by SMurf; 03-23-2006 at 11:29 AM.

  3. #3
    Registered User eth0's Avatar
    Join Date
    Dec 2003
    Posts
    164
    Thanks for the clarification, all is working now
    Open source isn't a matter of life or death......
    .......its much more important than that!!


    SuSE Linux - GCC 3.4.2
    XP Pro - Visual Studio 2005 TS, MinGW 3.4.2

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Drawing HBITMAP into CWnd, Acquired from "screenshot"
    By DeusAduro in forum Windows Programming
    Replies: 6
    Last Post: 07-02-2009, 03:41 PM
  2. Drawing bitmaps efficiently
    By scwizzo in forum Windows Programming
    Replies: 28
    Last Post: 06-30-2009, 08:25 PM
  3. DX9 Not Displaying Bitmaps
    By Sentral in forum Game Programming
    Replies: 9
    Last Post: 01-31-2006, 05:35 AM
  4. Interesting problem with bmp drawing
    By Victor in forum C++ Programming
    Replies: 3
    Last Post: 04-12-2005, 10:39 AM
  5. Drawing Bitmaps
    By filler_bunny in forum Windows Programming
    Replies: 6
    Last Post: 05-05-2004, 04:32 PM