gdidoc.cpp

来自「MFC编程实例」· C++ 代码 · 共 508 行

CPP
508
字号
#include "stdafx.h"
#include "GDI.h"
#include "GDIDoc.h"
#include "GDIView.h"

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

#define WIDTHBYTES(bits) ((((bits)+31)/32)*4)

IMPLEMENT_DYNCREATE(CGDIDoc, CDocument)

BEGIN_MESSAGE_MAP(CGDIDoc, CDocument)
	//{{AFX_MSG_MAP(CGDIDoc)
	ON_UPDATE_COMMAND_UI(ID_FILE_SAVE, OnUpdateFileSave)
	ON_UPDATE_COMMAND_UI(ID_FILE_SAVE_AS, OnUpdateFileSaveAs)
	ON_COMMAND(ID_CONVERT_256TORGB, OnConvert256toRGB)
	ON_UPDATE_COMMAND_UI(ID_CONVERT_256TORGB, OnUpdateConvert256toRGB)
	ON_COMMAND(ID_CONVERT_RGBTO256, OnConvertRGBto256)
	ON_UPDATE_COMMAND_UI(ID_CONVERT_RGBTO256, OnUpdateConvertRGBto256)
	ON_COMMAND(ID_CONVERT_BLACKWHITE, OnConvertBlackwhite)
	ON_UPDATE_COMMAND_UI(ID_CONVERT_BLACKWHITE, OnUpdateConvertBlackwhite)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

CGDIDoc::CGDIDoc()
{
	m_hDIB=NULL;
	m_nBmpFormat=BMP_FORMAT_NONE;
}

CGDIDoc::~CGDIDoc()
{
	if(m_hDIB != NULL)
	{
		::GlobalFree(m_hDIB);	
		m_hDIB=NULL;
	}
}

BOOL CGDIDoc::OnNewDocument()
{
	if (!CDocument::OnNewDocument())
		return FALSE;

	return TRUE;
}

void CGDIDoc::Serialize(CArchive& ar)
{
	if(ar.IsStoring())
	{
		HGLOBAL hDib;
		BITMAPFILEHEADER bmf;
		BITMAPINFOHEADER bi;
		LPBITMAPINFOHEADER lpBi;
		DWORD dwSizeCT;

		hDib=m_hDIB;
		ASSERT(hDib);
		bmf.bfType='MB';
		bmf.bfSize=sizeof(bmf)+::GlobalSize(hDib);
		bmf.bfReserved1=0;
		bmf.bfReserved2=0;
		lpBi=(LPBITMAPINFOHEADER)::GlobalLock(hDib);
		bi=*lpBi;
		if(bi.biSizeImage == 0)
		{
			bi.biSizeImage=WIDTHBYTES(bi.biBitCount*bi.biWidth)*bi.biHeight;
		}
		dwSizeCT=GetColorTableSize(bi.biBitCount);
		bmf.bfOffBits=sizeof(bmf)+bi.biSize+dwSizeCT*sizeof(RGBQUAD);
		ar.Write((char *)&bmf, sizeof(bmf));
		ar.Write((LPSTR)lpBi, bi.biSize+dwSizeCT*sizeof(RGBQUAD)+bi.biSizeImage);
		::GlobalUnlock(hDib);
	}
	else
	{
		BITMAPFILEHEADER bf;
		DWORD dwSize;
		LPSTR lpDIB;

		if(m_hDIB != NULL)
		{
			::GlobalFree(m_hDIB);	
			m_hDIB=NULL;
		}
		if
		(
			ar.Read
			(
				(LPSTR)&bf,
				sizeof(BITMAPFILEHEADER)
			) != sizeof(BITMAPFILEHEADER)
		)return;

		if(bf.bfType != 'MB')return;
		dwSize=bf.bfSize-sizeof(BITMAPFILEHEADER);
		m_hDIB=::GlobalAlloc(GHND, dwSize);
		ASSERT(m_hDIB);
		lpDIB=(LPSTR)::GlobalLock(m_hDIB);
		ASSERT(lpDIB);
		if(ar.Read(lpDIB, dwSize) != dwSize)
		{
			::GlobalUnlock(m_hDIB);
			::GlobalFree(m_hDIB);
			m_hDIB=NULL;
		}
		else ::GlobalUnlock(m_hDIB);
	}
}

#ifdef _DEBUG
void CGDIDoc::AssertValid() const
{
	CDocument::AssertValid();
}

void CGDIDoc::Dump(CDumpContext& dc) const
{
	CDocument::Dump(dc);
}
#endif

void CGDIDoc::OnUpdateFileSave(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable(FALSE);
}

void CGDIDoc::OnUpdateFileSaveAs(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable(m_hDIB != NULL);
}

DWORD CGDIDoc::GetColorTableSize(WORD wBitCount)
{
	DWORD dwSizeCT;

	switch(wBitCount)
	{                
		case 1:
		{
			dwSizeCT=2;
			m_nBmpFormat=BMP_FORMAT_MONO;
			break;
		}
		case 4:
		{
			dwSizeCT=16;
			m_nBmpFormat=BMP_FORMAT_16COLOR;
			break;
		}
		case 8:
		{
			dwSizeCT=256;
			m_nBmpFormat=BMP_FORMAT_256COLOR;
			break;
		}
		case 24:
		{
			dwSizeCT=0;
			m_nBmpFormat=BMP_FORMAT_24BIT;
		}
	}
	return dwSizeCT;
}

void CGDIDoc::OnConvert256toRGB() 
{
	LPBITMAPINFO lpBi;
	LPBITMAPINFO lpBi24;
	HGLOBAL hDIB24;
	DWORD dwSize;
	int nSizeCT;
	int i, j;
	LPSTR lpRowSrc;
	LPSTR lpRowTgt;
	BYTE byIndex;
	RGBQUAD rgbQuad;
	POSITION pos;
	CGDIView *ptrView;

	lpBi=(LPBITMAPINFO)::GlobalLock(m_hDIB);
	ASSERT(lpBi);
	nSizeCT=GetColorTableSize(lpBi->bmiHeader.biBitCount);
	dwSize=
	(
		sizeof(BITMAPINFOHEADER)+
		WIDTHBYTES(24*lpBi->bmiHeader.biWidth)*lpBi->bmiHeader.biHeight
	);
	hDIB24=::GlobalAlloc(GHND, dwSize);
	ASSERT(hDIB24);
	lpBi24=(LPBITMAPINFO)::GlobalLock(hDIB24);
	*lpBi24=*lpBi;
	lpBi24->bmiHeader.biBitCount=24;
	lpBi24->bmiHeader.biSizeImage=WIDTHBYTES
	(
		24*lpBi->bmiHeader.biWidth
	)*lpBi->bmiHeader.biHeight;
	lpBi24->bmiHeader.biClrUsed=0;
	for(j=0; j<lpBi->bmiHeader.biHeight; j++)
	{
		lpRowSrc=
		(
			(LPSTR)lpBi+
			sizeof(BITMAPINFOHEADER)+
			nSizeCT*sizeof(RGBQUAD)+
			WIDTHBYTES(lpBi->bmiHeader.biBitCount*lpBi->bmiHeader.biWidth)*j
		);
		lpRowTgt=
		(
			(LPSTR)lpBi24+
			sizeof(BITMAPINFOHEADER)+
			WIDTHBYTES(lpBi24->bmiHeader.biBitCount*lpBi24->bmiHeader.biWidth)*j
		);
		for(i=0; i<lpBi->bmiHeader.biWidth; i++)
		{
			byIndex=*lpRowSrc;
			rgbQuad=lpBi->bmiColors[byIndex];
			*lpRowTgt=rgbQuad.rgbBlue;
			*(lpRowTgt+1)=rgbQuad.rgbGreen;
			*(lpRowTgt+2)=rgbQuad.rgbRed;
			lpRowSrc++;
			lpRowTgt+=3;
		}
	}
	::GlobalUnlock(m_hDIB);
	::GlobalFree(m_hDIB);
	::GlobalUnlock(hDIB24);
	m_hDIB=hDIB24;
	m_nBmpFormat=BMP_FORMAT_24BIT;

	pos=GetFirstViewPosition();
	ptrView=(CGDIView *)GetNextView(pos);
	ASSERT(ptrView->IsKindOf(RUNTIME_CLASS(CGDIView)));
	ptrView->LoadBitmap(m_hDIB);
}

void CGDIDoc::OnUpdateConvert256toRGB(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable(m_nBmpFormat == BMP_FORMAT_256COLOR);
}

void CGDIDoc::OnConvertRGBto256() 
{
	LPBITMAPINFO lpBi;
	LPBITMAPINFO lpBi24;
	HGLOBAL hDIB;
	DWORD dwSize;
	int nSizeCT;
	int i, j;
	int n;
	LPSTR lpRowSrc;
	LPSTR lpRowTgt;
	POSITION pos;
	CGDIView *ptrView;
	CPtrArray arRgbQuad;
	LPRGBQUAD lpRgbQuad;
	RGBQUAD rgbQuad;
	BOOL bHit;
	BOOL bStandardPal;
	BYTE red, green, blue;

	AfxGetApp()->DoWaitCursor(TRUE);
	lpBi24=(LPBITMAPINFO)::GlobalLock(m_hDIB);
	ASSERT(lpBi24);
	for(j=0; j<lpBi24->bmiHeader.biHeight; j++)
	{
		lpRowSrc=
		(
			(LPSTR)lpBi24+
			sizeof(BITMAPINFOHEADER)+
			WIDTHBYTES(lpBi24->bmiHeader.biBitCount*lpBi24->bmiHeader.biWidth)*j
		);
		for(i=0; i<lpBi24->bmiHeader.biWidth; i++)
		{
			rgbQuad.rgbBlue=*lpRowSrc;
			rgbQuad.rgbGreen=*(lpRowSrc+1);
			rgbQuad.rgbRed=*(lpRowSrc+2);
			rgbQuad.rgbReserved=0;
			bHit=FALSE;
			for(n=0; n<arRgbQuad.GetSize(); n++)
			{
				if
				(	
					!memcmp
					(
						(LPSTR)&rgbQuad,
						(LPSTR)arRgbQuad[n],
						sizeof(RGBQUAD)
					)
				)
				{
					bHit=TRUE;
					break;
				}
			}
			if(bHit == FALSE)
			{
				lpRgbQuad=new RGBQUAD;
				*lpRgbQuad=rgbQuad;
				arRgbQuad.Add(lpRgbQuad);
			}
			lpRowSrc+=3;
		}
	}
	if(arRgbQuad.GetSize() > 256)
	{
		while(arRgbQuad.GetSize())
		{
			delete (LPRGBQUAD)arRgbQuad.GetAt(0);
			arRgbQuad.RemoveAt(0);
		}
		red=green=blue=0;
		for(i=0; i<256; i++)
		{
			lpRgbQuad=new RGBQUAD;
			lpRgbQuad->rgbBlue=blue;
			lpRgbQuad->rgbGreen=green;
			lpRgbQuad->rgbRed=red;
			lpRgbQuad->rgbReserved=0;
			if(!(red+=32))if(!(green+=32))blue+=64;
			arRgbQuad.Add(lpRgbQuad);
		}
		bStandardPal=TRUE;
	}
	else bStandardPal=FALSE;
	nSizeCT=256;
	dwSize=
	(
		sizeof(BITMAPINFOHEADER)+
		nSizeCT*sizeof(RGBQUAD)+
		WIDTHBYTES(8*lpBi24->bmiHeader.biWidth)*lpBi24->bmiHeader.biHeight
	);
	hDIB=::GlobalAlloc(GHND, dwSize);
	ASSERT(hDIB);
	lpBi=(LPBITMAPINFO)::GlobalLock(hDIB);
	ASSERT(lpBi);
	*lpBi=*lpBi24;
	lpBi->bmiHeader.biBitCount=8;
	lpBi->bmiHeader.biSizeImage=WIDTHBYTES
	(
		8*lpBi->bmiHeader.biWidth
	)*lpBi->bmiHeader.biHeight;
	lpBi->bmiHeader.biClrUsed=0;

	for(n=0; n<arRgbQuad.GetSize(); n++)
	{
		lpBi->bmiColors[n]=*(LPRGBQUAD)arRgbQuad[n];
	}

	for(j=0; j<lpBi->bmiHeader.biHeight; j++)
	{
		lpRowTgt=
		(
			(LPSTR)lpBi+
			sizeof(BITMAPINFOHEADER)+
			nSizeCT*sizeof(RGBQUAD)+
			WIDTHBYTES(lpBi->bmiHeader.biBitCount*lpBi->bmiHeader.biWidth)*j
		);
		lpRowSrc=
		(
			(LPSTR)lpBi24+
			sizeof(BITMAPINFOHEADER)+
			WIDTHBYTES(lpBi24->bmiHeader.biBitCount*lpBi24->bmiHeader.biWidth)*j
		);
		for(i=0; i<lpBi->bmiHeader.biWidth; i++)
		{
			rgbQuad.rgbBlue=*lpRowSrc;
			rgbQuad.rgbGreen=*(lpRowSrc+1);
			rgbQuad.rgbRed=*(lpRowSrc+2);
			rgbQuad.rgbReserved=0;
			if(bStandardPal == TRUE)
			{
				if(rgbQuad.rgbBlue <= 0xdf)rgbQuad.rgbBlue+=0x20;
				if(rgbQuad.rgbGreen <= 0xef)rgbQuad.rgbGreen+=0x10;
				if(rgbQuad.rgbRed <= 0xef)rgbQuad.rgbRed+=0x10;
				*lpRowTgt=(BYTE)
				(
					(0x00c0&rgbQuad.rgbBlue) |
					((0x00e0&rgbQuad.rgbGreen)>>2) |
					((0x00e0&rgbQuad.rgbRed)>>5)
				);
			}
			else
			{
				for(n=0; n<arRgbQuad.GetSize(); n++)
				{
					if
					(	
						!memcmp
						(
							(LPSTR)&rgbQuad,
							(LPSTR)arRgbQuad[n],
							sizeof(RGBQUAD)
						)
					)break;
				}
				*lpRowTgt=(BYTE)n;
			}
			lpRowSrc+=3;
			lpRowTgt++;
		}
	}
	::GlobalUnlock(m_hDIB);
	::GlobalFree(m_hDIB);
	::GlobalUnlock(hDIB);
	m_hDIB=hDIB;
	m_nBmpFormat=BMP_FORMAT_256COLOR;

	while(arRgbQuad.GetSize())
	{
		delete (LPRGBQUAD)arRgbQuad.GetAt(0);
		arRgbQuad.RemoveAt(0);
	}

	pos=GetFirstViewPosition();
	ptrView=(CGDIView *)GetNextView(pos);
	ASSERT(ptrView->IsKindOf(RUNTIME_CLASS(CGDIView)));
	ptrView->LoadBitmap(m_hDIB);
	AfxGetApp()->DoWaitCursor(FALSE);
}

void CGDIDoc::OnUpdateConvertRGBto256(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable(m_nBmpFormat == BMP_FORMAT_24BIT);
}

void CGDIDoc::OnConvertBlackwhite() 
{
	LPBITMAPINFO lpBi;
	int i, j;
	LPSTR lpRow;
	RGBQUAD rgbQuad;
	POSITION pos;
	CGDIView *ptrView;

	AfxGetApp()->DoWaitCursor(TRUE);
	lpBi=(LPBITMAPINFO)::GlobalLock(m_hDIB);
	ASSERT(lpBi);
	switch(lpBi->bmiHeader.biBitCount)
	{
		case 8:
		{
			for(i=0; i<256; i++)
			{
				rgbQuad=lpBi->bmiColors[i];
				rgbQuad.rgbBlue=rgbQuad.rgbGreen=rgbQuad.rgbRed=
				(
					rgbQuad.rgbBlue+
					rgbQuad.rgbGreen+
					rgbQuad.rgbRed
				)/3;
				lpBi->bmiColors[i]=rgbQuad;
			}
			break;
		}
		case 24:
		{
			for(j=0; j<lpBi->bmiHeader.biHeight; j++)
			{
				lpRow=
				(
					(LPSTR)lpBi+
					sizeof(BITMAPINFOHEADER)+
					WIDTHBYTES
					(
						lpBi->bmiHeader.biBitCount*
						lpBi->bmiHeader.biWidth
					)*j
				);
				for(i=0; i<lpBi->bmiHeader.biWidth; i++)
				{
					rgbQuad.rgbBlue=*lpRow;
					rgbQuad.rgbGreen=*(lpRow+1);
					rgbQuad.rgbRed=*(lpRow+2);
					*(lpRow)=*(lpRow+1)=*(lpRow+2)=
					(
						rgbQuad.rgbBlue+rgbQuad.rgbGreen+rgbQuad.rgbBlue
					)/3;
					lpRow+=3;
				}
			}
			break;
		}
	}

	::GlobalUnlock(m_hDIB);
	pos=GetFirstViewPosition();
	ptrView=(CGDIView *)GetNextView(pos);
	ASSERT(ptrView->IsKindOf(RUNTIME_CLASS(CGDIView)));
	ptrView->LoadBitmap(m_hDIB);
	AfxGetApp()->DoWaitCursor(FALSE);
}


void CGDIDoc::OnUpdateConvertBlackwhite(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable
	(
		m_nBmpFormat == BMP_FORMAT_24BIT ||
		m_nBmpFormat == BMP_FORMAT_256COLOR
	);
}

⌨️ 快捷键说明

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