Advanced MFC Programming
Advanced MFC Programming Advanced MFC Programming
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
- Page 263 and 264: Chapter 9. Font }; Variable m_nRang
- Page 265 and 266: Chapter 9. Font Frame border is gra
- Page 267 and 268: Chapter 9. Font CFont *ptrFont; if(
- Page 269 and 270: Chapter 9. Font POINT pt; CClientDC
- Page 271 and 272: Chapter 9. Font } if(dlg.DoModal()
- Page 273 and 274: Chapter 9. Font In this function, W
- Page 275 and 276: Chapter 9. Font } CScrollView::OnKe
- Page 277 and 278: Chapter 9. Font …… } nKeyState=
- Page 279 and 280: Chapter 9. Font To check out if the
- Page 281 and 282: Chapter 9. Font the same, it indica
- Page 283 and 284: Chapter 9. Font } if(m_nSelIndexBgn
- Page 285 and 286: Chapter 9. Font GHND GPTR Same with
- Page 287 and 288: Chapter 9. Font …… } { Since th
- Page 289 and 290: Chapter 9. Font Function CDocument:
- Page 291 and 292: Chapter 9. Font …… void CGDIDoc
- Page 293 and 294: Chapter 9. Font …… { } UpdateAl
- Page 295 and 296: Chapter 9. Font …… …… case
- Page 297 and 298: Chapter 9. Font client window to be
- Page 299 and 300: Chapter 10. Bitmap ); DWORD dwRop T
- Page 301 and 302: Chapter 10. Bitmap Sample 10.1-2\GD
- Page 303 and 304: Chapter 10. Bitmap The next part of
- Page 305 and 306: Chapter 10. Bitmap Sample Sample 10
- Page 307 and 308: Chapter 10. Bitmap } pPalDraw=pDoc-
- Page 309 and 310: Chapter 10. Bitmap Member bfType mu
- Page 311 and 312: Chapter 10. Bitmap …… dwSize=bf
- Page 313: Chapter 10. Bitmap …… …… }
- Page 317 and 318: Chapter 10. Bitmap fuColorUse Speci
- Page 319 and 320: Chapter 10. Bitmap if(hData != NULL
- Page 321 and 322: Chapter 10. Bitmap …… …… cl
- Page 323 and 324: Chapter 10. Bitmap used as the orig
- Page 325 and 326: Chapter 10. Bitmap With the above i
- Page 327 and 328: Chapter 10. Bitmap …… …… if
- Page 329 and 330: Chapter 10. Bitmap …… } } { if(
- Page 331 and 332: Chapter 10. Bitmap …… } rgbQuad
- Page 333 and 334: Chapter 10. Bitmap DIB Section Both
- Page 335 and 336: Chapter 10. Bitmap } } if(m_pBmpMas
- Page 337 and 338: Chapter 10. Bitmap …… m_pBmpOld
- Page 339 and 340: Chapter 10. Bitmap BITMAP bm; …
- Page 341 and 342: Chapter 10. Bitmap Draw this portio
- Page 343 and 344: Chapter 10. Bitmap 1) Paint the des
- Page 345 and 346: Chapter 10. Bitmap color bitmap, bu
- Page 347 and 348: Chapter 10. Bitmap will destroy the
- Page 349 and 350: Chapter 10. Bitmap 10) The total im
- Page 351 and 352: Chapter 11. Sample: Simple Paint Af
- Page 353 and 354: Chapter 11. Sample: Simple Paint CG
- Page 355 and 356: Chapter 11. Sample: Simple Paint Th
- Page 357 and 358: Chapter 11. Sample: Simple Paint Co
- Page 359 and 360: Chapter 11. Sample: Simple Paint vo
- Page 361 and 362: Chapter 11. Sample: Simple Paint m_
- Page 363 and 364: Chapter 11. Sample: Simple Paint cu
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