⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bmpfile.cpp

📁 带滚动条的图像浏览器
💻 CPP
字号:
// BmpFile.cpp : implementation file
//

#include "stdafx.h"
#include "MfcScroll1.h"
#include "BmpFile.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CBmpFile

IMPLEMENT_DYNCREATE(CBmpFile, CObject)

CBmpFile::CBmpFile()
{
	InitMemberVar();
}

CBmpFile::CBmpFile(CSize size, int nBitCount)
{
	InitMemberVar();
	ComputePaletteSize(nBitCount);
	m_pBmih = (LPBITMAPINFOHEADER) new 
		char[sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorTableEntries];
	m_pBmih->biSize = sizeof(BITMAPINFOHEADER);
	m_pBmih->biWidth = size.cx;
	m_pBmih->biHeight = size.cy;
	m_pBmih->biPlanes = 1;
	m_pBmih->biBitCount = nBitCount;
	m_pBmih->biCompression = BI_RGB;
	m_pBmih->biSizeImage = 0;
	m_pBmih->biXPelsPerMeter = 0;
	m_pBmih->biYPelsPerMeter = 0;
	m_pBmih->biClrUsed = m_nColorTableEntries;
	m_pBmih->biClrImportant = m_nColorTableEntries;
	CalcBufSize();
	memset(m_pColorTable, 0, sizeof(RGBQUAD) * m_nColorTableEntries);
}

CBmpFile::~CBmpFile()
{
	Empty();
}

void CBmpFile::InitMemberVar()
{
	m_pBmih = NULL;
	m_pBits = NULL;
	m_hPalette = NULL;
	m_hBitmap = NULL;
	m_pColorTable = NULL;
	m_nColorTableEntries = 0;
	m_dwSizeImage = 0;
	m_bNoDelBits = 0;
	m_bGray = 0;
}

/////////////////////////////////////////////////////////////////////////////
// CBmpFile message handlers

CSize CBmpFile::GetDimensions()
{	
	if(m_pBmih == NULL)
		return CSize(0, 0);
	return CSize((int) m_pBmih->biWidth, (int) m_pBmih->biHeight);
}

UINT CBmpFile::UsePalette(CDC* pDC, BOOL bBackground /* = FALSE */)
{
	if(m_hPalette == NULL) return 0;
	HDC hdc = pDC->GetSafeHdc();
	::SelectPalette(hdc, m_hPalette, bBackground);
	return ::RealizePalette(hdc);
}

BOOL CBmpFile::Draw(CDC* pDC, CPoint origin, CSize size)
{
	if(m_pBmih == NULL) return FALSE;
	if(m_hPalette != NULL) {
		::SelectPalette(pDC->GetSafeHdc(), m_hPalette, TRUE);
	}
	pDC->SetStretchBltMode(COLORONCOLOR);
	::StretchDIBits(pDC->GetSafeHdc(), origin.x, origin.y, size.cx, size.cy,
		0, 0, m_pBmih->biWidth, m_pBmih->biHeight,
		m_pBits, (LPBITMAPINFO) m_pBmih, DIB_RGB_COLORS, SRCCOPY);
	return TRUE;
}

BOOL CBmpFile::MakePalette( )
{
	// makes a logical palette (m_hPalette) from the DIB's color table
	// this palette will be selected and realized prior to drawing the DIB
	if(m_nColorTableEntries == 0) return FALSE;
	if(m_hPalette != NULL) ::DeleteObject(m_hPalette);
	LPLOGPALETTE pLogPal = (LPLOGPALETTE) new char[2 * sizeof(WORD) +
		m_nColorTableEntries * sizeof(PALETTEENTRY)];
	pLogPal->palVersion = 0x300;
	pLogPal->palNumEntries = m_nColorTableEntries;
	LPRGBQUAD pDibQuad = (LPRGBQUAD) m_pColorTable;
	for(int i = 0; i < m_nColorTableEntries; i++) {
		pLogPal->palPalEntry[i].peRed = pDibQuad->rgbRed;
		pLogPal->palPalEntry[i].peGreen = pDibQuad->rgbGreen;
		pLogPal->palPalEntry[i].peBlue = pDibQuad->rgbBlue;
		pLogPal->palPalEntry[i].peFlags = 0;
		pDibQuad++;
	}
	m_hPalette = ::CreatePalette(pLogPal);
	delete pLogPal;
	return TRUE;
}	

BOOL CBmpFile::SetSystemPalette(CDC* pDC)
{
	// if the DIB doesn't have a color table, we can use the system's halftone palette
	if(m_nColorTableEntries != 0) return FALSE;
	m_hPalette = ::CreateHalftonePalette(pDC->GetSafeHdc());
	return TRUE;
}

HBITMAP CBmpFile::CreateBitmap(CDC* pDC)
{
    if (m_dwSizeImage == 0) return NULL;
    HBITMAP hBitmap = ::CreateDIBitmap(pDC->GetSafeHdc(), m_pBmih,
            CBM_INIT, m_pBits, (LPBITMAPINFO) m_pBmih, DIB_RGB_COLORS);
    ASSERT(hBitmap != NULL);
    return hBitmap;
}

BOOL CBmpFile::Read(CFile* pFile)
{
	Empty();
	UINT nCount, nSize;
	BITMAPFILEHEADER bmfh;
	try {
		nCount = pFile->Read((LPVOID) &bmfh, sizeof(BITMAPFILEHEADER));
		if(nCount != sizeof(BITMAPFILEHEADER)) {
			throw new CException;
		}
		if(bmfh.bfType != 0x4d42) {
			throw new CException;
		}
		nSize = bmfh.bfOffBits - sizeof(BITMAPFILEHEADER);
		m_pBmih = (LPBITMAPINFOHEADER) new char[nSize];
		nCount = pFile->Read(m_pBmih, nSize); // info hdr & color table
		if(nCount != nSize) {
			throw new CException;
		}
		CalcBufSize();
		ComputePaletteSize(m_pBmih->biBitCount);
		MakePalette();
		m_pBits = (LPBYTE) new char[m_dwSizeImage];
		m_bNoDelBits = 0;

		nCount = pFile->Read(m_pBits, m_dwSizeImage); // image only
		if(nCount != m_dwSizeImage) {
			throw new CException;
		}
	}
	catch(CException* pe) {
		Empty();
		AfxMessageBox("Read error");
		pe->Delete();
		return FALSE;
	}
	return TRUE;
}

BOOL CBmpFile::ReadSection(CFile* pFile, CDC* pDC /* = NULL */)
{
	// new function reads BMP from disk and creates a DIB section
	//    allows modification of bitmaps from disk
	// 1. read file header to get size of info hdr + color table
	// 2. read info hdr (to get image size) and color table
	// 3. create DIB section based on header parms
	// 4. read image into memory that CreateDibSection allocates
	Empty();
	int nCount, nSize;
	BITMAPFILEHEADER bmfh;
	try {
		nCount = pFile->Read((LPVOID) &bmfh, sizeof(BITMAPFILEHEADER));
		if(nCount != sizeof(BITMAPFILEHEADER)) {
			throw new CException;
		}
		if(bmfh.bfType != 0x4d42) {
			throw new CException;
		}
		nSize = bmfh.bfOffBits - sizeof(BITMAPFILEHEADER);
		m_pBmih = (LPBITMAPINFOHEADER) new char[nSize];
		nCount = pFile->Read(m_pBmih, nSize); // info hdr & color table
		if(m_pBmih->biCompression != BI_RGB) {
			throw new CException;
		}
		CalcBufSize();
		ComputePaletteSize(m_pBmih->biBitCount);
		MakePalette();
		UsePalette(pDC);
		m_bNoDelBits = 1;
		m_hBitmap = ::CreateDIBSection(pDC->GetSafeHdc(), (LPBITMAPINFO) m_pBmih,
			DIB_RGB_COLORS,	(LPVOID*) &m_pBits, NULL, 0);
		ASSERT(m_pBits != NULL);
		nCount = pFile->Read(m_pBits, m_dwSizeImage); // image only
	}
	catch(CException* pe){
		AfxMessageBox("ReadSection error");
		pe->Delete();
		return FALSE;
	}
	return TRUE;
}

BOOL CBmpFile::Write(CFile* pFile)
{
	BITMAPFILEHEADER bmfh;
	bmfh.bfType = 0x4d42;  // 'BM'
	int nSizeHdr = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorTableEntries;
	bmfh.bfSize = sizeof(BITMAPFILEHEADER) + nSizeHdr + m_dwSizeImage;
	bmfh.bfReserved1 = bmfh.bfReserved2 = 0;
	bmfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) +
			sizeof(RGBQUAD) * m_nColorTableEntries;	
	try {
		pFile->Write((LPVOID) &bmfh, sizeof(BITMAPFILEHEADER));
		pFile->Write((LPVOID) m_pBmih,  nSizeHdr);
		pFile->Write((LPVOID) m_pBits, m_dwSizeImage);
	}
	catch(CException* pe) {
		pe->Delete();
		AfxMessageBox("write error");
		return FALSE;
	}
	return TRUE;
}

// helper functions
void CBmpFile::ComputePaletteSize(int nBitCount)
{
	if((m_pBmih == NULL) || (m_pBmih->biClrUsed == 0)) {
		switch(nBitCount) {
			case 1:
				m_nColorTableEntries = 2;
				break;
			case 4:
				m_nColorTableEntries = 16;
				break;
			case 8:
				m_nColorTableEntries = 256;
				break;
			case 16:
			case 24:
			case 32:
				m_nColorTableEntries = 0;
				break;
			default:
				ASSERT(FALSE);
		}
	}
	else {
		m_nColorTableEntries = m_pBmih->biClrUsed;
	}
	ASSERT((m_nColorTableEntries >= 0) && (m_nColorTableEntries <= 256)); 
}

void CBmpFile::CalcBufSize()
{
	m_dwSizeImage = m_pBmih->biSizeImage;
	if(m_dwSizeImage == 0) 
	{
		DWORD dwBytes = ((DWORD) m_pBmih->biWidth * m_pBmih->biBitCount+31) / 32*4;
		m_dwSizeImage = dwBytes * m_pBmih->biHeight; // no compression
	}
	m_pColorTable = (LPBYTE) m_pBmih + sizeof(BITMAPINFOHEADER);
}

void CBmpFile::Empty()
{
	if( m_pBmih ) {
		delete[] m_pBmih;
		m_pBmih = NULL;
	}

	if(m_hBitmap)
	{
		::DeleteObject(m_hBitmap);
		m_hBitmap = NULL;
	}

	if( m_pBits && !m_bNoDelBits )
		delete[] m_pBits;
	m_pBits = NULL;

	if(m_hPalette) 
	{
		::DeleteObject(m_hPalette);
		m_hPalette = NULL;
	}
	m_pColorTable = NULL;
	m_nColorTableEntries = 0;
	m_dwSizeImage = 0;
	m_bGray = 0;
}

HBITMAP CBmpFile::Detach()
{
	HBITMAP hBmp = NULL;
	if( m_bNoDelBits && m_hBitmap )
	{
		hBmp = m_hBitmap;
		m_hBitmap = NULL;
		m_pBits = NULL;
		Empty();
	}
	return hBmp;
}

BOOL CBmpFile::LoadFile( LPCTSTR szPathName)
{
	CFile file;
	int i = 0;
	if( file.Open( szPathName,CFile::modeRead ) )
	{
		i = Read( &file );
		file.Close( );
	}
	return i;
}

BOOL CBmpFile::LoadFileSection(LPCTSTR szPathName, CDC* pDC /*= NULL*/)
{
	CFile file;
	int i = 0;
	if( file.Open( szPathName,CFile::modeRead ) )
	{
		i = ReadSection( &file, pDC );
		file.Close( );
	}
	return i;
}

BOOL CBmpFile::WriteFile(LPCTSTR szPathName)
{
	CFile file;
	int i = 0;
	if( file.Open( szPathName,CFile::modeWrite ) )
	{
		i = Write( &file );
		file.Close( );
	}
	return i;
}

void CBmpFile::GetPixel( CPoint &pt,BYTE &r,BYTE &g,BYTE &b)
{
	if( m_pBmih == NULL )
		return;
	int y = pt.y, x = pt.x, xByte;
	BYTE uChar, xBit;
	if( pt.y < 0 )
		y = 0-y;
	if( y >= m_pBmih->biHeight )
		y = m_pBmih->biHeight-1;
	if( pt.x >= m_pBmih->biWidth )
		x = m_pBmih->biWidth-1;
	xByte = x*m_pBmih->biBitCount/8;
	xBit = BYTE(x*m_pBmih->biBitCount%8);
	DWORD bmHeight = m_pBmih->biHeight - y - 1;
	DWORD bmWidthBytes = (m_pBmih->biWidth * m_pBmih->biBitCount + 31) / 32*4;
	DWORD dwOffset = bmWidthBytes*bmHeight + xByte;

	UINT uIndex;
	LPBYTE pByte = m_pBits + dwOffset;
	LPRGBQUAD pRGBQURD = (LPRGBQUAD)m_pColorTable;
	switch( m_pBmih->biBitCount )
	{
		case 1:
			uChar = *pByte;
			uIndex = (uChar>>(7-xBit)) & 1; 
			r = pRGBQURD[uIndex].rgbRed;
			g = pRGBQURD[uIndex].rgbGreen;
			b = pRGBQURD[uIndex].rgbBlue;
			break;
		case 4:
			uChar = *pByte;
			uIndex = (uChar>>(4-xBit)) & 15; 
			r = pRGBQURD[uIndex].rgbRed;
			g = pRGBQURD[uIndex].rgbGreen;
			b = pRGBQURD[uIndex].rgbBlue;
			break;
		case 8:
			uIndex = *pByte;
			r = pRGBQURD[uIndex].rgbRed;
			g = pRGBQURD[uIndex].rgbGreen;
			b = pRGBQURD[uIndex].rgbBlue;
			break;
		case 16:
		{
			PWORD pWord = (PWORD)pByte;
			uIndex = *pWord;
			r = ( (uIndex >> 10) & 31)<<3;
			g = ((uIndex >> 5) & 31)<<3;
			b = (uIndex & 31)<<3;
			break;
		}
		case 24:
		case 32:
			r = *pByte++;
			g = *pByte++;
			b = *pByte;
			break;
	}
}

void CBmpFile::GrayImage( CDC *pDC )
{
	if( m_pBmih == NULL || m_pBits == NULL 	|| m_bGray )
		return;

	DWORD bmWidthBytes = (m_pBmih->biWidth * m_pBmih->biBitCount + 31) / 32*4;
	int i,j;
	BYTE r,b,g;
	LPBYTE pByte = m_pBits;
	LPRGBQUAD pRGBQURD = (LPRGBQUAD)m_pColorTable;
	switch( m_pBmih->biBitCount )
	{
		case 1:
		case 4:
		case 8:
			for( i=0;i<m_nColorTableEntries; i++ )
			{
				j = (pRGBQURD[i].rgbRed*59+pRGBQURD[i].rgbGreen*30+pRGBQURD[i].rgbBlue*11)/100;
				pRGBQURD[i].rgbRed = BYTE(j);
				pRGBQURD[i].rgbGreen = BYTE(j);;
				pRGBQURD[i].rgbBlue = BYTE(j);;
			}
			break;
		case 16:
		{
			PWORD pWord;
			register UINT uIndex;
			for( i=0; i<m_pBmih->biHeight; i++ )
			{
				pWord = (PWORD)pByte;
				for( j=0; j<m_pBmih->biWidth; j++ )
				{
					uIndex = *pWord;
					r = (uIndex >> 10) & 31;
					g = (uIndex >> 5) & 31;
					b = uIndex & 31;
					uIndex = r = (r*59 + g*30 + b*11)/100;
					uIndex <<= 5;
					uIndex += r;
					uIndex <<= 5;
					uIndex += r;
					*pWord++ = uIndex;
				}
				pByte += bmWidthBytes;
			}
			break;
		}
		case 24:
		case 32:
		{
			register PBYTE pData1,pData2;
			for( i=0; i<m_pBmih->biHeight; i++ )
			{
				pData1 = pData2 = pByte;
				for( j=0; j<m_pBmih->biWidth; j++ )
				{
					r = *pData1++;
					g = *pData1++;
					b = *pData1++;
					r = BYTE( (r*59 + g*30 + b*11)/100 );
					*pData2++ = r;
					*pData2++ = r;
					*pData2++ = r;
				}
				pByte += bmWidthBytes;
			}
			break;
		}
	}

	HBITMAP hBitmap = ::CreateDIBSection( pDC->GetSafeHdc(), (LPBITMAPINFO) m_pBmih,
			DIB_RGB_COLORS,	(LPVOID*) &pByte, NULL, 0);
	ASSERT(pByte != NULL);
	memcpy( pByte, m_pBits,m_dwSizeImage);
	if( m_hBitmap )
		::DeleteObject(m_hBitmap);
	m_hBitmap = hBitmap;
	if( m_pBits && !m_bNoDelBits )
		delete[] m_pBits;
	m_pBits = pByte;
	m_bNoDelBits = 1;
	m_bGray = 1;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -