dibsection.cpp

来自「Windows 图形编程 书籍」· C++ 代码 · 共 373 行

CPP
373
字号
//-----------------------------------------------------------------------------------//
//              Windows Graphics Programming: Win32 GDI and DirectDraw               //
//                             ISBN  0-13-086985-6                                   //
//                                                                                   //
//  Written            by  Yuan, Feng                             www.fengyuan.com   //
//  Copyright (c) 2000 by  Hewlett-Packard Company                www.hp.com         //
//  Published          by  Prentice Hall PTR, Prentice-Hall, Inc. www.phptr.com      //
//                                                                                   //
//  FileName   : dibsection.cpp						                                 //
//  Description: KDIBSection class, EMF rendering, AirBrush                          //
//  Version    : 1.00.000, May 31, 2000                                              //
//-----------------------------------------------------------------------------------//

#define STRICT
#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <assert.h>
#include <tchar.h>
#include <math.h>

#include "DIBSection.h"
#include "BitmapInfo.h"

// Copy from DIB section color table to DIB color table
UINT KDIBSection::GetColorTable(void)
{
	int width, height;

	if ( (GetDepth()>8) || ! Prepare(width, height) ) // create memory DC
		return 0;

	return GetDIBColorTable(m_hMemDC, 0, m_nClrUsed, m_pRGBQUAD);
}


// Copy from DIB's color table to DIB section's color table
UINT KDIBSection::SetColorTable(void)
{
	int width, height;

	if ( (GetDepth()>8) || ! Prepare(width, height) ) // create memory DC
		return 0;

	return SetDIBColorTable(m_hMemDC, 0, m_nClrUsed, m_pRGBQUAD);
}


void KDIBSection::DecodeDIBSectionFormat(TCHAR desp[])
{
	DIBSECTION dibsec;

	if ( GetObject(m_hBitmap, sizeof(DIBSECTION), & dibsec) )
	{
		KDIB::DecodeDIBFormat(desp);
		_tcscat(desp, _T("   "));
		DecodeDDB(GetBitmap(), desp + _tcslen(desp));
	}
	else
		_tcscpy(desp, _T("Invalid DIB Section"));
}


BOOL KDIBSection::CreateDIBSection(HDC hDC, CONST BITMAPINFO * pBMI, UINT iUsage, HANDLE hSection, DWORD dwOffset)
{
	PVOID pBits = NULL;
	
	HBITMAP hBmp = ::CreateDIBSection(hDC, pBMI, iUsage, & pBits, hSection, dwOffset);

	int typ = GetObjectType(hBmp);
	int size = GetObject(hBmp, 0, NULL);

	if ( hBmp )
	{
		ReleaseDDB();	// free the previous object
		ReleaseDIB();	
		
		m_hBitmap = hBmp;	// Use DDB handle to store DIB Section Handle

//		MEMORY_BASIC_INFORMATION mbi;
//		VirtualQuery(pBits, & mbi, sizeof(mbi));

		int nColor = GetDIBColorCount(pBMI->bmiHeader);
		int nSize  = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * nColor;
		
		BITMAPINFO * pDIB = (BITMAPINFO *) new BYTE[nSize];

		if ( pDIB==NULL )
			return FALSE;

		memcpy(pDIB, pBMI, nSize);	// copy header and color table

		AttachDIB(pDIB, (PBYTE) pBits, DIB_BMI_NEEDFREE);
		GetColorTable();
		return TRUE;
	}
	else
		return FALSE;
}


// Search for the largest DIBSection 
HBITMAP LargestDIBSection(BITMAPINFO * pBMI)
{
	HBITMAP hBmp;

	int mins = 1;			// 1	   pixel
	int maxs = 1024 * 128;	// 16 Giga pixels

	while ( true ) // search for largest DDB
	{
		int mid = (mins + maxs)/2;

		pBMI->bmiHeader.biWidth = mid;
		pBMI->bmiHeader.biHeight= mid;

		hBmp = CreateDIBSection(NULL, pBMI, DIB_RGB_COLORS, NULL, NULL, NULL);

		if ( hBmp )
		{
			pBMI->bmiHeader.biWidth = mid+1;
			pBMI->bmiHeader.biHeight= mid+1;

			HBITMAP h = CreateDIBSection(NULL, pBMI, DIB_RGB_COLORS, NULL, NULL, NULL);

			if ( h==NULL )
				return hBmp;

			DeleteObject(h);
			DeleteObject(hBmp);

			mins = mid+1;
		}
		else
			maxs = mid;
	}

	return NULL;
}


// Draw a 3D rectangle frame with color shades
void Frame(HDC hDC, int nFrame, COLORREF crFrame, int left, int top, int right, int bottom)
{
	int red   = GetRValue(crFrame);
	int green = GetGValue(crFrame);
	int blue  = GetBValue(crFrame);
	RECT rect = { left, top, right, bottom };

	for (int i=0; i<nFrame; i++)
	{
		HBRUSH hBrush = CreateSolidBrush(RGB(red, green, blue));
		FrameRect(hDC, & rect, hBrush);
		DeleteObject(hBrush);

		if ( i<nFrame/2 )
		{
			red   = red   * 19/20;	// darker
			green = green * 19/20;
			blue  = blue  * 19/20;
		}
		else
		{
			red   = red   * 19/18; if ( red>255 )   red  = 255;	// lighter
			green = green * 19/18; if ( green>255 ) green= 255;
			blue  = blue  * 19/18; if ( blue>255 )  blue = 255;
		}

		InflateRect(&rect, -1, -1);
	}
}


// Window contents saver using DIBSECTION
BOOL SaveWindow(HWND hWnd, bool bClient, int nFrame, COLORREF crFrame)
{
	RECT wnd;

	if ( bClient )
	{
		if ( ! GetClientRect(hWnd, & wnd) )
			return FALSE;
	}
	else
	{
		if ( ! GetWindowRect(hWnd, & wnd) )
			return FALSE;
	}

	KBitmapInfo bmi;
	KDIBSection dibsec;

	bmi.SetFormat(wnd.right - wnd.left + nFrame * 2, wnd.bottom - wnd.top + nFrame *2, 24, BI_RGB);

	if ( dibsec.CreateDIBSection(NULL, bmi.GetBMI(), DIB_RGB_COLORS, NULL, NULL) )
	{
		int width, height;
		dibsec.Prepare(width, height); // creates memory DC, select dibsec into memDC

		if ( nFrame )
		{
			Frame(dibsec.m_hMemDC, nFrame, crFrame, 0, 0, width, height); 

			TCHAR Title[128];
			GetWindowText(hWnd, Title, sizeof(Title)/sizeof(Title[0]));
			SetBkMode(dibsec.m_hMemDC, TRANSPARENT);
			SetTextColor(dibsec.m_hMemDC, RGB(0xFF, 0xFF, 0xFF));
			TextOut(dibsec.m_hMemDC, nFrame, (nFrame-20)/2, Title, _tcslen(Title));
		}

		HDC hDC;
		if ( bClient )
			hDC = GetDC(hWnd);
		else
			hDC = GetWindowDC(hWnd);
		
		BitBlt(dibsec.m_hMemDC, nFrame, nFrame, width - nFrame * 2, height - nFrame * 2, hDC, 0, 0, SRCCOPY);
		ReleaseDC(hWnd, hDC);

		return dibsec.SaveFile(NULL);
	}
	return FALSE;
}


KTarga24::KTarga24()
{
	m_hFile	       = INVALID_HANDLE_VALUE;
	m_hFileMapping = INVALID_HANDLE_VALUE;
}


KTarga24::~KTarga24()
{
	ReleaseDDB();
	ReleaseDIB();

	if ( m_hFileMapping!=INVALID_HANDLE_VALUE )
		CloseHandle(m_hFileMapping);

	if ( m_hFile != INVALID_HANDLE_VALUE )
		CloseHandle(m_hFile);
}


BOOL KTarga24::Create(int width, int height, const TCHAR * pFileName)
{
	if ( width & 3 )	// avoid compatiblity problem with TGA
		return FALSE;

	ImageHeader tgaheader;

	memset(& tgaheader, 0, sizeof(tgaheader));
	tgaheader.IDLength  = sizeof(tgaheader.ID);
	tgaheader.ImgType   = 2;
	tgaheader.Width     = width;
	tgaheader.Height    = height;
	tgaheader.PixelSize = 24;
	strcpy(tgaheader.ID, "BitmapShop");

	m_hFile = CreateFile(pFileName, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 
		NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

	if ( m_hFile==INVALID_HANDLE_VALUE )
		return FALSE;

	int imagesize = (width*3+3)/4*4 * height;

	m_hFileMapping = CreateFileMapping(m_hFile, NULL, PAGE_READWRITE, 0, sizeof(tgaheader) + imagesize, NULL);
	if ( m_hFileMapping==INVALID_HANDLE_VALUE )
		return FALSE;

	DWORD dwWritten = NULL;
	WriteFile(m_hFile, & tgaheader, sizeof(tgaheader), &dwWritten, NULL);
	SetFilePointer(m_hFile, sizeof(tgaheader) + imagesize, 0, FILE_BEGIN);
	SetEndOfFile(m_hFile);

	KBitmapInfo bmi;

	bmi.SetFormat(width, height, 24, BI_RGB);

	return CreateDIBSection(NULL, bmi.GetBMI(), DIB_RGB_COLORS, m_hFileMapping, sizeof(tgaheader));
}


BOOL RenderEMF(HENHMETAFILE hemf, int width, int height, const TCHAR * tgaFileName)
{
	KTarga24 targa;

	int w = (width+3)/4*4;
	
	if ( targa.Create(w, height, tgaFileName) )
	{
		targa.Prepare(w, height);

		// DIBSECTION dibsec;
		// GetObject(targa.GetBitmap(), sizeof(DIBSECTION), & dibsec);

		BitBlt(targa.m_hMemDC, 0, 0, width, height, NULL, 0, 0, WHITENESS); // clear
		
		RECT rect = { 0, 0, width, height };

		for (int h=0; h<=height; h+=128 )
		{
			HRGN hRgn = CreateRectRgn(0, h, width, h+128);

			SelectClipRgn(targa.m_hMemDC, hRgn);
			DeleteObject(hRgn);
			
			if ( ! PlayEnhMetaFile(targa.m_hMemDC, hemf, &rect) ) 
				return FALSE;
		}
 	}
	
	return FALSE;
}


void KAirBrush::Apply(HDC hDC, int x, int y)
{
	BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };

	AlphaBlend(hDC, x-m_nWidth/2, y-m_nHeight/2, m_nWidth, m_nHeight, m_hMemDC, 0, 0, m_nWidth, m_nHeight, blend);
}


void KAirBrush::Create(int width, int height, COLORREF color)
{
	Release();

	BYTE * pBits;
	BITMAPINFO Bmi = { { sizeof(BITMAPINFOHEADER), width, height, 1, 32, BI_RGB } };

	m_hBrush  = CreateDIBSection(NULL, & Bmi, DIB_RGB_COLORS, (void **) & pBits, NULL, NULL);
	m_hMemDC  = CreateCompatibleDC(NULL);
	m_hOld    = (HBITMAP) SelectObject(m_hMemDC, m_hBrush);
	m_nWidth  = width;
	m_nHeight = height;

	
	// solid color circle, on white background
	{	
		PatBlt(m_hMemDC, 0, 0, width, height, WHITENESS);

		HBRUSH hBrush = CreateSolidBrush(color);
		SelectObject(m_hMemDC, hBrush);
		SelectObject(m_hMemDC, GetStockObject(NULL_PEN));
		
		Ellipse(m_hMemDC, 0, 0, width, height);
		
		SelectObject(m_hMemDC, GetStockObject(WHITE_BRUSH));
		DeleteObject(hBrush);
	}
	
	BYTE * pPixel = pBits;
    double xx;
	for (int y=0; y<height; y++)
	for (int x=0; x<width;  x++, pPixel+=4)
	{
		
	    xx=( (x-width/2) * (x-width/2) + (y-height/2) * (y-height/2) ) * 255 / (max(width, height)/2);
	   int  dis   = (int)  sqrt(xx );

		BYTE alpha = (BYTE) max(min(255-dis, 255), 0);

		pPixel[0] = pPixel[0] * alpha / 255;
		pPixel[1] = pPixel[1] * alpha / 255;
		pPixel[2] = pPixel[2] * alpha / 255;
		pPixel[3] = alpha;
	}
}

⌨️ 快捷键说明

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