DIB.CPP
上传用户:zch19780
上传日期:2007-01-02
资源大小:8k
文件大小:15k
- /////////////////////////////////////////////////////////////////////////////
- // Copyright (C) 1998 by Jorge Lodos
- // All rights reserved
- //
- // Distribute and use freely, except:
- // 1. Don't alter or remove this notice.
- // 2. Mark the changes you made
- //
- // Send bug reports, bug fixes, enhancements, requests, etc. to:
- // lodos@cigb.edu.cu
- /////////////////////////////////////////////////////////////////////////////
- // dib.cpp
- //
- #include "stdafx.h"
- #include "dib.h"
- #include <windowsx.h>
- #include <afxadv.h>
- #include <io.h>
- #include <errno.h>
- /////////////////////////////////////////////////////////////////////////////
- // CDib
- IMPLEMENT_DYNAMIC(CDib, CObject)
- CDib::CDib()
- {
- m_pBMI = NULL;
- m_pBits = NULL;
- m_pPalette = NULL;
- }
- CDib::~CDib()
- {
- Free();
- }
- void CDib::Free()
- {
- // Make sure all member data that might have been allocated is freed.
- if (m_pBits)
- {
- GlobalFreePtr(m_pBits);
- m_pBits = NULL;
- }
- if (m_pBMI)
- {
- GlobalFreePtr(m_pBMI);
- m_pBMI = NULL;
- }
- if (m_pPalette)
- {
- m_pPalette->DeleteObject();
- delete m_pPalette;
- m_pPalette = NULL;
- }
- }
- /*************************************************************************
- *
- * Paint()
- *
- * Parameters:
- *
- * HDC hDC - DC to do output to
- *
- * LPRECT lpDCRect - rectangle on DC to do output to
- *
- * LPRECT lpDIBRect - rectangle of DIB to output into lpDCRect
- *
- * CPalette* pPal - pointer to CPalette containing DIB's palette
- *
- * Return Value:
- *
- * BOOL - TRUE if DIB was drawn, FALSE otherwise
- *
- * Description:
- * Painting routine for a DIB. Calls StretchDIBits() or
- * SetDIBitsToDevice() to paint the DIB. The DIB is
- * output to the specified DC, at the coordinates given
- * in lpDCRect. The area of the DIB to be output is
- * given by lpDIBRect.
- *
- ************************************************************************/
- BOOL CDib::Paint(HDC hDC, LPRECT lpDCRect, LPRECT lpDIBRect) const
- {
- if (!m_pBMI)
- return FALSE;
- HPALETTE hPal = NULL; // Our DIB's palette
- HPALETTE hOldPal = NULL; // Previous palette
- // Get the DIB's palette, then select it into DC
- if (m_pPalette != NULL)
- {
- hPal = (HPALETTE) m_pPalette->m_hObject;
- // Select as background since we have
- // already realized in forground if needed
- hOldPal = ::SelectPalette(hDC, hPal, TRUE);
- }
- /* Make sure to use the stretching mode best for color pictures */
- ::SetStretchBltMode(hDC, COLORONCOLOR);
- /* Determine whether to call StretchDIBits() or SetDIBitsToDevice() */
- BOOL bSuccess;
- if ((RECTWIDTH(lpDCRect) == RECTWIDTH(lpDIBRect)) &&
- (RECTHEIGHT(lpDCRect) == RECTHEIGHT(lpDIBRect)))
- bSuccess = ::SetDIBitsToDevice(hDC, // hDC
- lpDCRect->left, // DestX
- lpDCRect->top, // DestY
- RECTWIDTH(lpDCRect), // nDestWidth
- RECTHEIGHT(lpDCRect), // nDestHeight
- lpDIBRect->left, // SrcX
- (int)Height() -
- lpDIBRect->top -
- RECTHEIGHT(lpDIBRect), // SrcY
- 0, // nStartScan
- (WORD)Height(), // nNumScans
- m_pBits, // lpBits
- m_pBMI, // lpBitsInfo
- DIB_RGB_COLORS); // wUsage
- else
- bSuccess = ::StretchDIBits(hDC, // hDC
- lpDCRect->left, // DestX
- lpDCRect->top, // DestY
- RECTWIDTH(lpDCRect), // nDestWidth
- RECTHEIGHT(lpDCRect), // nDestHeight
- lpDIBRect->left, // SrcX
- lpDIBRect->top, // SrcY
- RECTWIDTH(lpDIBRect), // wSrcWidth
- RECTHEIGHT(lpDIBRect), // wSrcHeight
- m_pBits, // lpBits
- m_pBMI, // lpBitsInfo
- DIB_RGB_COLORS, // wUsage
- SRCCOPY); // dwROP
- /* Reselect old palette */
- if (hOldPal != NULL)
- {
- ::SelectPalette(hDC, hOldPal, TRUE);
- }
- return bSuccess;
- }
- /*************************************************************************
- *
- * CreatePalette()
- *
- * Return Value:
- *
- * TRUE if succesfull, FALSE otherwise
- *
- * Description:
- *
- * This function creates a palette from a DIB by allocating memory for the
- * logical palette, reading and storing the colors from the DIB's color table
- * into the logical palette, creating a palette from this logical palette,
- * and then returning the palette's handle. This allows the DIB to be
- * displayed using the best possible colors (important for DIBs with 256 or
- * more colors).
- *
- ************************************************************************/
- BOOL CDib::CreatePalette()
- {
- if (!m_pBMI)
- return FALSE;
- //get the number of colors in the DIB
- WORD wNumColors = NumColors();
- if (wNumColors != 0)
- {
- // allocate memory block for logical palette
- HANDLE hLogPal = ::GlobalAlloc(GHND, sizeof(LOGPALETTE) + sizeof(PALETTEENTRY)*wNumColors);
- // if not enough memory, clean up and return NULL
- if (hLogPal == 0)
- return FALSE;
- LPLOGPALETTE lpPal = (LPLOGPALETTE)::GlobalLock((HGLOBAL)hLogPal);
- // set version and number of palette entries
- lpPal->palVersion = PALVERSION;
- lpPal->palNumEntries = (WORD)wNumColors;
- for (int i = 0; i < (int)wNumColors; i++)
- {
- lpPal->palPalEntry[i].peRed = m_pBMI->bmiColors[i].rgbRed;
- lpPal->palPalEntry[i].peGreen = m_pBMI->bmiColors[i].rgbGreen;
- lpPal->palPalEntry[i].peBlue = m_pBMI->bmiColors[i].rgbBlue;
- lpPal->palPalEntry[i].peFlags = 0;
- }
- /* create the palette and get handle to it */
- if (m_pPalette)
- {
- m_pPalette->DeleteObject();
- delete m_pPalette;
- }
- m_pPalette = new CPalette;
- BOOL bResult = m_pPalette->CreatePalette(lpPal);
- ::GlobalUnlock((HGLOBAL) hLogPal);
- ::GlobalFree((HGLOBAL) hLogPal);
- return bResult;
- }
- return TRUE;
- }
- /*************************************************************************
- *
- * Width()
- *
- * Return Value:
- *
- * DWORD - width of the DIB
- *
- * Description:
- *
- * This function gets the width of the DIB from the BITMAPINFOHEADER
- * width field
- *
- ************************************************************************/
- DWORD CDib::Width() const
- {
- if (!m_pBMI)
- return 0;
- /* return the DIB width */
- return m_pBMI->bmiHeader.biWidth;
- }
- /*************************************************************************
- *
- * Height()
- *
- * Return Value:
- *
- * DWORD - height of the DIB
- *
- * Description:
- *
- * This function gets the height of the DIB from the BITMAPINFOHEADER
- * height field
- *
- ************************************************************************/
- DWORD CDib::Height() const
- {
- if (!m_pBMI)
- return 0;
-
- /* return the DIB height */
- return m_pBMI->bmiHeader.biHeight;
- }
- /*************************************************************************
- *
- * PaletteSize()
- *
- * Return Value:
- *
- * WORD - size of the color palette of the DIB
- *
- * Description:
- *
- * This function gets the size required to store the DIB's palette by
- * multiplying the number of colors by the size of an RGBQUAD
- *
- ************************************************************************/
- WORD CDib::PaletteSize() const
- {
- if (!m_pBMI)
- return 0;
- return NumColors() * sizeof(RGBQUAD);
- }
- /*************************************************************************
- *
- * NumColors()
- *
- * Return Value:
- *
- * WORD - number of colors in the color table
- *
- * Description:
- *
- * This function calculates the number of colors in the DIB's color table
- * by finding the bits per pixel for the DIB (whether Win3.0 or other-style
- * DIB). If bits per pixel is 1: colors=2, if 4: colors=16, if 8: colors=256,
- * if 24, no colors in color table.
- *
- ************************************************************************/
- WORD CDib::NumColors() const
- {
- if (!m_pBMI)
- return 0;
- WORD wBitCount; // DIB bit count
- /* The number of colors in the color table can be less than
- * the number of bits per pixel allows for (i.e. lpbi->biClrUsed
- * can be set to some value).
- * If this is the case, return the appropriate value.
- */
- DWORD dwClrUsed;
- dwClrUsed = m_pBMI->bmiHeader.biClrUsed;
- if (dwClrUsed != 0)
- return (WORD)dwClrUsed;
- /* Calculate the number of colors in the color table based on
- * the number of bits per pixel for the DIB.
- */
- wBitCount = m_pBMI->bmiHeader.biBitCount;
- /* return number of colors based on bits per pixel */
- switch (wBitCount)
- {
- case 1:
- return 2;
- case 4:
- return 16;
- case 8:
- return 256;
- default:
- return 0;
- }
- }
- /*************************************************************************
- *
- * Save()
- *
- * Saves the specified DIB into the specified CFile. The CFile
- * is opened and closed by the caller.
- *
- * Parameters:
- *
- * CFile& file - open CFile used to save DIB
- *
- * Return value: Number of saved bytes or CFileException
- *
- *************************************************************************/
- DWORD CDib::Save(CFile& file) const
- {
- BITMAPFILEHEADER bmfHdr; // Header for Bitmap file
- DWORD dwDIBSize;
- if (m_pBMI == NULL)
- return 0;
- // Fill in the fields of the file header
- // Fill in file type (first 2 bytes must be "BM" for a bitmap)
- bmfHdr.bfType = DIB_HEADER_MARKER; // "BM"
- // Calculating the size of the DIB is a bit tricky (if we want to
- // do it right). The easiest way to do this is to call GlobalSize()
- // on our global handle, but since the size of our global memory may have
- // been padded a few bytes, we may end up writing out a few too
- // many bytes to the file (which may cause problems with some apps).
- //
- // So, instead let's calculate the size manually (if we can)
- //
- // First, find size of header plus size of color table. Since the
- // first DWORD in both BITMAPINFOHEADER and BITMAPCOREHEADER conains
- // the size of the structure, let's use this.
- dwDIBSize = *(LPDWORD)&m_pBMI->bmiHeader + PaletteSize(); // Partial Calculation
- // Now calculate the size of the image
- if ((m_pBMI->bmiHeader.biCompression == BI_RLE8) || (m_pBMI->bmiHeader.biCompression == BI_RLE4))
- {
- // It's an RLE bitmap, we can't calculate size, so trust the
- // biSizeImage field
- dwDIBSize += m_pBMI->bmiHeader.biSizeImage;
- }
- else
- {
- DWORD dwBmBitsSize; // Size of Bitmap Bits only
- // It's not RLE, so size is Width (DWORD aligned) * Height
- dwBmBitsSize = WIDTHBYTES((m_pBMI->bmiHeader.biWidth)*((DWORD)m_pBMI->bmiHeader.biBitCount)) * m_pBMI->bmiHeader.biHeight;
- dwDIBSize += dwBmBitsSize;
- // Now, since we have calculated the correct size, why don't we
- // fill in the biSizeImage field (this will fix any .BMP files which
- // have this field incorrect).
- m_pBMI->bmiHeader.biSizeImage = dwBmBitsSize;
- }
- // Calculate the file size by adding the DIB size to sizeof(BITMAPFILEHEADER)
- bmfHdr.bfSize = dwDIBSize + sizeof(BITMAPFILEHEADER);
- bmfHdr.bfReserved1 = 0;
- bmfHdr.bfReserved2 = 0;
- /*
- * Now, calculate the offset the actual bitmap bits will be in
- * the file -- It's the Bitmap file header plus the DIB header,
- * plus the size of the color table.
- */
- bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + m_pBMI->bmiHeader.biSize + PaletteSize();
- // Write the file header
- file.Write((LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER));
- DWORD dwBytesSaved = sizeof(BITMAPFILEHEADER);
- // Write the DIB header
- UINT nCount = sizeof(BITMAPINFO) + (NumColors()-1)*sizeof(RGBQUAD);
- dwBytesSaved += nCount;
- file.Write(m_pBMI, nCount);
-
- // Write the DIB bits
- DWORD dwBytes = m_pBMI->bmiHeader.biBitCount * Width();
- // Calculate the number of bytes per line
- if (dwBytes%32 == 0)
- dwBytes /= 8;
- else
- dwBytes = dwBytes/8 + (32-dwBytes%32)/8 + (((32-dwBytes%32)%8 > 0) ? 1 : 0);
- nCount = dwBytes * Height();
- dwBytesSaved += nCount;
- file.WriteHuge(m_pBits, nCount);
- return dwBytesSaved;
- }
- /*************************************************************************
- Function: Read (CFile&)
- Purpose: Reads in the specified DIB file into a global chunk of
- memory.
- Returns: Number of read bytes.
- *************************************************************************/
- DWORD CDib::Read(CFile& file)
- {
- // Ensures no memory leaks will occur
- Free();
-
- BITMAPFILEHEADER bmfHeader;
- // Go read the DIB file header and check if it's valid.
- if (file.Read((LPSTR)&bmfHeader, sizeof(bmfHeader)) != sizeof(bmfHeader))
- return 0;
- if (bmfHeader.bfType != DIB_HEADER_MARKER)
- return 0;
- DWORD dwReadBytes = sizeof(bmfHeader);
- // Allocate memory for DIB
- m_pBMI = (LPBITMAPINFO)GlobalAllocPtr(GHND, bmfHeader.bfOffBits-sizeof(BITMAPFILEHEADER) + 256*sizeof(RGBQUAD));
- if (m_pBMI == 0)
- return 0;
- // Read header.
- if (file.Read(m_pBMI, bmfHeader.bfOffBits-sizeof(BITMAPFILEHEADER)) != (UINT)(bmfHeader.bfOffBits-sizeof(BITMAPFILEHEADER)))
- {
- GlobalFreePtr(m_pBMI);
- m_pBMI = NULL;
- return 0;
- }
- dwReadBytes += bmfHeader.bfOffBits-sizeof(BITMAPFILEHEADER);
- DWORD dwLength = file.GetLength();
- // Go read the bits.
- m_pBits = (LPBYTE)GlobalAllocPtr(GHND, dwLength - bmfHeader.bfOffBits);
- if (m_pBits == 0)
- {
- GlobalFreePtr(m_pBMI);
- m_pBMI = NULL;
- return 0;
- }
-
- if (file.ReadHuge(m_pBits, dwLength-bmfHeader.bfOffBits) != (dwLength - bmfHeader.bfOffBits))
- {
- GlobalFreePtr(m_pBMI);
- m_pBMI = NULL;
- GlobalFreePtr(m_pBits);
- m_pBits = NULL;
- return 0;
- }
- dwReadBytes += dwLength - bmfHeader.bfOffBits;
- CreatePalette();
- return dwReadBytes;
- }
- #ifdef _DEBUG
- void CDib::Dump(CDumpContext& dc) const
- {
- CObject::Dump(dc);
- }
- #endif
- //////////////////////////////////////////////////////////////////////////
- //// Clipboard support
- //---------------------------------------------------------------------
- //
- // Function: CopyToHandle
- //
- // Purpose: Makes a copy of the DIB to a global memory block. Returns
- // a handle to the new memory block (NULL on error).
- //
- // Returns: Handle to new global memory block.
- //
- //---------------------------------------------------------------------
- HGLOBAL CDib::CopyToHandle() const
- {
- CSharedFile file;
- try
- {
- if (Save(file)==0)
- return 0;
- }
- catch (CFileException* e)
- {
- e->Delete();
- return 0;
- }
-
- return file.Detach();
- }
- //---------------------------------------------------------------------
- //
- // Function: ReadFromHandle
- //
- // Purpose: Initializes from the given global memory block.
- //
- // Returns: Number of read bytes.
- //
- //---------------------------------------------------------------------
- DWORD CDib::ReadFromHandle(HGLOBAL hGlobal)
- {
- CSharedFile file;
- file.SetHandle(hGlobal, FALSE);
- DWORD dwResult = Read(file);
- file.Detach();
- return dwResult;
- }
- //////////////////////////////////////////////////////////////////////////
- //// Serialization support
- void CDib::Serialize(CArchive& ar)
- {
- CFile* pFile = ar.GetFile();
- ASSERT(pFile != NULL);
- if (ar.IsStoring())
- { // storing code
- Save(*pFile);
- }
- else
- { // loading code
- Read(*pFile);
- }
- }