DIB.CPP
上传用户:zch19780
上传日期:2007-01-02
资源大小:8k
文件大小:15k
源码类别:

Static控件

开发平台:

Visual C++

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Copyright (C) 1998 by Jorge Lodos
  3. // All rights reserved
  4. //
  5. // Distribute and use freely, except:
  6. // 1. Don't alter or remove this notice.
  7. // 2. Mark the changes you made
  8. //
  9. // Send bug reports, bug fixes, enhancements, requests, etc. to:
  10. //    lodos@cigb.edu.cu
  11. /////////////////////////////////////////////////////////////////////////////
  12. //  dib.cpp
  13. //
  14. #include "stdafx.h"
  15. #include "dib.h"
  16. #include <windowsx.h>
  17. #include <afxadv.h>
  18. #include <io.h>
  19. #include <errno.h>
  20. /////////////////////////////////////////////////////////////////////////////
  21. // CDib
  22. IMPLEMENT_DYNAMIC(CDib, CObject)
  23. CDib::CDib()
  24. {
  25. m_pBMI = NULL;
  26. m_pBits = NULL;
  27. m_pPalette = NULL;
  28. }
  29. CDib::~CDib()
  30. {
  31. Free();
  32. }
  33. void CDib::Free()
  34. {
  35. // Make sure all member data that might have been allocated is freed.
  36. if (m_pBits)
  37. {
  38. GlobalFreePtr(m_pBits);
  39. m_pBits = NULL;
  40. }
  41. if (m_pBMI)
  42. {
  43. GlobalFreePtr(m_pBMI);
  44. m_pBMI = NULL;
  45. }
  46. if (m_pPalette)
  47. {
  48. m_pPalette->DeleteObject();
  49. delete m_pPalette;
  50. m_pPalette = NULL;
  51. }
  52. }
  53. /*************************************************************************
  54.  *
  55.  * Paint()
  56.  *
  57.  * Parameters:
  58.  *
  59.  * HDC hDC          - DC to do output to
  60.  *
  61.  * LPRECT lpDCRect  - rectangle on DC to do output to
  62.  *
  63.  * LPRECT lpDIBRect - rectangle of DIB to output into lpDCRect
  64.  *
  65.  * CPalette* pPal   - pointer to CPalette containing DIB's palette
  66.  *
  67.  * Return Value:
  68.  *
  69.  * BOOL             - TRUE if DIB was drawn, FALSE otherwise
  70.  *
  71.  * Description:
  72.  *   Painting routine for a DIB.  Calls StretchDIBits() or
  73.  *   SetDIBitsToDevice() to paint the DIB.  The DIB is
  74.  *   output to the specified DC, at the coordinates given
  75.  *   in lpDCRect.  The area of the DIB to be output is
  76.  *   given by lpDIBRect.
  77.  *
  78.  ************************************************************************/
  79. BOOL CDib::Paint(HDC hDC, LPRECT lpDCRect, LPRECT lpDIBRect) const
  80. {
  81. if (!m_pBMI)
  82. return FALSE;
  83. HPALETTE hPal = NULL;           // Our DIB's palette
  84. HPALETTE hOldPal = NULL;        // Previous palette
  85. // Get the DIB's palette, then select it into DC
  86. if (m_pPalette != NULL)
  87. {
  88. hPal = (HPALETTE) m_pPalette->m_hObject;
  89. // Select as background since we have
  90. // already realized in forground if needed
  91. hOldPal = ::SelectPalette(hDC, hPal, TRUE);
  92. }
  93. /* Make sure to use the stretching mode best for color pictures */
  94. ::SetStretchBltMode(hDC, COLORONCOLOR);
  95. /* Determine whether to call StretchDIBits() or SetDIBitsToDevice() */
  96. BOOL bSuccess;
  97. if ((RECTWIDTH(lpDCRect)  == RECTWIDTH(lpDIBRect)) &&
  98.    (RECTHEIGHT(lpDCRect) == RECTHEIGHT(lpDIBRect)))
  99. bSuccess = ::SetDIBitsToDevice(hDC,        // hDC
  100.    lpDCRect->left,             // DestX
  101.    lpDCRect->top,              // DestY
  102.    RECTWIDTH(lpDCRect),        // nDestWidth
  103.    RECTHEIGHT(lpDCRect),       // nDestHeight
  104.    lpDIBRect->left,            // SrcX
  105.    (int)Height() -
  106.   lpDIBRect->top -
  107.   RECTHEIGHT(lpDIBRect),     // SrcY
  108.    0,                          // nStartScan
  109.    (WORD)Height(),             // nNumScans
  110.    m_pBits,                    // lpBits
  111.    m_pBMI,                     // lpBitsInfo
  112.    DIB_RGB_COLORS);            // wUsage
  113.    else
  114.   bSuccess = ::StretchDIBits(hDC,            // hDC
  115.    lpDCRect->left,               // DestX
  116.    lpDCRect->top,                // DestY
  117.    RECTWIDTH(lpDCRect),          // nDestWidth
  118.    RECTHEIGHT(lpDCRect),         // nDestHeight
  119.    lpDIBRect->left,              // SrcX
  120.    lpDIBRect->top,               // SrcY
  121.    RECTWIDTH(lpDIBRect),         // wSrcWidth
  122.    RECTHEIGHT(lpDIBRect),        // wSrcHeight
  123.    m_pBits,                      // lpBits
  124.    m_pBMI,                       // lpBitsInfo
  125.    DIB_RGB_COLORS,               // wUsage
  126.    SRCCOPY);                     // dwROP
  127. /* Reselect old palette */
  128. if (hOldPal != NULL)
  129. {
  130. ::SelectPalette(hDC, hOldPal, TRUE);
  131. }
  132.    return bSuccess;
  133. }
  134. /*************************************************************************
  135.  *
  136.  * CreatePalette()
  137.  *
  138.  * Return Value:
  139.  *
  140.  * TRUE if succesfull, FALSE otherwise
  141.  *
  142.  * Description:
  143.  *
  144.  * This function creates a palette from a DIB by allocating memory for the
  145.  * logical palette, reading and storing the colors from the DIB's color table
  146.  * into the logical palette, creating a palette from this logical palette,
  147.  * and then returning the palette's handle. This allows the DIB to be
  148.  * displayed using the best possible colors (important for DIBs with 256 or
  149.  * more colors).
  150.  *
  151.  ************************************************************************/
  152. BOOL CDib::CreatePalette()
  153. {
  154. if (!m_pBMI)
  155. return FALSE;
  156.    //get the number of colors in the DIB
  157.    WORD wNumColors = NumColors();
  158.    if (wNumColors != 0)
  159.    {
  160. // allocate memory block for logical palette
  161. HANDLE hLogPal = ::GlobalAlloc(GHND, sizeof(LOGPALETTE) + sizeof(PALETTEENTRY)*wNumColors);
  162. // if not enough memory, clean up and return NULL
  163. if (hLogPal == 0)
  164. return FALSE;
  165. LPLOGPALETTE lpPal = (LPLOGPALETTE)::GlobalLock((HGLOBAL)hLogPal);
  166. // set version and number of palette entries
  167. lpPal->palVersion = PALVERSION;
  168. lpPal->palNumEntries = (WORD)wNumColors;
  169. for (int i = 0; i < (int)wNumColors; i++)
  170. {
  171. lpPal->palPalEntry[i].peRed = m_pBMI->bmiColors[i].rgbRed;
  172. lpPal->palPalEntry[i].peGreen = m_pBMI->bmiColors[i].rgbGreen;
  173. lpPal->palPalEntry[i].peBlue = m_pBMI->bmiColors[i].rgbBlue;
  174. lpPal->palPalEntry[i].peFlags = 0;
  175. }
  176. /* create the palette and get handle to it */
  177. if (m_pPalette)
  178. {
  179. m_pPalette->DeleteObject();
  180. delete m_pPalette;
  181. }
  182. m_pPalette = new CPalette;
  183. BOOL bResult = m_pPalette->CreatePalette(lpPal);
  184. ::GlobalUnlock((HGLOBAL) hLogPal);
  185. ::GlobalFree((HGLOBAL) hLogPal);
  186. return bResult;
  187. }
  188. return TRUE;
  189. }
  190. /*************************************************************************
  191.  *
  192.  * Width()
  193.  *
  194.  * Return Value:
  195.  *
  196.  * DWORD            - width of the DIB
  197.  *
  198.  * Description:
  199.  *
  200.  * This function gets the width of the DIB from the BITMAPINFOHEADER
  201.  * width field 
  202.  *
  203.  ************************************************************************/
  204. DWORD CDib::Width() const
  205. {
  206. if (!m_pBMI)
  207. return 0;
  208. /* return the DIB width */
  209. return m_pBMI->bmiHeader.biWidth;
  210. }
  211. /*************************************************************************
  212.  *
  213.  * Height()
  214.  *
  215.  * Return Value:
  216.  *
  217.  * DWORD            - height of the DIB
  218.  *
  219.  * Description:
  220.  *
  221.  * This function gets the height of the DIB from the BITMAPINFOHEADER
  222.  * height field 
  223.  *
  224.  ************************************************************************/
  225. DWORD CDib::Height() const
  226. {
  227. if (!m_pBMI)
  228. return 0;
  229. /* return the DIB height */
  230. return m_pBMI->bmiHeader.biHeight;
  231. }
  232. /*************************************************************************
  233.  *
  234.  * PaletteSize()
  235.  *
  236.  * Return Value:
  237.  *
  238.  * WORD             - size of the color palette of the DIB
  239.  *
  240.  * Description:
  241.  *
  242.  * This function gets the size required to store the DIB's palette by
  243.  * multiplying the number of colors by the size of an RGBQUAD 
  244.  *
  245.  ************************************************************************/
  246. WORD CDib::PaletteSize() const
  247. {
  248. if (!m_pBMI)
  249. return 0;
  250. return NumColors() * sizeof(RGBQUAD);
  251. }
  252. /*************************************************************************
  253.  *
  254.  * NumColors()
  255.  *
  256.  * Return Value:
  257.  *
  258.  * WORD             - number of colors in the color table
  259.  *
  260.  * Description:
  261.  *
  262.  * This function calculates the number of colors in the DIB's color table
  263.  * by finding the bits per pixel for the DIB (whether Win3.0 or other-style
  264.  * DIB). If bits per pixel is 1: colors=2, if 4: colors=16, if 8: colors=256,
  265.  * if 24, no colors in color table.
  266.  *
  267.  ************************************************************************/
  268. WORD CDib::NumColors() const
  269. {
  270. if (!m_pBMI)
  271. return 0;
  272. WORD wBitCount;  // DIB bit count
  273. /*  The number of colors in the color table can be less than 
  274.  *  the number of bits per pixel allows for (i.e. lpbi->biClrUsed
  275.  *  can be set to some value).
  276.  *  If this is the case, return the appropriate value.
  277.  */
  278. DWORD dwClrUsed;
  279. dwClrUsed = m_pBMI->bmiHeader.biClrUsed;
  280. if (dwClrUsed != 0)
  281. return (WORD)dwClrUsed;
  282. /*  Calculate the number of colors in the color table based on
  283.  *  the number of bits per pixel for the DIB.
  284.  */
  285. wBitCount = m_pBMI->bmiHeader.biBitCount;
  286. /* return number of colors based on bits per pixel */
  287. switch (wBitCount)
  288. {
  289. case 1:
  290. return 2;
  291. case 4:
  292. return 16;
  293. case 8:
  294. return 256;
  295. default:
  296. return 0;
  297. }
  298. }
  299. /*************************************************************************
  300.  *
  301.  * Save()
  302.  *
  303.  * Saves the specified DIB into the specified CFile.  The CFile
  304.  * is opened and closed by the caller.
  305.  *
  306.  * Parameters:
  307.  *
  308.  * CFile& file - open CFile used to save DIB
  309.  *
  310.  * Return value: Number of saved bytes or CFileException
  311.  *
  312.  *************************************************************************/
  313. DWORD CDib::Save(CFile& file) const
  314. {
  315. BITMAPFILEHEADER bmfHdr; // Header for Bitmap file
  316. DWORD dwDIBSize;
  317. if (m_pBMI == NULL)
  318. return 0;
  319. // Fill in the fields of the file header
  320. // Fill in file type (first 2 bytes must be "BM" for a bitmap)
  321. bmfHdr.bfType = DIB_HEADER_MARKER;  // "BM"
  322. // Calculating the size of the DIB is a bit tricky (if we want to
  323. // do it right).  The easiest way to do this is to call GlobalSize()
  324. // on our global handle, but since the size of our global memory may have
  325. // been padded a few bytes, we may end up writing out a few too
  326. // many bytes to the file (which may cause problems with some apps).
  327. //
  328. // So, instead let's calculate the size manually (if we can)
  329. //
  330. // First, find size of header plus size of color table.  Since the
  331. // first DWORD in both BITMAPINFOHEADER and BITMAPCOREHEADER conains
  332. // the size of the structure, let's use this.
  333. dwDIBSize = *(LPDWORD)&m_pBMI->bmiHeader + PaletteSize();  // Partial Calculation
  334. // Now calculate the size of the image
  335. if ((m_pBMI->bmiHeader.biCompression == BI_RLE8) || (m_pBMI->bmiHeader.biCompression == BI_RLE4))
  336. {
  337. // It's an RLE bitmap, we can't calculate size, so trust the
  338. // biSizeImage field
  339. dwDIBSize += m_pBMI->bmiHeader.biSizeImage;
  340. }
  341. else
  342. {
  343. DWORD dwBmBitsSize;  // Size of Bitmap Bits only
  344. // It's not RLE, so size is Width (DWORD aligned) * Height
  345. dwBmBitsSize = WIDTHBYTES((m_pBMI->bmiHeader.biWidth)*((DWORD)m_pBMI->bmiHeader.biBitCount)) * m_pBMI->bmiHeader.biHeight;
  346. dwDIBSize += dwBmBitsSize;
  347. // Now, since we have calculated the correct size, why don't we
  348. // fill in the biSizeImage field (this will fix any .BMP files which
  349. // have this field incorrect).
  350. m_pBMI->bmiHeader.biSizeImage = dwBmBitsSize;
  351. }
  352. // Calculate the file size by adding the DIB size to sizeof(BITMAPFILEHEADER)
  353. bmfHdr.bfSize = dwDIBSize + sizeof(BITMAPFILEHEADER);
  354. bmfHdr.bfReserved1 = 0;
  355. bmfHdr.bfReserved2 = 0;
  356. /*
  357.  * Now, calculate the offset the actual bitmap bits will be in
  358.  * the file -- It's the Bitmap file header plus the DIB header,
  359.  * plus the size of the color table.
  360.  */
  361. bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + m_pBMI->bmiHeader.biSize + PaletteSize();
  362. // Write the file header
  363. file.Write((LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER));
  364. DWORD dwBytesSaved = sizeof(BITMAPFILEHEADER); 
  365. // Write the DIB header
  366. UINT nCount = sizeof(BITMAPINFO) + (NumColors()-1)*sizeof(RGBQUAD);
  367. dwBytesSaved += nCount; 
  368. file.Write(m_pBMI, nCount);
  369. // Write the DIB bits
  370. DWORD dwBytes = m_pBMI->bmiHeader.biBitCount * Width();
  371.   // Calculate the number of bytes per line
  372. if (dwBytes%32 == 0)
  373. dwBytes /= 8;
  374. else
  375. dwBytes = dwBytes/8 + (32-dwBytes%32)/8 + (((32-dwBytes%32)%8 > 0) ? 1 : 0); 
  376. nCount = dwBytes * Height();
  377. dwBytesSaved += nCount; 
  378. file.WriteHuge(m_pBits, nCount);
  379. return dwBytesSaved;
  380. }
  381. /*************************************************************************
  382.   Function:  Read (CFile&)
  383.    Purpose:  Reads in the specified DIB file into a global chunk of
  384.  memory.
  385.    Returns:  Number of read bytes.
  386. *************************************************************************/
  387. DWORD CDib::Read(CFile& file)
  388. {
  389. // Ensures no memory leaks will occur
  390. Free();
  391. BITMAPFILEHEADER bmfHeader;
  392. // Go read the DIB file header and check if it's valid.
  393. if (file.Read((LPSTR)&bmfHeader, sizeof(bmfHeader)) != sizeof(bmfHeader))
  394. return 0;
  395. if (bmfHeader.bfType != DIB_HEADER_MARKER)
  396. return 0;
  397. DWORD dwReadBytes = sizeof(bmfHeader);
  398. // Allocate memory for DIB
  399. m_pBMI = (LPBITMAPINFO)GlobalAllocPtr(GHND, bmfHeader.bfOffBits-sizeof(BITMAPFILEHEADER) + 256*sizeof(RGBQUAD));
  400. if (m_pBMI == 0)
  401. return 0;
  402. // Read header.
  403. if (file.Read(m_pBMI, bmfHeader.bfOffBits-sizeof(BITMAPFILEHEADER)) != (UINT)(bmfHeader.bfOffBits-sizeof(BITMAPFILEHEADER)))
  404. {
  405. GlobalFreePtr(m_pBMI);
  406. m_pBMI = NULL;
  407. return 0;
  408. }
  409. dwReadBytes += bmfHeader.bfOffBits-sizeof(BITMAPFILEHEADER);
  410. DWORD dwLength = file.GetLength();
  411. // Go read the bits.
  412. m_pBits = (LPBYTE)GlobalAllocPtr(GHND, dwLength - bmfHeader.bfOffBits);
  413. if (m_pBits == 0)
  414. {
  415. GlobalFreePtr(m_pBMI);
  416. m_pBMI = NULL;
  417. return 0;
  418. }
  419. if (file.ReadHuge(m_pBits, dwLength-bmfHeader.bfOffBits) != (dwLength - bmfHeader.bfOffBits))
  420. {
  421. GlobalFreePtr(m_pBMI);
  422. m_pBMI = NULL;
  423. GlobalFreePtr(m_pBits);
  424. m_pBits = NULL;
  425. return 0;
  426. }
  427. dwReadBytes += dwLength - bmfHeader.bfOffBits;
  428. CreatePalette();
  429. return dwReadBytes;
  430. }
  431. #ifdef _DEBUG
  432. void CDib::Dump(CDumpContext& dc) const
  433. {
  434. CObject::Dump(dc);
  435. }
  436. #endif
  437. //////////////////////////////////////////////////////////////////////////
  438. //// Clipboard support
  439. //---------------------------------------------------------------------
  440. //
  441. // Function:   CopyToHandle
  442. //
  443. // Purpose:    Makes a copy of the DIB to a global memory block.  Returns
  444. //             a handle to the new memory block (NULL on error).
  445. //
  446. // Returns:    Handle to new global memory block.
  447. //
  448. //---------------------------------------------------------------------
  449. HGLOBAL CDib::CopyToHandle() const
  450. {
  451. CSharedFile file;
  452. try
  453. {
  454. if (Save(file)==0)
  455. return 0;
  456. }
  457. catch (CFileException* e)
  458. {
  459. e->Delete();
  460. return 0;
  461. }
  462. return file.Detach();
  463. }
  464. //---------------------------------------------------------------------
  465. //
  466. // Function:   ReadFromHandle
  467. //
  468. // Purpose:    Initializes from the given global memory block.  
  469. //
  470. // Returns:    Number of read bytes.
  471. //
  472. //---------------------------------------------------------------------
  473. DWORD CDib::ReadFromHandle(HGLOBAL hGlobal)
  474. {
  475. CSharedFile file;
  476. file.SetHandle(hGlobal, FALSE);
  477. DWORD dwResult = Read(file);
  478. file.Detach();
  479. return dwResult;
  480. }
  481. //////////////////////////////////////////////////////////////////////////
  482. //// Serialization support
  483. void CDib::Serialize(CArchive& ar) 
  484. {
  485. CFile* pFile = ar.GetFile();
  486. ASSERT(pFile != NULL);
  487. if (ar.IsStoring())
  488. { // storing code
  489. Save(*pFile);
  490. }
  491. else
  492. { // loading code
  493. Read(*pFile);
  494. }
  495. }