|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1993.
//
// File: bmpfile.cxx
//
// Contents: CBitmapFile implementation
//
// Classes:
//
// Functions:
//
// History: 4-23-94 KirtD Created
//
//----------------------------------------------------------------------------
#include "headers.hxx"
#pragma hdrstop
//+---------------------------------------------------------------------------
//
// Member: CBitmapFile::CBitmapFile
//
// Synopsis: Constructor
//
// Arguments: (none)
//
// Returns: nothing
//
// History: 4-23-94 KirtD Created
//
// Notes:
//
//----------------------------------------------------------------------------
CBitmapFile::CBitmapFile () { //
// Initialize private members
//
//
// The name
//
_pszBitmapFile[0] = '\0'; _cBitmapFile = 0;
//
// The bitmap information
//
_cbi = 0; _pbi = NULL;
//
// The bits
//
_cbData = 0; _pbData = NULL; }
//+---------------------------------------------------------------------------
//
// Member: CBitmapFile::~CBitmapFile
//
// Synopsis: Destructor
//
// Arguments: (none)
//
// Returns: nothing
//
// History: 4-23-94 KirtD Created
//
// Notes:
//
//----------------------------------------------------------------------------
CBitmapFile::~CBitmapFile () { //
// Delete any possibly allocated things
//
delete _pbi; delete _pbData; }
//+---------------------------------------------------------------------------
//
// Member: CBitmapFile::LoadBitmapFile
//
// Synopsis: loads a bitmap file
//
// Arguments: [pszFile] -- the file
//
// Returns: HRESULT
//
// History: 4-23-94 KirtD Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CBitmapFile::LoadBitmapFile (LPSTR pszFile) { HRESULT hr = ResultFromScode(S_OK); HANDLE hFile = INVALID_HANDLE_VALUE; HANDLE hMap = INVALID_HANDLE_VALUE; DWORD dwFileSizeLow = 0; DWORD dwFileSizeHigh = 0; LPBYTE pbuffer = NULL;
//
// First open the file
//
hFile = CreateFileA(pszFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) { hr = HRESULT_FROM_WIN32(GetLastError()); }
//
// Get the size of the file
//
if (SUCCEEDED(hr)) { dwFileSizeLow = GetFileSize(hFile, &dwFileSizeHigh); if ((dwFileSizeLow == 0xFFFFFFFF) && (GetLastError() != NO_ERROR)) { hr = HRESULT_FROM_WIN32(GetLastError()); } else if (dwFileSizeHigh != 0) { //
// Bitmap files can't be greater than 4G
//
hr = ResultFromScode(E_FAIL); } }
//
// Create a file mapping object on the file
//
if (SUCCEEDED(hr)) { hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, dwFileSizeLow, NULL);
if (hMap == INVALID_HANDLE_VALUE) { hr = HRESULT_FROM_WIN32(GetLastError()); } }
//
// Now map a view of the file into our address space
//
if (SUCCEEDED(hr)) { pbuffer = (LPBYTE)MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0); if (pbuffer == NULL) { hr = HRESULT_FROM_WIN32(GetLastError()); } }
//
// Get the bitmap data from the buffer
//
if (SUCCEEDED(hr)) { hr = _GetBitmapDataFromBuffer(pbuffer, (ULONG)dwFileSizeLow); }
//
// Record the file name
//
if (SUCCEEDED(hr)) { ULONG cFile;
//
// Get the length of the file name
//
cFile = strlen(pszFile);
//
// Check to see that our buffer is big enough and then copy
// it. NOTE that I can use sizeof here since the buffer is
// in characters which are 1 byte.
//
if (cFile < sizeof(_pszBitmapFile)) { strcpy(_pszBitmapFile, pszFile); _cBitmapFile = cFile; } else { hr = ResultFromScode(E_FAIL); } }
//
// Cleanup
//
if (hMap != INVALID_HANDLE_VALUE) { CloseHandle(hMap); }
if (hFile != INVALID_HANDLE_VALUE) { CloseHandle(hFile); }
return(hr); }
//+---------------------------------------------------------------------------
//
// Member: CBitmapFile::GetBitmapFileName
//
// Synopsis: gets the file name used to set the bitmap
//
// Arguments: [pszFile] -- the file
// [cChar] -- the length of the buffer in characters
//
// Returns: HRESULT
//
// History: 4-23-94 KirtD Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CBitmapFile::GetBitmapFileName (LPSTR pszFile, ULONG cChar) const { //
// Check the length of the receiving buffer, making sure the buffer size
// includes the null terminator
//
if (cChar <= _cBitmapFile) { return(ResultFromScode(E_INVALIDARG)); }
//
// Copy the string
//
strcpy(pszFile, _pszBitmapFile);
return(ResultFromScode(S_OK)); }
//+---------------------------------------------------------------------------
//
// Member: CBitmapFile::GetBitmapFileNameLength
//
// Synopsis: returns _cBitmapFile
//
// Arguments: (none)
//
// Returns: ULONG
//
// History: 4-23-94 KirtD Created
//
// Notes:
//
//----------------------------------------------------------------------------
ULONG CBitmapFile::GetBitmapFileNameLength () const { return(_cBitmapFile); }
//+---------------------------------------------------------------------------
//
// Member: CBitmapFile::GetDIBHeight
//
// Synopsis: gets the height in pixels of the DIB
//
// Arguments: (none)
//
// Returns: LONG
//
// History: 4-23-94 KirtD Created
//
// Notes:
//
//----------------------------------------------------------------------------
LONG CBitmapFile::GetDIBHeight () const { if (_pbi) { return(_pbi->bmiHeader.biHeight); } else { return(0); } }
//+---------------------------------------------------------------------------
//
// Member: CBitmapFile::GetDIBWidth
//
// Synopsis: gets the width in pixels of the DIB
//
// Arguments: (none)
//
// Returns: LONG
//
// History: 4-23-94 KirtD Created
//
// Notes:
//
//----------------------------------------------------------------------------
LONG CBitmapFile::GetDIBWidth () const { if (_pbi) { return(_pbi->bmiHeader.biWidth); } else { return(0); } }
//+---------------------------------------------------------------------------
//
// Member: CBitmapFile::GetLogicalPalette
//
// Synopsis: gets the logical palette from the DIB
//
// Arguments: [pplogpal] -- logical palette goes here
//
// Returns: HRESULT
//
// History: 4-23-94 KirtD Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CBitmapFile::GetLogicalPalette (LPLOGPALETTE *pplogpal) const { HRESULT hr = ResultFromScode(S_OK); LOGPALETTE *plogpal = NULL; WORD cPalEntry; LPMALLOC pMalloc = NULL;
//
// First check to see if we have been initialized with a bitmap
//
if (_pbi == NULL) { return(ResultFromScode(E_FAIL)); }
//
// Check to see if this bit count allows a palette
//
if (HasPaletteData() == FALSE) { return(ResultFromScode(E_FAIL)); }
//
// NOTE: We are about to get the number of palette entries we
// need to allocate, we do NOT use biClrUsed since we
// know that if this field was set the bitmap would
// not have been loaded, see BUGBUG in
// _GetBitmapDataFromBuffer notes section. This is
// probably a good candidate for an assert.
//
//
// Get the palette entries
//
cPalEntry = (WORD) (1 << _pbi->bmiHeader.biBitCount);
//
// Allocate a LOGPALETTE
//
hr = CoGetMalloc(MEMCTX_TASK, &pMalloc); if (SUCCEEDED(hr)) { plogpal = (LOGPALETTE *)pMalloc->Alloc(sizeof(LOGPALETTE)+ ((cPalEntry-1)* sizeof(PALETTEENTRY)));
if (plogpal == NULL) { hr = ResultFromScode(E_OUTOFMEMORY); } }
//
// Copy the palette information
//
if (SUCCEEDED(hr)) { ULONG cCount;
plogpal->palVersion = 0x300; plogpal->palNumEntries = cPalEntry;
for (cCount = 0; cCount < cPalEntry; cCount++) { plogpal->palPalEntry[cCount].peRed = _pbi->bmiColors[cCount].rgbRed; plogpal->palPalEntry[cCount].peGreen = _pbi->bmiColors[cCount].rgbGreen; plogpal->palPalEntry[cCount].peBlue = _pbi->bmiColors[cCount].rgbBlue; plogpal->palPalEntry[cCount].peFlags = PC_NOCOLLAPSE; }
*pplogpal = plogpal; }
//
// Cleanup
//
if (pMalloc) { pMalloc->Release(); }
return(hr); }
//+---------------------------------------------------------------------------
//
// Member: CBitmapFile::CreateDIBInHGlobal
//
// Synopsis: creates a DIB i.e. info and data in a GlobalAlloc'd buffer
//
// Arguments: [phGlobal] -- handle goes here
//
// Returns: HRESULT
//
// History: 5-06-94 KirtD Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CBitmapFile::CreateDIBInHGlobal (HGLOBAL *phGlobal) const { HRESULT hr = ResultFromScode(S_OK); ULONG cb = 0; LPBYTE pb = NULL; HGLOBAL hGlobal = NULL; ULONG cbPalEntry = 0;
//
// Check to see if we are initialized
//
if (_pbi == NULL) { return(ResultFromScode(E_FAIL)); }
//
// The size to allocate for the data must be calculated
// from the following ...
//
//
// The size of the bitmap info plus the size of the data
//
cb = _cbi + _cbData;
//
// Allocate
//
hGlobal = GlobalAlloc(GHND, cb); if (hGlobal == NULL) { hr = HRESULT_FROM_WIN32(GetLastError()); }
//
// Lock the handle
//
if (SUCCEEDED(hr)) { pb = (LPBYTE)GlobalLock(hGlobal); if (pb == NULL) { hr = HRESULT_FROM_WIN32(GetLastError()); } }
//
// Copy the information
//
if (SUCCEEDED(hr)) { //
// First the bitmap info
//
memcpy(pb, _pbi, _cbi);
//
// Move pointer but if there is no palette compensate
// for the extra RGBQUAD
//
if (_pbi->bmiHeader.biBitCount == BMP_24_BITSPERPIXEL) { pb += (_cbi - sizeof(RGBQUAD)); } else { pb += _cbi; }
//
// Now the bits
//
memcpy(pb, _pbData, _cbData); }
//
// Cleanup
//
//
// If we locked the handle, unlock it
//
if (pb) { GlobalUnlock(hGlobal); }
//
// If we succeeded, set the out parameter, if we failed and
// we had allocated the hGlobal, free it
//
if (SUCCEEDED(hr)) { *phGlobal = hGlobal; } else if (hGlobal) { GlobalFree(hGlobal); }
return(hr); }
//+---------------------------------------------------------------------------
//
// Member: CBitmapFile::HasPaletteData
//
// Synopsis: returns whether or not the dib has palette data
//
// Arguments: (none)
//
// Returns: BOOL
//
// History: 5-16-94 kirtd Created
//
// Notes:
//
//----------------------------------------------------------------------------
BOOL CBitmapFile::HasPaletteData () const { //
// If we are not initialized return FALSE
//
if (_pbi == NULL) { return(FALSE); }
//
// If we are a 24, 16 or 32 bpp DIB then we do not have
// palette data
//
// BUGBUG: The case where biClrUsed is set is not dealt
// with
//
if ((_pbi->bmiHeader.biBitCount == BMP_24_BITSPERPIXEL) || (_pbi->bmiHeader.biBitCount == BMP_16_BITSPERPIXEL) || (_pbi->bmiHeader.biBitCount == BMP_32_BITSPERPIXEL)) { return(FALSE); }
//
// Otherwise we do have palette data
//
return(TRUE); }
//+---------------------------------------------------------------------------
//
// Member: CBitmapFile::GetDIBBits
//
// Synopsis: gets the bits
//
// Arguments: (none)
//
// Returns: LPBYTE
//
// History: 5-02-94 KirtD Created
//
// Notes:
//
//----------------------------------------------------------------------------
LPBYTE CBitmapFile::GetDIBBits () { return(_pbData); }
//+---------------------------------------------------------------------------
//
// Member: CBitmapFile::GetBitmapInfo
//
// Synopsis: gets the bitmap info pointer
//
// Arguments: (none)
//
// Returns: LPBITMAPINFO
//
// History: 5-14-94 kirtd Created
//
// Notes:
//
//----------------------------------------------------------------------------
LPBITMAPINFO CBitmapFile::GetBitmapInfo () { return(_pbi); }
//+---------------------------------------------------------------------------
//
// Member: CBitmapFile::_GetBitmapDataFromBuffer
//
// Synopsis: gets the bitmap data from the given buffer
//
// Arguments: [pbuffer] -- the buffer
// [cb] -- the buffer size
//
// Returns: HRESULT
//
// History: 4-23-94 KirtD Created
//
// Notes: BUGBUG: If biClrUsed is set the bitmap is not loaded
//
//----------------------------------------------------------------------------
HRESULT CBitmapFile::_GetBitmapDataFromBuffer (LPBYTE pbuffer, ULONG cb) { HRESULT hr = ResultFromScode(S_OK); BITMAPFILEHEADER bmfh; BITMAPCOREHEADER *pbch; BITMAPINFOHEADER bih; LPBYTE pbStart; ULONG cbi = 0; ULONG cbData; LPBITMAPINFO pbi = NULL; LPBYTE pbData = NULL; DWORD dwSizeOfHeader;
//
// Record the starting position
//
pbStart = pbuffer;
//
// First validate the buffer for size
//
if (cb < sizeof(BITMAPFILEHEADER)) { return(ResultFromScode(E_FAIL)); }
//
// Now get the bitmap file header
//
memcpy(&bmfh, pbuffer, sizeof(BITMAPFILEHEADER));
//
// Validate the information
//
hr = _ValidateBitmapFileHeader (&bmfh, cb);
//
// Get the next 4 bytes which will represent the size of the
// next structure and allow us to determine the type
//
if (SUCCEEDED(hr)) { pbuffer += sizeof(BITMAPFILEHEADER); memcpy(&dwSizeOfHeader, pbuffer, sizeof(DWORD));
if (dwSizeOfHeader == sizeof(BITMAPCOREHEADER)) { pbch = (BITMAPCOREHEADER *)pbuffer; memset(&bih, 0, sizeof(BITMAPINFOHEADER));
bih.biSize = sizeof(BITMAPINFOHEADER); bih.biWidth = pbch->bcWidth; bih.biHeight = pbch->bcHeight; bih.biPlanes = pbch->bcPlanes; bih.biBitCount = pbch->bcBitCount;
pbuffer += sizeof(BITMAPCOREHEADER); } else if (dwSizeOfHeader == sizeof(BITMAPINFOHEADER)) { memcpy(&bih, pbuffer, sizeof(BITMAPINFOHEADER));
pbuffer += sizeof(BITMAPINFOHEADER); } else { hr = ResultFromScode(E_FAIL); } }
//
// Check if biClrUsed is set since we do not handle that
// case at this time
//
if (SUCCEEDED(hr)) { if (bih.biClrUsed != 0) { hr = ResultFromScode(E_FAIL); } }
//
// Now we need to calculate the size of the BITMAPINFO we need
// to allocate including any palette information
//
if (SUCCEEDED(hr)) { //
// First the size of the header
//
cbi = sizeof(BITMAPINFOHEADER);
//
// Now the palette
//
if (bih.biBitCount == BMP_24_BITSPERPIXEL) { //
// Just add on the 1 RGBQUAD for the structure but
// there is no palette
//
cbi += sizeof(RGBQUAD); } else if ((bih.biBitCount == BMP_16_BITSPERPIXEL) || (bih.biBitCount == BMP_32_BITSPERPIXEL)) { //
// Add on the 3 DWORD masks which are used to
// get the colors out of the data
//
cbi += (3 * sizeof(DWORD)); } else { //
// Anything else we just use the bit count to calculate
// the number of entries
//
cbi += ((1 << bih.biBitCount) * sizeof(RGBQUAD)); }
//
// Now allocate the BITMAPINFO
//
pbi = (LPBITMAPINFO) new BYTE [cbi]; if (pbi == NULL) { hr = ResultFromScode(E_OUTOFMEMORY); } }
//
// Fill in the BITMAPINFO data structure and get the bits
//
if (SUCCEEDED(hr)) { //
// First copy the header data
//
memcpy(&(pbi->bmiHeader), &bih, sizeof(BITMAPINFOHEADER));
//
// Now the palette data
//
if (bih.biBitCount == BMP_24_BITSPERPIXEL) { //
// No palette data to copy
//
} else if ((bih.biBitCount == BMP_16_BITSPERPIXEL) || (bih.biBitCount == BMP_32_BITSPERPIXEL)) { //
// Copy the 3 DWORD masks
//
memcpy(&(pbi->bmiColors), pbuffer, 3*sizeof(DWORD)); } else { //
// If we were a BITMAPCOREHEADER type then we have our
// palette data in the form of RGBTRIPLEs so we must
// explicitly copy each. Otherwise we can just memcpy
// the RGBQUADs
//
if (dwSizeOfHeader == sizeof(BITMAPCOREHEADER)) { ULONG cPalEntry = (1 << bih.biBitCount); ULONG cCount; RGBTRIPLE *argbt = (RGBTRIPLE *)pbuffer;
for (cCount = 0; cCount < cPalEntry; cCount++) { pbi->bmiColors[cCount].rgbRed = argbt[cCount].rgbtRed; pbi->bmiColors[cCount].rgbGreen = argbt[cCount].rgbtGreen; pbi->bmiColors[cCount].rgbBlue = argbt[cCount].rgbtBlue;
pbi->bmiColors[cCount].rgbReserved = 0; } } else { ULONG cbPalette = (1 << bih.biBitCount) * sizeof(RGBQUAD);
memcpy(&(pbi->bmiColors), pbuffer, cbPalette); } }
//
// Now find out where the bits are
//
pbuffer = pbStart + bmfh.bfOffBits;
//
// Get the size to copy
//
cbData = cb - bmfh.bfOffBits;
//
// Allocate the buffer to hold the bits
//
pbData = new BYTE [cbData]; if (pbData == NULL) { hr = ResultFromScode(E_OUTOFMEMORY); }
if (SUCCEEDED(hr)) { memcpy(pbData, pbuffer, cbData); } }
//
// If everything succeeded record the data
//
if (SUCCEEDED(hr)) { //
// Record the info
//
delete _pbi; _cbi = cbi; _pbi = pbi;
//
// Record the data
//
delete _pbData; _cbData = cbData; _pbData = pbData; } else { //
// Cleanup
//
delete pbi; delete pbData; }
return(hr); }
//+---------------------------------------------------------------------------
//
// Member: CBitmapFile::_ValidateBitmapFileHeader
//
// Synopsis: validates a bitmap file header
//
// Arguments: [pbmfh] -- bitmap file header
// [cbFile] -- bitmap file size
//
// Returns: HRESULT
//
// History: 4-23-94 KirtD Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT CBitmapFile::_ValidateBitmapFileHeader (BITMAPFILEHEADER *pbmfh, ULONG cbFile) { //
// Check for the following,
//
// 1. The bfType member contains 'BM'
// 2. The bfOffset member is NOT greater than the size of the file
//
if ((pbmfh->bfType == 0x4d42) && (pbmfh->bfOffBits <= cbFile)) { return(ResultFromScode(S_OK)); }
return(ResultFromScode(E_FAIL)); }
|