dib256.cpp
上传用户:yinguanfa
上传日期:2022-02-19
资源大小:400k
文件大小:14k
源码类别:

ListView/ListBox

开发平台:

Visual C++

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Copyright (C) 1998 by J鰎g K鰊ig
  3. // All rights reserved
  4. //
  5. // This file is part of the completely free tetris clone "CGTetris".
  6. //
  7. // This is free software.
  8. // You may redistribute it by any means providing it is not sold for profit
  9. // without the authors written consent.
  10. //
  11. // No warrantee of any kind, expressed or implied, is included with this
  12. // software; use at your own risk, responsibility for damages (if any) to
  13. // anyone resulting from the use of this software rests entirely with the
  14. // user.
  15. //
  16. // Send bug reports, bug fixes, enhancements, requests, flames, etc., and
  17. // I'll try to keep a version up to date.  I can be reached as follows:
  18. //    J.Koenig@adg.de                 (company site)
  19. //    Joerg.Koenig@rhein-neckar.de    (private site)
  20. /////////////////////////////////////////////////////////////////////////////
  21. #include "stdafx.h"
  22. #include "dib256.h"
  23. #include "dibpal.h"
  24. #define PADWIDTH(x) (((x)*8 + 31)  & (~31))/8
  25. CDIBitmap :: CDIBitmap()
  26. : m_pInfo(0)
  27. , m_pPixels(0)
  28. , m_pPal(0)
  29. , m_bIsPadded(FALSE)
  30. {
  31. }
  32. CDIBitmap :: ~CDIBitmap() {
  33.     delete [] (BYTE*)m_pInfo;
  34.     delete [] m_pPixels;
  35. delete m_pPal;
  36. }
  37. void CDIBitmap :: DestroyBitmap() {
  38.     delete [] (BYTE*)m_pInfo;
  39.     delete [] m_pPixels;
  40. delete m_pPal;
  41. m_pInfo = 0;
  42. m_pPixels = 0;
  43. m_pPal = 0;
  44. }
  45. BOOL CDIBitmap :: CreateFromBitmap( CDC * pDC, CBitmap * pSrcBitmap ) {
  46. ASSERT_VALID(pSrcBitmap);
  47. ASSERT_VALID(pDC);
  48. try {
  49. BITMAP bmHdr;
  50. // Get the pSrcBitmap info
  51. pSrcBitmap->GetObject(sizeof(BITMAP), &bmHdr);
  52. // Reallocate space for the image data
  53. if( m_pPixels ) {
  54. delete [] m_pPixels;
  55. m_pPixels = 0;
  56. }
  57. DWORD dwWidth;
  58. if (bmHdr.bmBitsPixel > 8)
  59. dwWidth = PADWIDTH(bmHdr.bmWidth * 3);
  60. else
  61. dwWidth = PADWIDTH(bmHdr.bmWidth);
  62. m_pPixels = new BYTE[dwWidth*bmHdr.bmHeight];
  63. if( !m_pPixels )
  64. throw TEXT("could not allocate data storagen");
  65. // Set the appropriate number of colors base on BITMAP structure info
  66. WORD wColors;
  67. switch( bmHdr.bmBitsPixel ) {
  68. case 1 : 
  69. wColors = 2;
  70. break;
  71. case 4 :
  72. wColors = 16;
  73. break;
  74. case 8 :
  75. wColors = 256;
  76. break;
  77. default :
  78. wColors = 0;
  79. break;
  80. }
  81. // Re-allocate and populate BITMAPINFO structure
  82. if( m_pInfo ) {
  83. delete [] (BYTE*)m_pInfo;
  84. m_pInfo = 0;
  85. }
  86. m_pInfo = (BITMAPINFO*)new BYTE[sizeof(BITMAPINFOHEADER) + wColors*sizeof(RGBQUAD)];
  87. if( !m_pInfo )
  88. throw TEXT("could not allocate BITMAPINFO structn");
  89. // Populate BITMAPINFO header info
  90. m_pInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  91. m_pInfo->bmiHeader.biWidth = bmHdr.bmWidth;
  92. m_pInfo->bmiHeader.biHeight = bmHdr.bmHeight;
  93. m_pInfo->bmiHeader.biPlanes = bmHdr.bmPlanes;
  94. if( bmHdr.bmBitsPixel > 8 )
  95. m_pInfo->bmiHeader.biBitCount = 24;
  96. else
  97. m_pInfo->bmiHeader.biBitCount = bmHdr.bmBitsPixel;
  98. m_pInfo->bmiHeader.biCompression = BI_RGB;
  99. m_pInfo->bmiHeader.biSizeImage = ((((bmHdr.bmWidth * bmHdr.bmBitsPixel) + 31) & ~31) >> 3) * bmHdr.bmHeight;
  100. m_pInfo->bmiHeader.biXPelsPerMeter = 0;
  101. m_pInfo->bmiHeader.biYPelsPerMeter = 0;
  102. m_pInfo->bmiHeader.biClrUsed = 0;
  103. m_pInfo->bmiHeader.biClrImportant = 0;
  104. // Now actually get the bits
  105. int test = ::GetDIBits(pDC->GetSafeHdc(), (HBITMAP)pSrcBitmap->GetSafeHandle(),
  106.   0, (WORD)bmHdr.bmHeight, m_pPixels, m_pInfo, DIB_RGB_COLORS);
  107. // check that we scanned in the correct number of bitmap lines
  108. if( test != (int)bmHdr.bmHeight )
  109. throw TEXT("call to GetDIBits did not return full number of requested scan linesn");
  110. CreatePalette();
  111. m_bIsPadded = FALSE;
  112. #ifdef _DEBUG
  113. } catch( TCHAR * psz ) {
  114. TRACE1("CDIBitmap::CreateFromBitmap(): %sn", psz);
  115. #else
  116. } catch( TCHAR * ) {
  117. #endif
  118. if( m_pPixels ) {
  119. delete [] m_pPixels;
  120. m_pPixels = 0;
  121. }
  122. if( m_pInfo ) {
  123. delete [] (BYTE*) m_pInfo;
  124. m_pInfo = 0;
  125. }
  126. return FALSE;
  127. }
  128. return TRUE;
  129. }
  130. BOOL CDIBitmap :: LoadResource(LPCTSTR pszID) {
  131. HBITMAP hBmp = (HBITMAP)::LoadImage(
  132. AfxGetInstanceHandle(), 
  133. pszID, IMAGE_BITMAP,
  134. 0,0, LR_CREATEDIBSECTION
  135. );
  136. if( hBmp == 0 ) 
  137. return FALSE;
  138. CBitmap bmp;
  139. bmp.Attach(hBmp);
  140. CClientDC cdc( CWnd::GetDesktopWindow() );
  141. BOOL bRet = CreateFromBitmap( &cdc, &bmp );
  142. bmp.DeleteObject();
  143. return bRet;
  144. }
  145. BOOL CDIBitmap :: Load( CFile* pFile ) {
  146.     ASSERT( pFile );
  147.     BOOL fReturn = TRUE;
  148.     try {
  149.         delete [] (BYTE*)m_pInfo;
  150.         delete [] m_pPixels;
  151.         m_pInfo = 0;
  152.         m_pPixels = 0;
  153.         DWORD       dwStart = pFile->GetPosition();
  154.         //
  155.         // Check to make sure we have a bitmap. The first two bytes must
  156.         // be 'B' and 'M'.
  157.         BITMAPFILEHEADER fileHeader;
  158.         pFile->Read(&fileHeader, sizeof(fileHeader));
  159.         if( fileHeader.bfType != 0x4D42 )
  160.             throw TEXT("Error:Unexpected file type, not a DIBn");
  161.         BITMAPINFOHEADER infoHeader;
  162.         pFile->Read( &infoHeader, sizeof(infoHeader) );
  163.         if( infoHeader.biSize != sizeof(infoHeader) )
  164.             throw TEXT("Error:OS2 PM BMP Format not supportedn");
  165.         // Store the sizes of the DIB structures
  166.         int cPaletteEntries = GetPalEntries( infoHeader );
  167.         int cColorTable = 256 * sizeof(RGBQUAD);
  168.         int cInfo = sizeof(BITMAPINFOHEADER) + cColorTable;
  169.         int cPixels = fileHeader.bfSize - fileHeader.bfOffBits;
  170.         //
  171.         // Allocate space for a new bitmap info header, and copy
  172.         // the info header that was loaded from the file. Read the
  173.         // the file and store the results in the color table.
  174.         m_pInfo = (BITMAPINFO*)new BYTE[cInfo];
  175.         memcpy( m_pInfo, &infoHeader, sizeof(BITMAPINFOHEADER) );
  176.         pFile->Read( ((BYTE*)m_pInfo) + sizeof(BITMAPINFOHEADER),
  177.                      cColorTable );
  178.         //
  179.         // Allocate space for the pixel area, and load the pixel
  180.         // info from the file.
  181.         m_pPixels = new BYTE[cPixels];
  182.         pFile->Seek(dwStart + fileHeader.bfOffBits, CFile::begin);
  183.         pFile->Read( m_pPixels, cPixels );
  184. CreatePalette();
  185. m_bIsPadded = TRUE;
  186. #ifdef _DEBUG
  187.     } catch( TCHAR * psz ) {
  188. TRACE( psz );
  189. #else
  190.     } catch( TCHAR * ) {
  191. #endif
  192.         fReturn = FALSE;
  193.     }
  194.     return fReturn;
  195. }
  196. BOOL CDIBitmap :: Load( const CString & strFilename ) {
  197. CFile file;
  198. if( file.Open( strFilename, CFile::modeRead ) )
  199. return Load( &file );
  200. return FALSE;
  201. }
  202. BOOL CDIBitmap :: Save( const CString & strFileName ) {
  203.     ASSERT(! strFileName.IsEmpty());
  204.     CFile File;
  205. if( !File.Open(strFileName, CFile::modeCreate|CFile::modeWrite) ) {
  206.     TRACE1("CDIBitmap::Save(): Failed to open file %s for writing.n", LPCSTR(strFileName));
  207.     return FALSE;
  208. }
  209.     return Save( &File );
  210. }      
  211. // Does not open or close pFile.  Assumes
  212. // caller will do it.
  213. BOOL CDIBitmap :: Save( CFile * pFile ) {
  214. ASSERT_VALID( pFile );
  215.     ASSERT( m_pInfo );
  216.     ASSERT( m_pPixels );
  217.     
  218.     BITMAPFILEHEADER bmfHdr;
  219.     
  220. DWORD dwPadWidth = PADWIDTH(GetWidth());
  221. // Make sure bitmap data is in padded format
  222. PadBits();
  223.     
  224.     bmfHdr.bfType = 0x4D42;
  225.     // initialize to BitmapInfo size
  226.     DWORD dwImageSize= m_pInfo->bmiHeader.biSize;
  227. // Add in palette size
  228.     WORD wColors = GetColorCount();
  229.     WORD wPaletteSize = (WORD)(wColors*sizeof(RGBQUAD));
  230.     dwImageSize += wPaletteSize;
  231.     
  232.     // Add in size of actual bit array
  233.     dwImageSize += PADWIDTH((GetWidth()) * DWORD(m_pInfo->bmiHeader.biBitCount)/8) * GetHeight();
  234.     m_pInfo->bmiHeader.biSizeImage = 0;
  235.     bmfHdr.bfSize = dwImageSize + sizeof(BITMAPFILEHEADER);
  236.     bmfHdr.bfReserved1 = 0;
  237.     bmfHdr.bfReserved2 = 0;
  238.     bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + m_pInfo->bmiHeader.biSize + wPaletteSize;
  239.     pFile->Write(&bmfHdr, sizeof(BITMAPFILEHEADER));
  240.     
  241.     pFile->Write(m_pInfo, sizeof(BITMAPINFO) + (wColors-1)*sizeof(RGBQUAD));
  242.     pFile->WriteHuge(m_pPixels,
  243. DWORD((dwPadWidth*(DWORD)m_pInfo->bmiHeader.biBitCount*GetHeight())/8) );
  244.   
  245. return TRUE;
  246. }
  247. BOOL CDIBitmap :: CreatePalette() {
  248. if( m_pPal )
  249. delete m_pPal;
  250. m_pPal = 0;
  251. ASSERT( m_pInfo );
  252. // We only need a palette, if there are <= 256 colors.
  253. // otherwise we would bomb the memory.
  254. if( m_pInfo->bmiHeader.biBitCount <= 8 )
  255. m_pPal = new CBmpPalette(this);
  256. return m_pPal ? TRUE : FALSE;
  257. }
  258. void CDIBitmap :: ClearPalette() {
  259. if( m_pPal )
  260. delete m_pPal;
  261. m_pPal = 0;
  262. }
  263. void CDIBitmap :: DrawDIB( CDC* pDC, int x, int y ) {
  264. DrawDIB( pDC, x, y, GetWidth(), GetHeight() );
  265. }
  266. //
  267. // DrawDib uses StretchDIBits to display the bitmap.
  268. void CDIBitmap :: DrawDIB( CDC* pDC, int x, int y, int width, int height ) {
  269.     ASSERT( pDC );
  270.     HDC     hdc = pDC->GetSafeHdc();
  271. CPalette * pOldPal = 0;
  272. if( m_pPal ) {
  273. pOldPal = pDC->SelectPalette( m_pPal, FALSE );
  274. pDC->RealizePalette();
  275. // Make sure to use the stretching mode best for color pictures
  276. pDC->SetStretchBltMode(COLORONCOLOR);
  277. }
  278.     if( m_pInfo )
  279.         StretchDIBits( hdc,
  280.                        x,
  281.                        y,
  282.                        width,
  283.                        height,
  284.                        0,
  285.                        0,
  286.                        GetWidth(),
  287.                        GetHeight(),
  288.                        GetPixelPtr(),
  289.                        GetHeaderPtr(),
  290.                        DIB_RGB_COLORS,
  291.                        SRCCOPY );
  292. if( m_pPal )
  293. pDC->SelectPalette( pOldPal, FALSE );
  294. }
  295. int CDIBitmap :: DrawDIB( CDC * pDC, CRect & rectDC, CRect & rectDIB ) {
  296.     ASSERT( pDC );
  297.     HDC     hdc = pDC->GetSafeHdc();
  298. CPalette * pOldPal = 0;
  299. if( m_pPal ) {
  300. pOldPal = pDC->SelectPalette( m_pPal, FALSE );
  301. pDC->RealizePalette();
  302. // Make sure to use the stretching mode best for color pictures
  303. pDC->SetStretchBltMode(COLORONCOLOR);
  304. }
  305. int nRet = 0;
  306.     if( m_pInfo )
  307. nRet = SetDIBitsToDevice(
  308. hdc, // device
  309. rectDC.left, // DestX
  310. rectDC.top, // DestY
  311. rectDC.Width(), // DestWidth
  312. rectDC.Height(), // DestHeight
  313. rectDIB.left, // SrcX
  314. GetHeight() -
  315. rectDIB.top -
  316. rectDIB.Height(), // SrcY
  317. 0, // StartScan
  318. GetHeight(), // NumScans
  319. GetPixelPtr(), // color data
  320. GetHeaderPtr(), // header data
  321. DIB_RGB_COLORS // color usage
  322. );
  323. if( m_pPal )
  324. pDC->SelectPalette( pOldPal, FALSE );
  325. return nRet;
  326. }
  327. BITMAPINFO * CDIBitmap :: GetHeaderPtr() const {
  328.     ASSERT( m_pInfo );
  329.     ASSERT( m_pPixels );
  330.     return m_pInfo;
  331. }
  332. RGBQUAD * CDIBitmap :: GetColorTablePtr() const {
  333.     ASSERT( m_pInfo );
  334.     ASSERT( m_pPixels );
  335.     RGBQUAD* pColorTable = 0;
  336.     if( m_pInfo != 0 ) {
  337.         int cOffset = sizeof(BITMAPINFOHEADER);
  338.         pColorTable = (RGBQUAD*)(((BYTE*)(m_pInfo)) + cOffset);
  339.     }
  340.     return pColorTable;
  341. }
  342. BYTE * CDIBitmap :: GetPixelPtr() const {
  343. //    ASSERT( m_pInfo );
  344. //    ASSERT( m_pPixels );
  345.     return m_pPixels;
  346. }
  347. int CDIBitmap :: GetWidth() const {
  348.     ASSERT( m_pInfo );
  349.     return m_pInfo->bmiHeader.biWidth;
  350. }
  351. int CDIBitmap :: GetHeight() const {
  352.     ASSERT( m_pInfo );
  353.     return m_pInfo->bmiHeader.biHeight;
  354. }
  355. WORD CDIBitmap :: GetColorCount() const {
  356. ASSERT( m_pInfo );
  357. switch( m_pInfo->bmiHeader.biBitCount ) {
  358. case 1: return 2;
  359. case 4: return 16;
  360. case 8: return 256;
  361. default: return 0;
  362. }
  363. }
  364. int CDIBitmap :: GetPalEntries() const {
  365.     ASSERT( m_pInfo );
  366.     return GetPalEntries( *(BITMAPINFOHEADER*)m_pInfo );
  367. }
  368. int CDIBitmap :: GetPalEntries( BITMAPINFOHEADER& infoHeader ) const {
  369. int nReturn;
  370. if( infoHeader.biClrUsed == 0 )
  371. nReturn = ( 1 << infoHeader.biBitCount );
  372. else
  373. nReturn = infoHeader.biClrUsed;
  374. return nReturn;
  375. }
  376. DWORD CDIBitmap :: GetBitsPerPixel() const {
  377. ASSERT( m_pInfo );
  378. return m_pInfo->bmiHeader.biBitCount;
  379. }
  380. DWORD CDIBitmap :: LastByte( DWORD dwBitsPerPixel, DWORD dwPixels ) const {
  381. register DWORD dwBits = dwBitsPerPixel * dwPixels;
  382. register DWORD numBytes  = dwBits / 8;
  383. register DWORD extraBits = dwBits - numBytes * 8;
  384.     return (extraBits % 8) ? numBytes+1 : numBytes;
  385. }
  386. DWORD CDIBitmap :: GetBytesPerLine( DWORD dwBitsPerPixel, DWORD dwWidth ) const {
  387. DWORD dwBits = dwBitsPerPixel * dwWidth;
  388. if( (dwBits % 32) == 0 )
  389. return (dwBits/8);  // already DWORD aligned, no padding needed
  390. DWORD dwPadBits = 32 - (dwBits % 32);
  391. return (dwBits/8 + dwPadBits/8 + (((dwPadBits % 8) > 0) ? 1 : 0));
  392. }
  393. BOOL CDIBitmap :: PadBits() {
  394. if( m_bIsPadded )
  395. return TRUE;
  396.     // dwAdjust used when bits per pixel spreads over more than 1 byte
  397.     DWORD dwAdjust = 1, dwOffset = 0, dwPadOffset=0;
  398. BOOL bIsOdd = FALSE;
  399.     
  400. dwPadOffset = GetBytesPerLine(GetBitsPerPixel(), GetWidth());
  401. dwOffset = LastByte(GetBitsPerPixel(), GetWidth());
  402. if( dwPadOffset == dwOffset )
  403. return TRUE;
  404.     BYTE * pTemp = new BYTE [GetWidth()*dwAdjust];
  405.     if( !pTemp ) {
  406. TRACE1("CDIBitmap::PadBits(): could not allocate row of width %d.n", GetWidth());
  407. return FALSE;
  408. }
  409.     
  410.     // enough space has already been allocated for the bit array to
  411.     // include the padding, so we just need to shift rows around.
  412.     // This will pad each "row" on a DWORD alignment.
  413.     for( DWORD row = GetHeight()-1 ; row>0 ; --row ) {
  414.     CopyMemory((void *)pTemp, (const void *)(m_pPixels + (row*dwOffset)), dwOffset );
  415.     CopyMemory((void *)(m_pPixels + (row*dwPadOffset)), (const void *)pTemp, dwOffset);
  416. }
  417.     delete [] pTemp;
  418.     
  419.     return TRUE;
  420. }
  421. BOOL CDIBitmap::UnPadBits() {
  422. if( ! m_bIsPadded )
  423. return TRUE;
  424. DWORD dwAdjust = 1;
  425. BOOL bIsOdd = FALSE;
  426. DWORD dwPadOffset = GetBytesPerLine(GetBitsPerPixel(), GetWidth());
  427. DWORD dwOffset = LastByte(GetBitsPerPixel(), GetWidth());
  428.     BYTE * pTemp = new BYTE [dwOffset];
  429.     if( !pTemp ) {
  430. TRACE1("CDIBitmap::UnPadBits() could not allocate row of width %d.n", GetWidth());
  431. return FALSE;
  432. }
  433.     // enough space has already been allocated for the bit array to
  434.     // include the padding, so we just need to shift rows around.
  435.     for( DWORD row=1 ; row < DWORD(GetHeight()); ++row ) {
  436. CopyMemory((void *)pTemp, (const void *)(m_pPixels + row*(dwPadOffset)), dwOffset);
  437.     CopyMemory((void *)(m_pPixels + (row*dwOffset)), (const void *)pTemp, dwOffset);
  438. }
  439.     delete [] pTemp;
  440.     
  441.     return TRUE;
  442. }