Advanced MFC Programming

Advanced MFC Programming Advanced MFC Programming

math.hcmuns.edu.vn
from math.hcmuns.edu.vn More from this publisher
11.04.2014 Views

Chapter 10. Bitmap pBmp->GetBitmap(&bm); bi.biSize=sizeof(BITMAPINFOHEADER); bi.biWidth=bm.bmWidth; bi.biHeight=bm.bmHeight; bi.biPlanes=bm.bmPlanes; bi.biBitCount=bm.bmPlanes*bm.bmBitsPixel; bi.biCompression=BI_RGB; bi.biSizeImage=0; bi.biXPelsPerMeter=0; bi.biYPelsPerMeter=0; bi.biClrUsed=0; bi.biClrImportant=0; dwSizeCT=GetColorTableSize(bi.biBitCount); dwDibLen=bi.biSize+dwSizeCT*sizeof(RGBQUAD); pPalOld=dc.SelectPalette(&m_palDraw, FALSE); dc.RealizePalette(); hDib=::GlobalAlloc(GHND, dwDibLen); lpBi=(LPBITMAPINFO)::GlobalLock(hDib); …… lpBi->bmiHeader=bi; We first fill the information obtained previously into a BITMAPINFOHEADER object. This is necessary because when calling function ::GetDIBits(…), we need to provide a BITMAPINFOHEADER type pointer which contains useful information. Here, some unimportant members of BITMAPINFOHEADER are assigned 0s (biSizeImage, biXPelsPerMeter…). Then the size of the color table is calculated and a global memory that is big enough for holding bitmap information header and color table is allocated, and the bitmap information header is stored into the buffers. We will use these buffers to receive color table. Although the memory size for storing bitmap data can be calculated from the information already known, usually it is not done at this point. Generally the color table and the bitmap data are retrieved separately, in the first step, only the memory that is big enough for storing structure BITMAPINFOHEADER and the color table is prepared. When color table is being retrieved, the bitmap information header will also be updated at the same time. Since it is more desirable to calculate the bitmap data size using the updated information, in the sample, the memory size is updated after the color table is obtained successfully, and the global memory is reallocated for retrieving the bitmap data. We also need to select logical palette into the DC and realize it so that the bitmap pixels will be intepreted by its own color table. Function ::GetDIBits(…) is called in the next step to recieve BITMAPINFOHEADER data and the color table. Because some device drivers do not fill member biImageSize (This member carries redunant information with members biWidth, biHeight, and biBitCount), we need to calculate it if necessary: …… …… VERIFY ( ::GetDIBits ( dc.GetSafeHdc(), (HBITMAP)pBmp->GetSafeHandle(), 0, (WORD)bi.biHeight, NULL, lpBi, DIB_RGB_COLORS ) ); bi=lpBi->bmiHeader; ::GlobalUnlock(hDib); if(bi.biSizeImage == 0) { bi.biSizeImage=WIDTHBYTES(bi.biBitCount*bi.biWidth)*bi.biHeight; } 298

Chapter 10. Bitmap Now the size of DIB data is already known, we can reallocate the buffers, and call function ::GetDIBits(…) again to receive bitmap data. Finally we need to select the logical palette out of the DC, and return the handle of the global memory before function exits: …… } dwDibLen+=bi.biSizeImage; hDib=::GlobalReAlloc(hDib, dwDibLen, GHND); ASSERT(hDib); lpBi=(LPBITMAPINFO)::GlobalLock(hDib); ASSERT(hDib); VERIFY ( ::GetDIBits ( dc.GetSafeHdc(), (HBITMAP)pBmp->GetSafeHandle(), 0, (WORD)bi.biHeight, (LPSTR)lpBi+sizeof(BITMAPINFOHEADER)+dwSizeCT*sizeof(RGBQUAD), lpBi, DIB_RGB_COLORS ) ); ::GlobalUnlock(hDib); dc.SelectPalette(pPalOld, FALSE); return hDib; Using New Functions Using function CGDIDoc::ConvertDDBtoDIB(…), it is farily easy to save the bitmap into a file. All we need is to call this function to convert DDB to DIB, add a BITMAPFILEHEADER structure to it, and write the whole data into a file. In the sample, file saving is implement in function CGDIDoc::Serialize(…): void CGDIDoc::Serialize(CArchive& ar) { if(ar.IsStoring()) { HGLOBAL hDib; BITMAPFILEHEADER bmf; BITMAPINFOHEADER bi; LPBITMAPINFOHEADER lpBi; DWORD dwSizeCT; …… } hDib=ConvertDDBtoDIB(&m_bmpDraw); ASSERT(hDib); bmf.bfType='MB'; bmf.bfSize=sizeof(bmf)+::GlobalSize(hDib); bmf.bfReserved1=0; bmf.bfReserved2=0; lpBi=(LPBITMAPINFOHEADER)::GlobalLock(hDib); bi=*lpBi; dwSizeCT=GetColorTableSize(bi.biBitCount); bmf.bfOffBits=sizeof(bmf)+bi.biSize+dwSizeCT*sizeof(RGBQUAD); ar.Write((char *)&bmf, sizeof(bmf)); ar.Write((LPSTR)lpBi, bi.biSize+dwSizeCT*sizeof(RGBQUAD)+bi.biSizeImage); ::GlobalUnlock(hDib); ::GlobalFree(hDib); } else In the sample, command File | Save is disabled so that the user can only save the image through File | Save As command by specifying a new file name. To implement this, UPDATE_COMMAND_UI message 299

Chapter 10. Bitmap<br />

Now the size of DIB data is already known, we can reallocate the buffers, and call function<br />

::GetDIBits(…) again to receive bitmap data. Finally we need to select the logical palette out of the DC,<br />

and return the handle of the global memory before function exits:<br />

……<br />

}<br />

dwDibLen+=bi.biSizeImage;<br />

hDib=::GlobalReAlloc(hDib, dwDibLen, GHND);<br />

ASSERT(hDib);<br />

lpBi=(LPBITMAPINFO)::GlobalLock(hDib);<br />

ASSERT(hDib);<br />

VERIFY<br />

(<br />

::GetDIBits<br />

(<br />

dc.GetSafeHdc(),<br />

(HBITMAP)pBmp->GetSafeHandle(),<br />

0,<br />

(WORD)bi.biHeight,<br />

(LPSTR)lpBi+sizeof(BITMAPINFOHEADER)+dwSizeCT*sizeof(RGBQUAD),<br />

lpBi,<br />

DIB_RGB_COLORS<br />

)<br />

);<br />

::GlobalUnlock(hDib);<br />

dc.SelectPalette(pPalOld, FALSE);<br />

return hDib;<br />

Using New Functions<br />

Using function CGDIDoc::ConvertDDBtoDIB(…), it is farily easy to save the bitmap into a file. All we<br />

need is to call this function to convert DDB to DIB, add a BITMAPFILEHEADER structure to it, and write the<br />

whole data into a file. In the sample, file saving is implement in function CGDIDoc::Serialize(…):<br />

void CGDIDoc::Serialize(CArchive& ar)<br />

{<br />

if(ar.IsStoring())<br />

{<br />

HGLOBAL hDib;<br />

BITMAPFILEHEADER bmf;<br />

BITMAPINFOHEADER bi;<br />

LPBITMAPINFOHEADER lpBi;<br />

DWORD dwSizeCT;<br />

……<br />

}<br />

hDib=ConvertDDBtoDIB(&m_bmpDraw);<br />

ASSERT(hDib);<br />

bmf.bfType='MB';<br />

bmf.bfSize=sizeof(bmf)+::GlobalSize(hDib);<br />

bmf.bfReserved1=0;<br />

bmf.bfReserved2=0;<br />

lpBi=(LPBITMAPINFOHEADER)::GlobalLock(hDib);<br />

bi=*lpBi;<br />

dwSizeCT=GetColorTableSize(bi.biBitCount);<br />

bmf.bfOffBits=sizeof(bmf)+bi.biSize+dwSizeCT*sizeof(RGBQUAD);<br />

ar.Write((char *)&bmf, sizeof(bmf));<br />

ar.Write((LPSTR)lpBi, bi.biSize+dwSizeCT*sizeof(RGBQUAD)+bi.biSizeImage);<br />

::GlobalUnlock(hDib);<br />

::GlobalFree(hDib);<br />

}<br />

else<br />

In the sample, command File | Save is disabled so that the user can only save the image through File |<br />

Save As command by specifying a new file name. To implement this, UPDATE_COMMAND_UI message<br />

299

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!