📄 dib.cpp
字号:
// Dib.cpp: implementation of the CDib class.
//
//////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// dib.cpp
//
#include "stdafx.h"
#include "dib.h"
#include <windowsx.h>
#include <afxadv.h> //CSharefile
#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;
CRect r1,r2;
r1.top=0;
r1.left=0;
r1.bottom=Height()-1;
r1.right=Width()-1;
r2.top=0;
r2.left=0;
r2.bottom=Height()-1;
r2.right=Width()-1;
if(lpDCRect==NULL) lpDCRect=&r1;
if(lpDIBRect==NULL) lpDIBRect=&r2;
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 ints 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 ints 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 ints, we may end up writing out a few too
// many ints 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 dwintsSaved = sizeof(BITMAPFILEHEADER);
// Write the DIB header
UINT nCount = sizeof(BITMAPINFO) + (NumColors()-1)*sizeof(RGBQUAD);
dwintsSaved += nCount;
file.Write(m_pBMI, nCount);
// Write the DIB bits
DWORD dwints = m_pBMI->bmiHeader.biBitCount * Width();
// Calculate the number of ints per line
if (dwints%32 == 0)
dwints /= 8;
else
dwints = dwints/8 + (32-dwints%32)/8 + (((32-dwints%32)%8 > 0) ? 1 : 0);
nCount = dwints * Height();
dwintsSaved += nCount;
file.WriteHuge(m_pBits, nCount);
return dwintsSaved;
}
/*************************************************************************
Function: Read (CFile&)
Purpose: Reads in the specified DIB file into a global chunk of
memory.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -