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;
ZeroMemory(&bmi, sizeof(bmi));
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;
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;
if (dwWeight1 > 255) return FALSE;
dwWeight2 = 255-dwWeight1;
if (!GetObject(hbmSrc1, sizeof(BITMAP), &bmSrc1)) return FALSE;
if (!GetObject(hbmSrc2, sizeof(BITMAP), &bmSrc2)) return FALSE;
if (!GetObject(hbmDst, sizeof(BITMAP), &bmDst)) return FALSE;
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;
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);
}
lprgbSrc1 = (RGBTRIPLE *)((LPBYTE)lprgbSrc1 + dwWidthBytes);
lprgbSrc2 = (RGBTRIPLE *)((LPBYTE)lprgbSrc2 + dwWidthBytes);
lprgbDst = (RGBTRIPLE *)((LPBYTE)lprgbDst + dwWidthBytes);
}
return TRUE;
}
BOOL DoAlphaBlend(
HDC hdcDest,
int nXOriginDest,
int nYOriginDest,
int nWidthDest,
int nHeightDest,
HDC hdcSrc,
int nXOriginSrc,
int nYOriginSrc,
int nWidthSrc,
int nHeightSrc,
DWORD dwSourceWeight)
{
HDC hdcSrc1 = NULL;
HDC hdcSrc2 = NULL;
HDC hdcDst = NULL;
HBITMAP hbmSrc1 = NULL;
HBITMAP hbmSrc2 = NULL;
HBITMAP hbmDst = NULL;
BOOL bReturn;
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;
hdcSrc1 = CreateCompatibleDC(hdcDest);
if (!hdcSrc1) goto HANDLEERROR;
hdcSrc2 = CreateCompatibleDC(hdcDest);
if (!hdcSrc2) goto HANDLEERROR;
hdcDst = CreateCompatibleDC(hdcDest);
if (!hdcDst) goto HANDLEERROR;
SelectObject(hdcSrc1, hbmSrc1);
SelectObject(hdcSrc2, hbmSrc2);
SelectObject(hdcDst, hbmDst);
SetStretchBltMode(hdcSrc1, COLORONCOLOR);
SetStretchBltMode(hdcSrc2, COLORONCOLOR);
if (!StretchBlt(hdcSrc1, 0,0,nWidthDest,nHeightDest,
hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
SRCCOPY))
goto HANDLEERROR;
if (!StretchBlt(hdcSrc2, 0,0,nWidthDest,nHeightDest,
hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest,
SRCCOPY))
goto HANDLEERROR;
bReturn = BlendImages(hbmSrc1, hbmSrc2, hbmDst, dwSourceWeight);
DeleteDC(hdcSrc1);
DeleteDC(hdcSrc2);
DeleteObject(hbmSrc1);
DeleteObject(hbmSrc2);
if (bReturn) {
BitBlt(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest,
hdcDst, 0,0, SRCCOPY);
}
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
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;
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;
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);
}
HDC hDC = ::GetDC(hWnd);
HDC hMemDC = ::CreateCompatibleDC(hDC);
HBITMAP hBitmap = CreateCompatibleBitmap(hDC,
nScreenWidth,nScreenHeight);
::SelectObject(hMemDC,hBitmap);
...
...
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.