Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Desktop Calendar

0.00/5 (No votes)
4 Mar 2004 1  
A nice desktop calendar that sits on your desktop.

Sample Image - Desktop_Calendar.jpg

Introduction

This article describes a simple calendar that sits on your desktop. I have created this application to just study about alpha blending, desktop wallpapers, and how a device context can be saved as a bitmap. I am planning to make a more refined version including a time scheduler and reminder also.

Using the code

Alpha Blending

HBITMAP Create24BPPDIBSection(HDC hDC, int iWidth, int iHeight)
{
    BITMAPINFO bmi;
    HBITMAP hbm;
    LPBYTE pBits;

    // Initialize header to 0s.

    ZeroMemory(&bmi, sizeof(bmi));

    // Fill out the fields you care about.

    bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bmi.bmiHeader.biWidth = iWidth;
    bmi.bmiHeader.biHeight = iHeight;
    bmi.bmiHeader.biPlanes = 1;
    bmi.bmiHeader.biBitCount = 24;
    bmi.bmiHeader.biCompression = BI_RGB;

    // Create the surface.

    hbm = CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS,(void **)&pBits, NULL, 0);
      
    return(hbm);
}

BOOL BitmapsCompatible(LPBITMAP lpbm1, LPBITMAP lpbm2)
{
    if (lpbm1->bmBitsPixel != lpbm2->bmBitsPixel) 
        return FALSE;
    if (lpbm1->bmPlanes    != lpbm2->bmPlanes)    
        return FALSE;
    if (lpbm1->bmWidth     != lpbm2->bmWidth)     
        return FALSE;
    if (lpbm1->bmHeight    != lpbm2->bmHeight)    
        return FALSE;
    return TRUE;
}

BOOL BlendImages(HBITMAP hbmSrc1, HBITMAP hbmSrc2, HBITMAP hbmDst, DWORD dwWeight1)
{
    BITMAP bmSrc1, bmSrc2, bmDst;
    RGBTRIPLE *lprgbSrc1, *lprgbSrc2, *lprgbDst;
    DWORD dwWidthBytes, dwWeight2;
    int x, y;
    
    // Only values between 0 and 255 are valid.

    if (dwWeight1 > 255) return FALSE;
    
    // Get weighting value for second source image.

    dwWeight2 = 255-dwWeight1;
    
    // Get information about the surfaces you were passed.

    if (!GetObject(hbmSrc1, sizeof(BITMAP), &bmSrc1)) return FALSE;
    if (!GetObject(hbmSrc2, sizeof(BITMAP), &bmSrc2)) return FALSE;
    if (!GetObject(hbmDst,  sizeof(BITMAP), &bmDst))  return FALSE;

    // Make sure you have data that meets your requirements.

    if (!BitmapsCompatible(&bmSrc1, &bmSrc2))
        return FALSE;
    if (!BitmapsCompatible(&bmSrc1, &bmDst))
        return FALSE;
    if (bmSrc1.bmBitsPixel != 24)
        return FALSE;
    if (bmSrc1.bmPlanes != 1)
        return FALSE;
    if (!bmSrc1.bmBits || !bmSrc2.bmBits || !bmDst.bmBits)
        return FALSE;

    dwWidthBytes = bmDst.bmWidthBytes;
    
    // Initialize the surface pointers.

    lprgbSrc1 = (RGBTRIPLE *)bmSrc1.bmBits; 
    lprgbSrc2 = (RGBTRIPLE *)bmSrc2.bmBits;  
    lprgbDst  = (RGBTRIPLE *)bmDst.bmBits;

    for (y=0; y<bmDst.bmHeight; y++) {
        for (x=0; x<bmDst.bmWidth; x++) {
            lprgbDst[x].rgbtRed   = 
              (BYTE)((((DWORD)lprgbSrc1[x].rgbtRed * dwWeight1) + 
              ((DWORD)lprgbSrc2[x].rgbtRed * dwWeight2)) >> 8);
            lprgbDst[x].rgbtGreen = 
              (BYTE)((((DWORD)lprgbSrc1[x].rgbtGreen * dwWeight1) + 
              ((DWORD)lprgbSrc2[x].rgbtGreen * dwWeight2)) >> 8);
            lprgbDst[x].rgbtBlue  = 
              (BYTE)((((DWORD)lprgbSrc1[x].rgbtBlue * dwWeight1) + 
              ((DWORD)lprgbSrc2[x].rgbtBlue * dwWeight2)) >> 8);
        }

        // Move to next scan line.

        lprgbSrc1 = (RGBTRIPLE *)((LPBYTE)lprgbSrc1 + dwWidthBytes);
        lprgbSrc2 = (RGBTRIPLE *)((LPBYTE)lprgbSrc2 + dwWidthBytes);
        lprgbDst  = (RGBTRIPLE *)((LPBYTE)lprgbDst  + dwWidthBytes);
    }

    return TRUE;
}

BOOL DoAlphaBlend(
  HDC hdcDest,                 // Handle to destination DC.

  int nXOriginDest,            // X-coord of upper-left corner.

  int nYOriginDest,            // Y-coord of upper-left corner.

  int nWidthDest,              // Destination width.

  int nHeightDest,             // Destination height.

  HDC hdcSrc,                  // Handle to source DC.

  int nXOriginSrc,             // X-coord of upper-left corner.

  int nYOriginSrc,             // Y-coord of upper-left corner.

  int nWidthSrc,               // Source width.

  int nHeightSrc,              // Source height.

  DWORD dwSourceWeight)        // Source weighting (between 0 and 255).

{
    HDC      hdcSrc1 = NULL;
    HDC      hdcSrc2 = NULL;
    HDC      hdcDst  = NULL;
    HBITMAP  hbmSrc1 = NULL;
    HBITMAP  hbmSrc2 = NULL;
    HBITMAP  hbmDst  = NULL;
    BOOL     bReturn;

    // Create surfaces for sources and destination images.

    hbmSrc1 = Create24BPPDIBSection(hdcDest, nWidthDest,nHeightDest);
    if (!hbmSrc1) goto HANDLEERROR;

    hbmSrc2 = Create24BPPDIBSection(hdcDest, nWidthDest,nHeightDest);
    if (!hbmSrc2) goto HANDLEERROR;

    hbmDst  = Create24BPPDIBSection(hdcDest, nWidthDest,nHeightDest);
    if (!hbmDst) goto HANDLEERROR;

    
    // Create HDCs to hold our surfaces.

    hdcSrc1 = CreateCompatibleDC(hdcDest);
    if (!hdcSrc1) goto HANDLEERROR;
    
    hdcSrc2 = CreateCompatibleDC(hdcDest);
    if (!hdcSrc2) goto HANDLEERROR;
    
    hdcDst  = CreateCompatibleDC(hdcDest);
    if (!hdcDst) goto HANDLEERROR;

    
    // Prepare the surfaces for drawing.

    SelectObject(hdcSrc1, hbmSrc1);
    SelectObject(hdcSrc2, hbmSrc2);
    SelectObject(hdcDst,  hbmDst);
    SetStretchBltMode(hdcSrc1, COLORONCOLOR);
    SetStretchBltMode(hdcSrc2, COLORONCOLOR);

    
    // Capture a copy of the source area.

    if (!StretchBlt(hdcSrc1, 0,0,nWidthDest,nHeightDest,
                    hdcSrc,  nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc, 
                    SRCCOPY))
         goto HANDLEERROR;
    
    // Capture a copy of the destination area.

    if (!StretchBlt(hdcSrc2, 0,0,nWidthDest,nHeightDest,
                    hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, 
                    SRCCOPY))
         goto HANDLEERROR;

                  
    // Blend the two source areas to create the destination image.

    bReturn = BlendImages(hbmSrc1, hbmSrc2, hbmDst, dwSourceWeight);

    
    // Clean up objects you do not need any longer.

    // You cannot delete an object that's selected into an

    // HDC so delete the HDC first. 

    DeleteDC(hdcSrc1);
    DeleteDC(hdcSrc2);
    DeleteObject(hbmSrc1);
    DeleteObject(hbmSrc2);

    
    // Display the blended (destination) image to the target HDC.

    if (bReturn) {
        BitBlt(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, 
               hdcDst, 0,0, SRCCOPY);
    }

    
    // Clean up the rest of the objects you created.

    DeleteDC(hdcDst);
    DeleteObject(hbmDst);

    return bReturn;

HANDLEERROR:

    if (hdcSrc1) DeleteDC(hdcSrc1);
    if (hdcSrc2) DeleteDC(hdcSrc2);
    if (hdcDst)  DeleteDC(hdcDst);
    if (hbmSrc1) DeleteObject(hbmSrc1);
    if (hbmSrc2) DeleteObject(hbmSrc2);
    if (hbmDst)  DeleteObject(hbmDst);

    return FALSE;
}

Save Device Context into an uncompressed bitmap

// Function to save bitmap

BOOL SaveBitmap(HDC hDC,HBITMAP hBitmap,CString szPath)
{
    FILE * fp= NULL;
    fp = fopen(szPath.GetBuffer(1),"wb");
    if(fp == NULL)
        return false;
    
    BITMAP Bm;
    BITMAPINFO BitInfo;
    ZeroMemory(&BitInfo, sizeof(BITMAPINFO));
    BitInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    BitInfo.bmiHeader.biBitCount = 0;

    if(!::GetDIBits(hDC, hBitmap, 0, 0, NULL, &BitInfo, DIB_RGB_COLORS))
        return (false);

    Bm.bmHeight = BitInfo.bmiHeader.biHeight;
    Bm.bmWidth  = BitInfo.bmiHeader.biWidth;

    BITMAPFILEHEADER    BmHdr;
    
    BmHdr.bfType        = 0x4d42;   // 'BM' WINDOWS_BITMAP_SIGNATURE

    BmHdr.bfSize        = (((3 * Bm.bmWidth + 3) & ~3) * Bm.bmHeight) 
                          + sizeof(BITMAPFILEHEADER) 
                          + sizeof(BITMAPINFOHEADER);
    BmHdr.bfReserved1    = BmHdr.bfReserved2 = 0;
    BmHdr.bfOffBits      = (DWORD) sizeof(BITMAPFILEHEADER) 
                          + sizeof(BITMAPINFOHEADER);
    
    BitInfo.bmiHeader.biCompression = 0;
    // Writing Bitmap File Header ////

    fwrite(&BmHdr,sizeof(BITMAPFILEHEADER),1,fp);

    fwrite(&BitInfo.bmiHeader,sizeof(BITMAPINFOHEADER),1,fp);

    BYTE *pData = new BYTE5>;
    if(!::GetDIBits(hDC, hBitmap, 0, Bm.bmHeight, 
                 pData, &BitInfo, DIB_RGB_COLORS))
        return (false);
    if(pData != NULL)
        fwrite(pData,1,BitInfo.bmiHeader.biSizeImage,fp);

    fclose(fp);
    delete (pData);

    return (true);
}

// here is how to use the above function


//Get the device context

HDC hDC = ::GetDC(hWnd);
// Create a memory device context

HDC hMemDC = ::CreateCompatibleDC(hDC);
// Create a compatible bitmap 

HBITMAP hBitmap = CreateCompatibleBitmap(hDC, 
                 nScreenWidth,nScreenHeight);
// Select the bitmap into the memory context

::SelectObject(hMemDC,hBitmap);    
// Do what ever drawing you want into the Device Context

...
...
SaveBitmap(hMemDC, hBitmap,"Sample.bmp");

Points of Interest

SetStretchBltMode(hDC,HALFTONE)

Try out this function, this improves the quality of StretchBlt(). I think with our using this mode, SretchBlt() function cannot give you the required quality if you are dealing with big bitmaps.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here