Click here to Skip to main content
Licence 
First Posted 4 Mar 2004
Views 58,842
Downloads 1,495
Bookmarked 44 times

Desktop Calendar

By Arun krishnan | 4 Mar 2004
A nice desktop calendar that sits on your desktop.
5 votes, 23.8%
1

2
1 vote, 4.8%
3
6 votes, 28.6%
4
9 votes, 42.9%
5
3.80/5 - 21 votes
μ 3.21, σa 2.84 [?]

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 BYTE[BitInfo.bmiHeader.biSizeImage + 5];
    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

About the Author

Arun krishnan

Software Developer (Senior)
Tata Elxsi Ltd
India India

Member


Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
QuestionHow to display Window 7? Pinmemberdinh_vu_vt200521:54 23 Feb '11  
RantHelp PinmemberSteve Noll1:49 18 Aug '10  
GeneralRe: Help PinmemberArun krishnan8:10 20 Aug '10  
QuestionHow can i put the month and a year? Pinmemberallan paglinawan4:32 14 Mar '09  
QuestionThe code does not support unicode ? PinmemberTo Quang Hiep7:16 5 Oct '08  
GeneralSaveBitmap Function NOTWorking PinmemberGaurang Shah 03320:31 31 Aug '07  
GeneralRe: SaveBitmap Function NOTWorking PinmemberArun krishnan17:24 1 Sep '07  
QuestionSaveBitmap PinmemberMember #74686111:33 7 Mar '07  
AnswerRe: SaveBitmap PinmemberArun krishnan7:11 17 Aug '07  
GeneralmEMORYYY Pinmembermircea1313138:08 24 Aug '06  
Generalnice one Pinmemberseishin6661:32 3 Jun '06  
GeneralPlease give me some directions about advanced functions Pinmemberu852100117:23 27 Jan '05  
GeneralHighlighting Current Date... PinmemberVali_Ali21:04 22 Aug '04  
A minor enhancement would be to highlight the current date on the calendar.   The thing to do will be to add another variable in DrawCalendar method, say:
 
CTime     t = CTime::GetCurrentTime();
....
INT nToday = t.GetDay();
 
Then, while drawing the actual day (find the matching code in the for statement), add something similar to the code below...
 
if(strlen(days[n-7]) != 0)
{
     if ((n - 7) == (nToday - 1))
     {
          int iOldMode = ::SetBkMode(m_hMemDC, TRANSPARENT);
          ::Rectangle(m_hMemDC,
                                          (RectDay.left + 16),
                                          (RectDay.top - 2),
                                          (RectDay.right + 10),
                                          (RectDay.bottom + 2));
          ::SetBkMode(m_hMemDC, iOldMode);
     }
 
     DrawText(m_hMemDC,
                        days[n-7],
                        strlen(days[n-7]),
                        &RectDay,
                        DT_RIGHT |
                        DT_VCENTER |
                        DT_SINGLELINE);
}

 
Vali Ali
GeneralVery cool code PinmemberDanYELL17:19 17 May '04  
Generaldifferent language PinsussCuriousInCrossLanguageDeveloper21:43 19 Mar '04  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web04 | 2.5.120210.1 | Last Updated 5 Mar 2004
Article Copyright 2004 by Arun krishnan
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid