www.pudn.com > yuzhishuanfa.zip > File.cpp


//  位图文件读写  File.cpp  ,鲍捷,1998年4月 
// 
//  Source file for Device-Independent Bitmap (DIB) API.  Provides 
//  the following functions: 
// 
//  SaveDIB()           - Saves the specified dib in a file 
//  ReadDIBFile()       - Loads a DIB from a file 
// 
 
#include "stdafx.h" 
#include  
#include  
#include  
#include "dibapi.h" 
 
/* 
 * Dib Header Marker - used in writing DIBs to files 
 */ 
#define DIB_HEADER_MARKER   ((WORD) ('M' << 8) | 'B') 
 
#ifdef _MAC 
#define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x)) 
#define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x))) 
void ByteSwapHeader(BITMAPFILEHEADER* bmiHeader); 
void ByteSwapInfo(LPSTR lpHeader, BOOL fWin30Header); 
#endif 
 
/************************************************************************* 
 * 
 * SaveDIB() 
 * 
 * Saves the specified DIB into the specified CFile.  The CFile 
 * is opened and closed by the caller. 
 * 
 * Parameters: 
 * 
 * HDIB hDib - Handle to the dib to save 
 * 
 * CFile& file - open CFile used to save DIB 
 * 
 * Return value: TRUE if successful, else FALSE or CFileException 
 * 
 *************************************************************************/ 
 
 
BOOL WINAPI SaveDIB(HDIB hDib, CFile& file) 
{ 
	BITMAPFILEHEADER bmfHdr; // Header for Bitmap file 
	LPBITMAPINFOHEADER lpBI;   // Pointer to DIB info structure 
	DWORD dwDIBSize; 
 
	if (hDib == NULL) 
		return FALSE; 
 
	/* 
	 * Get a pointer to the DIB memory, the first of which contains 
	 * a BITMAPINFO structure 
	 */ 
	lpBI = (LPBITMAPINFOHEADER) ::GlobalLock((HGLOBAL) hDib); 
	if (lpBI == NULL) 
		return FALSE; 
 
	if (!IS_WIN30_DIB(lpBI)) 
	{ 
		::GlobalUnlock((HGLOBAL) hDib); 
		return FALSE;       // It's an other-style DIB (save not supported) 
	} 
 
	/* 
	 * 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)lpBI + ::PaletteSize((LPSTR)lpBI);  // Partial Calculation 
 
	// Now calculate the size of the image 
 
	if ((lpBI->biCompression == BI_RLE8) || (lpBI->biCompression == BI_RLE4)) 
	{ 
		// It's an RLE bitmap, we can't calculate size, so trust the 
		// biSizeImage field 
 
		dwDIBSize += lpBI->biSizeImage; 
	} 
	else 
	{ 
		DWORD dwBmBitsSize;  // Size of Bitmap Bits only 
 
		// It's not RLE, so size is Width (DWORD aligned) * Height 
 
		dwBmBitsSize = WIDTHBYTES((lpBI->biWidth)*((DWORD)lpBI->biBitCount)) * lpBI->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). 
 
		lpBI->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) + lpBI->biSize 
											  + PaletteSize((LPSTR)lpBI); 
#ifdef _MAC 
	ByteSwapHeader(&bmfHdr); 
 
	// First swap the size field 
	*((LPDWORD)lpBI) = SWAPLONG(*((LPDWORD)lpBI)); 
 
	// Now swap the rest of the structure (we don't save < Win30 files) 
	ByteSwapInfo((LPSTR)lpBI, TRUE); 
#endif 
 
	TRY 
	{ 
		// Write the file header 
		file.Write((LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER)); 
		// 
		// Write the DIB header and the bits 
		// 
		file.WriteHuge(lpBI, dwDIBSize); 
	} 
	CATCH (CFileException, e) 
	{ 
#ifdef _MAC 
		// Swap everything back 
		*((LPDWORD)lpBI) = SWAPLONG(*((LPDWORD)lpBI)); 
		ByteSwapInfo((LPSTR)lpBI, TRUE); 
#endif 
		::GlobalUnlock((HGLOBAL) hDib); 
		THROW_LAST(); 
	} 
	END_CATCH 
 
#ifdef _MAC 
	// Swap everything back 
	*((LPDWORD)lpBI) = SWAPLONG(*((LPDWORD)lpBI)); 
	ByteSwapInfo((LPSTR)lpBI, TRUE); 
#endif 
 
	::GlobalUnlock((HGLOBAL) hDib); 
	return TRUE; 
} 
 
 
/************************************************************************* 
 
  Function:  ReadDIBFile (CFile&) 
 
   Purpose:  Reads in the specified DIB file into a global chunk of 
			 memory. 
 
   Returns:  A handle to a dib (hDIB) if successful. 
			 NULL if an error occurs. 
 
  Comments:  BITMAPFILEHEADER is stripped off of the DIB.  Everything 
			 from the end of the BITMAPFILEHEADER structure on is 
			 returned in the global memory handle. 
 
*************************************************************************/ 
 
 
HDIB WINAPI ReadDIBFile(CFile& file) 
{ 
	BITMAPFILEHEADER bmfHeader; 
	DWORD dwBitsSize; 
	HDIB hDIB; 
	LPSTR pDIB; 
 
	// 取得文件长度以准备读入	  
	dwBitsSize = file.GetLength(); 
 
	// 读入DIB文件头并检验其有效性 
	if (file.Read((LPSTR)&bmfHeader, sizeof(bmfHeader)) != sizeof(bmfHeader)) 
		return NULL; 
 
#ifdef _MAC 
	ByteSwapHeader(&bmfHeader); 
#endif 
	if (bmfHeader.bfType != DIB_HEADER_MARKER)//是否是BMP,头为"BM" 
		return NULL; 
 
	// 为DIB分配内存 
	hDIB = (HDIB) ::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, dwBitsSize); 
	if (hDIB == 0) 
	{ 
		return NULL; 
	} 
	//指向DIB句柄的指针 
	pDIB = (LPSTR) ::GlobalLock((HGLOBAL) hDIB); 
 
	// Go read the bits.读入图象数据 
	//读入信息头、调色板、数据  
	if (file.ReadHuge(pDIB, dwBitsSize - sizeof(BITMAPFILEHEADER)) != 
		dwBitsSize - sizeof(BITMAPFILEHEADER) ) 
	{ 
		::GlobalUnlock((HGLOBAL) hDIB); 
		::GlobalFree((HGLOBAL) hDIB); 
		return NULL; 
	} 
#ifdef _MAC 
	// First swap the size field 
	*((LPDWORD)pDIB) = SWAPLONG(*((LPDWORD)pDIB)); 
	// Now swap the rest of the structure 
	ByteSwapInfo(pDIB, IS_WIN30_DIB(pDIB)); 
#endif 
	::GlobalUnlock((HGLOBAL) hDIB); 
	return hDIB; 
} 
 
 
#ifdef _MAC 
void ByteSwapHeader(BITMAPFILEHEADER* bmfHeader) 
{ 
	bmfHeader->bfType = SWAPWORD(bmfHeader->bfType); 
	bmfHeader->bfSize = SWAPLONG(bmfHeader->bfSize); 
	bmfHeader->bfOffBits = SWAPLONG(bmfHeader->bfOffBits); 
} 
 
 
void ByteSwapInfo(LPSTR lpHeader, BOOL fWin30Header) 
{ 
	// Note this doesn't swap the bcSize/biSize field.  It assumes that the 
	// size field was swapped during read or while setting the fWin30Header 
	// flag. 
 
	if (fWin30Header) 
	{ 
		LPBITMAPINFOHEADER lpBMIH = &(LPBITMAPINFO(lpHeader)->bmiHeader); 
 
		//lpBMIH->biSize = SWAPLONG(lpBMIH->biSize); 
		lpBMIH->biWidth = SWAPLONG(lpBMIH->biWidth); 
		lpBMIH->biHeight = SWAPLONG(lpBMIH->biHeight); 
		lpBMIH->biPlanes = SWAPWORD(lpBMIH->biPlanes); 
		lpBMIH->biBitCount = SWAPWORD(lpBMIH->biBitCount); 
		lpBMIH->biCompression = SWAPLONG(lpBMIH->biCompression); 
		lpBMIH->biSizeImage = SWAPLONG(lpBMIH->biSizeImage); 
		lpBMIH->biXPelsPerMeter = SWAPLONG(lpBMIH->biXPelsPerMeter); 
		lpBMIH->biYPelsPerMeter = SWAPLONG(lpBMIH->biYPelsPerMeter); 
		lpBMIH->biClrUsed = SWAPLONG(lpBMIH->biClrUsed); 
		lpBMIH->biClrImportant = SWAPLONG(lpBMIH->biClrImportant); 
	} 
	else 
	{ 
		LPBITMAPCOREHEADER lpBMCH = &(LPBITMAPCOREINFO(lpHeader)->bmciHeader); 
 
		lpBMCH->bcWidth = SWAPWORD(lpBMCH->bcWidth); 
		lpBMCH->bcHeight = SWAPWORD(lpBMCH->bcHeight); 
		lpBMCH->bcPlanes = SWAPWORD(lpBMCH->bcPlanes); 
		lpBMCH->bcBitCount = SWAPWORD(lpBMCH->bcBitCount); 
	} 
} 
 
#endif