fonttext.h

来自「Windows 图形编程 书籍」· C头文件 代码 · 共 477 行

H
477
字号
#pragma once

//-----------------------------------------------------------------------------------//
//              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   : fonttext.h				                                             //
//  Description: Font &  text routines and classes                                   //
//  Version    : 1.00.000, May 31, 2000                                              //
//-----------------------------------------------------------------------------------//

// convert point size to logical coordinate space size
int PointSizetoLogical(HDC hDC, int points, int divisor=1);

// Create a font as large as EM square size for accurate metrics
HFONT CreateReferenceFont(HFONT hFont, int & emsquare);

// justify text string within a left..right margin
BOOL TextOutJust(HDC hDC, int left, int right, int y, LPCTSTR lpStr, int nCount, bool bAllowNegative=false, TCHAR cBreakChar=' ');


// ABC extent of a text string
// ( A0, B0, C0 ) + ( A1, B1, C1 ) = ( A0, B0+C0+A1+B1, C1 }
BOOL GetTextABCExtent(HDC hDC, LPCTSTR lpString, int cbString, long * pHeight, ABC * pABC);

BOOL GetOpaqueBox(HDC hDC, LPCTSTR lpString, int cbString, RECT * pRect, int x, int y);

// Pixel-level precise text alignment
BOOL PreciseTextOut(HDC hDC, int x, int y, LPCTSTR lpString, int cbString);


class KLogFont
{
public:
	LOGFONT m_lf;

	KLogFont(int height, const TCHAR * typeface=NULL)
	{
		m_lf.lfHeight         = height;
		m_lf.lfWidth          = 0;
		m_lf.lfEscapement     = 0;
		m_lf.lfOrientation    = 0;
		m_lf.lfWeight         = FW_NORMAL;
		m_lf.lfItalic         = FALSE;
		m_lf.lfUnderline      = FALSE;
		m_lf.lfStrikeOut      = FALSE;
		m_lf.lfCharSet        = ANSI_CHARSET;
		m_lf.lfOutPrecision   = OUT_TT_PRECIS;
		m_lf.lfClipPrecision  = CLIP_DEFAULT_PRECIS;
		m_lf.lfQuality        = DEFAULT_QUALITY;
		m_lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;

		if ( typeface )
			_tcsncpy(m_lf.lfFaceName, typeface, LF_FACESIZE-1);
		else
			m_lf.lfFaceName[0] = 0;
	}

	HFONT CreateFont(void)
	{
		return ::CreateFontIndirect(& m_lf);
	}

	int GetObject(HFONT hFont)
	{
		return ::GetObject(hFont, sizeof(m_lf), & m_lf);
	}
};


template <int maxlength>
class KPlacement
{
public:
	GCP_RESULTS m_gcp;

	TCHAR		m_strOut[maxlength];
	int			m_dx    [maxlength];
	unsigned	m_order [maxlength];
	int			m_caret [maxlength];
	char		m_class [maxlength];
	WORD		m_glyphs[maxlength];

	DWORD GetPlacement(HDC hDC, const TCHAR * mess, DWORD flags=0, int maxextent=0)
	{
		memset(&m_gcp, 0, sizeof(m_gcp));
	
		m_gcp.lStructSize = sizeof(GCP_RESULTS);
		m_gcp.lpOutString = m_strOut;
		m_gcp.lpOrder     = m_order;
		m_gcp.lpDx        = m_dx;
		m_gcp.lpCaretPos  = m_caret;
		m_gcp.lpClass     = m_class;
		m_gcp.lpGlyphs    = m_glyphs;
		m_gcp.nGlyphs     = maxlength;

		return GetCharacterPlacement(hDC, mess, _tcslen(mess), maxextent, & m_gcp, flags);
	}

	BOOL GlyphTextOut(HDC hDC, int x, int y)
	{
		return ExtTextOut(hDC, x, y, ETO_GLYPH_INDEX, NULL, (LPCTSTR) m_glyphs, m_gcp.nGlyphs, m_dx);
	}
};


class KKerningPair
{
public:
	KERNINGPAIR * m_pKerningPairs;
	int			  m_nPairs;

	KKerningPair(HDC hDC)
	{
		m_nPairs = GetKerningPairs(hDC, 0, NULL);

		if ( m_nPairs==0 )
			m_pKerningPairs = NULL;
		else
		{
			m_pKerningPairs = new KERNINGPAIR[m_nPairs];
			assert(m_pKerningPairs);

			GetKerningPairs(hDC, m_nPairs, m_pKerningPairs);
		}
	}

	int GetKerning(TCHAR first, TCHAR second)
	{
		for (int i=0; i<m_nPairs; i++)
			if ( (m_pKerningPairs[i].wFirst ==first) && 
				 (m_pKerningPairs[i].wSecond==second) )
				 return m_pKerningPairs[i].iKernAmount;

		return 0;
	}

	~KKerningPair(void)
	{
		if ( m_pKerningPairs )
		{
			delete m_pKerningPairs;
			m_pKerningPairs = NULL;
		}
	}
};


class KGlyph
{
public:
	GLYPHMETRICS  m_metrics;
	BYTE *        m_pPixels;
	DWORD		  m_nAllocSize;
	DWORD		  m_nDataSize;
	int			  m_uFormat;

	KGlyph()
	{
		m_pPixels = NULL;
	}

	~KGlyph(void);

	DWORD GetGlyph(HDC hDC, UINT uChar, UINT uFormat, const MAT2 * pMat2=NULL);
	
	BOOL  DrawGlyphROP(HDC HDC, int x, int y, DWORD rop, COLORREF crBack, COLORREF crFore);
	BOOL  DrawGlyph(HDC HDC, int x, int y, int & dx, int & dy);
};


template <int MAX_POINTS>
class KGlyphOutline
{
public:
	POINT m_Point[MAX_POINTS];
	BYTE  m_Flag [MAX_POINTS];

	int   m_nPoints;

private:
	void AddPoint(int x, int y, BYTE flag)
	{
		if ( m_nPoints < MAX_POINTS )
		{
			m_Point[m_nPoints].x = x;
			m_Point[m_nPoints].y = y;
			m_Flag [m_nPoints]   = flag;
			m_nPoints ++;
		}
		else
			assert(false);
	}

	void AddQSpline(int x1, int y1, int x2, int y2)
	{
		assert(m_nPoints);

		// p0 p1 p2 -> p0 (p0+2p1)/3 (2p1+p2)/3, p2
		int x0 = m_Point[m_nPoints-1].x;
		int y0 = m_Point[m_nPoints-1].y;

		AddCSpline((x0+2*x1)/3, (y0+2*y1)/3, (2*x1+x2)/3, (2*y1+y2)/3, x2, y2);
	}

	void AddCSpline(int x1, int y1, int x2, int y2, int x3, int y3)
	{
		assert(m_nPoints);

		AddPoint(x1, y1, PT_BEZIERTO);
		AddPoint(x2, y2, PT_BEZIERTO);
		AddPoint(x3, y3, PT_BEZIERTO);
	}

	void MarkLast(BYTE flag)
	{
		assert(m_nPoints);
		m_Flag[m_nPoints-1] |= flag;
	}

	void Transform(int dx, int dy)
	{
		for (int i=0; i<m_nPoints; i++)
		{
			m_Point[i].x = (   m_Point[i].x + 32768 ) / 65536 + dx;
			m_Point[i].y = ( - m_Point[i].y + 32768 ) / 65536 + dy;
		}
	}

public:
	int DecodeTTPolygon(const TTPOLYGONHEADER * lpHeader, int size);

	BOOL Draw(HDC hDC, int x, int y)
	{
		Transform(x, y);
	
		return PolyDraw(hDC, m_Point, m_Flag, m_nPoints);
	}

	int DecodeOutline(KGlyph & glyph)
	{
		if ( (glyph.m_uFormat==GGO_NATIVE) || (glyph.m_uFormat==GGO_BEZIER) )
			return DecodeTTPolygon((const TTPOLYGONHEADER *) glyph.m_pPixels, glyph.m_nDataSize);
		else
			return 0;
	}

};


template <int MAX_POINTS>
int KGlyphOutline<MAX_POINTS>::DecodeTTPolygon(const TTPOLYGONHEADER * pHeader, int size)
{
	m_nPoints = 0;

	while ( size>sizeof(TTPOLYGONHEADER) )
    {
		int curvesize = pHeader->cb;

		size -= curvesize;

		if ( size<0 )
		{
			assert(false);
			break;
		}

		if (pHeader->dwType != TT_POLYGON_TYPE)
		{
			assert(false);
			break;
		}

		const POINT * p = (const POINT *) & pHeader->pfxStart;

		AddPoint(p[0].x, p[0].y, PT_MOVETO);

		const TTPOLYCURVE * pCurve = (const TTPOLYCURVE *) & pHeader[1];
		
		while ( (unsigned) pCurve < ( ((unsigned) pHeader) + curvesize) )
		{
			int i;

			p = (const POINT *) pCurve->apfx;

			switch ( pCurve->wType )
			{
				case TT_PRIM_LINE:		// polyline. 
					for (i=0; i<pCurve->cpfx; i++)
						AddPoint(p[i].x, p[i].y, PT_LINETO);
					break;

				case TT_PRIM_QSPLINE:	// quadratic B閦ier spline.
					assert(pCurve->cpfx>=2);

					for (i=0; i<(pCurve->cpfx-1); i++)
						if ( i==(pCurve->cpfx-2) )
							AddQSpline(p[i].x, p[i].y, p[i+1].x, p[i+1].y);
						else
							AddQSpline(
								p[i].x, 
								p[i].y, 
								( p[i].x + p[i+1].x ) / 2, 
								( p[i].y + p[i+1].y ) / 2);
					break;

				case TT_PRIM_CSPLINE:	// cubic Bezier spline
					assert((pCurve->cpfx % 3) ==0);
					for (i=0; i<pCurve->cpfx; i+=3)
						AddCSpline(p[i].x, p[i].y, p[i+1].x, p[i+1].y, p[i+2].x, p[i+2].y);
					break;

				default:
					assert(false);
					return 0;
			}

			pCurve = (const TTPOLYCURVE *) & pCurve->apfx[pCurve->cpfx];
		}

		MarkLast(PT_CLOSEFIGURE);

		pHeader = (const TTPOLYGONHEADER *) ((unsigned) pHeader + curvesize);
    }

	return m_nPoints;
}

BOOL BitmapTextOut(HDC hDC, int x, int y, const TCHAR * str, int count, int format = GGO_BITMAP);
BOOL BitmapTextOutROP(HDC hDC, int x, int y, const TCHAR * str, int count, DWORD rop);

BOOL OutlineTextOut(HDC hDC, int x, int y, const TCHAR * str, int count);

///////////////////////////////////////////////////////////

class KTextFormator
{
	typedef enum { MaxCharNo = 256 };

	float m_fCharWidth[MaxCharNo];
	float m_fHeight;
	float m_fLinespace;

public:

	BOOL  SetupPixel(HDC hDC, HFONT hFont, float pixelsize);
	BOOL  Setup(HDC hDC, HFONT hFont, float pointsize);

	float GetLinespace(void) const
	{
		return m_fLinespace;
	}

	BOOL  GetTextExtent(HDC hdc, LPCTSTR pString, int cbString, float & width, float & height);
	BOOL  TextOut(HDC hDC, int x, int y, LPCTSTR pString, int nCount);
	DWORD DrawText(HDC hDC, LPCTSTR pString, int nCount, const RECT * pRect, UINT uFormat);
};


BOOL ColorText(HDC hDC, int x, int y, LPCTSTR pString, int nCount, HBRUSH hFore);
 BOOL BitmapText(HDC hDC, int x, int y, LPCTSTR pString, int nCount, HBITMAP hBmp);
BOOL BitmapText2(HDC hDC, int x, int y, LPCTSTR pString, int nCount, HBITMAP hBmp);
BOOL OffsetTextOut(HDC hDC, int x, int y, LPCTSTR pStr, int nCount, 
				   int dx1, int dy1, COLORREF cr1,
				   int dx2, int dy2, COLORREF cr2);

BOOL DrawChar(HDC hDC, double x0, double y0, double x1, double y1, TCHAR ch);
void PathTextOut(HDC hDC, LPCTSTR pString, POINT point[], int no);
BOOL PathTextOut(HDC hDC, LPCTSTR pString);


// 3x3 average filter for any 8-bpp, 24-bpp, or 32-bpp frame buffer
template <int bytepp>
void Average(BYTE * pBits, int pitch, int width, int height)
{
	BYTE * buffer = new BYTE[pitch*2];

	for (int y=1; y<height; y++)
	{
		pBits += pitch; // first channel of pixel 0

		if ( y<(height-1) )
		{
			BYTE * P = pBits + bytepp;				// pixel 1
			BYTE * B = buffer + pitch * (y & 1);	// pixel 1..n-2	

			for (int x=1; x<(width-1); x++)
			{
				for (int b=0; b<bytepp; b++)
				{
					B[0] = ( P[-pitch-bytepp] + P[-pitch] + P[-pitch+bytepp] +
							 P[      -bytepp] + P[     0] + P[       bytepp] +
							 P[ pitch-bytepp] + P[ pitch] + P[ pitch+bytepp])/9;

					P ++;
					B ++;
				}
			}
		}

		if ( y>=2 )
		{
			memcpy(pBits-pitch+bytepp, buffer + pitch * ( 1 - (y & 1)), (width-2) * bytepp);
		}
	}

	delete [] buffer;
}


// Conver text string to bitmap
class KTextBitmap
{
public:
	
	HBITMAP		m_hBitmap;
	HDC		    m_hMemDC;
	HGDIOBJ		m_hOldBmp;
	int			m_width;
	int			m_height;
	int			m_dx;
	int			m_dy;
	BYTE *      m_pBits;

	BOOL Convert(HDC hDC, LPCTSTR pString, int nCount, int extra);

	void ReleaseBitmap(void)
	{
		if ( m_hOldBmp )
		{
			SelectObject(m_hMemDC, m_hOldBmp);
			m_hOldBmp = NULL;
		}

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

	KTextBitmap()
	{
		m_hBitmap = NULL;
		m_hMemDC  = NULL;
		m_hOldBmp = NULL;
	}

	~KTextBitmap()
	{
		if ( m_hMemDC )
		{
			DeleteObject(m_hMemDC);
			m_hMemDC = NULL;
		}
	}

	void Blur(void);

	BOOL Draw(HDC hDC, int x, int y, int rop=SRCCOPY)
	{
		return BitBlt(hDC, x - m_dx, y - m_dy, m_width, m_height,
			          m_hMemDC, 0, 0, rop);
	}

	BOOL RenderText(HDC hDC, int x, int y, const TCHAR * pString, int nCount);
};

// Embossing or Engraving by change edges only, good for non-solod background
void TransparentEmboss(HDC hDC, const TCHAR * pString, int nCount, COLORREF crTL, COLORREF crBR, int offset, int x, int y);
	

⌨️ 快捷键说明

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