fonttext.cpp

来自「Windows 图形编程 书籍」· C++ 代码 · 共 1,012 行 · 第 1/2 页

CPP
1,012
字号

class KLineBreaker
{
	LPCTSTR m_pText;
	int     m_nLength;
	int		m_nPos;

	BOOL SkipWhite(void)
	{
		// skip white space
		while ( (m_nPos<m_nLength) && (m_pText[m_nPos]<=' ') )
			m_nPos ++;

		return m_nPos < m_nLength;
	}

	// m_pText[m_nPos] is the starting of a word, find its end
	void GetWord(void)
	{
		while ( (m_nPos<m_nLength) && (m_pText[m_nPos]>' ') )
			m_nPos ++;
	}

	BOOL Breakable(int pos)
	{
		if ( m_pText[pos]<=' ') // space character is breakable
			return true;

		if ( pos && (m_pText[pos-1]<=' ') ) // having space before it
			return true;

		if ( pos && (m_pText[pos-1]=='-') ) // having hypen before it
			return true;

		return false;
	}

public:

	float textwidth, textheight;

	KLineBreaker(LPCTSTR pText, int nCount)
	{
		m_pText   = pText;
		m_nPos    = 0;

		if ( nCount<=0 )
			m_nLength = _tcslen(m_pText);
		else
			m_nLength = nCount;
	}

	BOOL GetLine(KTextFormator & formator, HDC hDC, int width, int & begin, int & end)
	{
		const float epsilon = (float) 0.001;

		if ( ! SkipWhite() )
			return FALSE;
	
		begin = m_nPos; // first no white space to diplay
		
		// add words until the line is too long
		while ( SkipWhite() )
		{
			// first end of word
			GetWord();

			formator.GetTextExtent(hDC, m_pText + begin, m_nPos - begin, textwidth, textheight);

			// break out if it's too long
			if ( textwidth >= (width-epsilon) )
				break;
		}

		if ( textwidth > width )
			for (int p=m_nPos-1; p>begin; p--) // find a place to break a word into two
				if ( Breakable(p) )
				{   // can we fit now ?
					formator.GetTextExtent(hDC, m_pText + begin, p - begin, textwidth, textheight);
					if ( textwidth<=(width+epsilon) )
					{
						m_nPos = p;
						break;
					}
				}

		end = m_nPos;

		return TRUE;
	}
};


BOOL KTextFormator::TextOut(HDC hDC, int x, int y, LPCTSTR pString, int nCount)
{
	int Dx[MAX_PATH];

	int lastx = 0;
	float sum = 0.0;

	int sumdx = 0;
	for (int i=0; i<nCount; i++)
	{
		sum = sum + m_fCharWidth[pString[i]];

		int newx = (int) (sum + 0.5);
		Dx[i] = newx - lastx;
		lastx = newx;

		sumdx += Dx[i];
	}

//	TCHAR temp[64];
//	sprintf(temp, "sum: %8.5f sumdx : %d\n", sum, sumdx);
//	OutputDebugString(temp);

	return ExtTextOut(hDC, x, y, 0, NULL, pString, nCount, Dx);
}


DWORD KTextFormator::DrawText(HDC hDC, LPCTSTR pString, int nCount, const RECT * pRect, UINT uFormat)
{
	if ( pString==NULL )
		return 0;

	KLineBreaker breaker(pString, nCount);

	int   x     = pRect->left;
	float y     = (float) pRect->top;
	int width = pRect->right - pRect->left;
	int begin, end;

	while ( breaker.GetLine(* this, hDC, width, begin, end) )
	{
		while ( (end>begin) && (pString[end-1]<=' ') )
			end --;

//		TCHAR mess[64];
//		sprintf(mess, "width %8.5f\n", breaker.textwidth);
//		OutputDebugString(mess);

		TextOut(hDC, x, (int)(y+0.5), pString + begin, end - begin);

		y += breaker.textheight;
	}
	
	return 0;
}


BOOL ColorText(HDC hDC, int x, int y, LPCTSTR pString, int nCount, HBRUSH hFore)
{
	HGDIOBJ hOld      = SelectObject(hDC, hFore);

	RECT rect;
	GetOpaqueBox(hDC, pString, nCount, & rect, x, y);
	PatBlt(hDC, rect.left, rect.top, 
		rect.right-rect.left, rect.bottom - rect.top, PATINVERT);

	int      oldBk    = SetBkMode(hDC, TRANSPARENT);
	COLORREF oldColor = SetTextColor(hDC, RGB(0, 0, 0));
	
	TextOut(hDC, x, y, pString, nCount);
	SetBkMode(hDC, oldBk);
	SetTextColor(hDC, oldColor);
	
	BOOL rslt = PatBlt(hDC, rect.left, rect.top, 
					rect.right-rect.left, rect.bottom - rect.top, PATINVERT);

	SelectObject(hDC, hOld);

	return rslt;
}


BOOL BitmapText(HDC hDC, int x, int y, LPCTSTR pString, int nCount, HBITMAP hBmp)
{
	RECT rect;
	GetOpaqueBox(hDC, pString, nCount, & rect, x, y);

	HDC hMemDC = CreateCompatibleDC(hDC);
	HGDIOBJ hOld = SelectObject(hMemDC, hBmp);

	BitBlt(hDC, rect.left, rect.top, 
				rect.right-rect.left, 
				rect.bottom - rect.top, hMemDC, 0, 0, SRCINVERT);

	int      oldBk    = SetBkMode(hDC, TRANSPARENT);
	COLORREF oldColor = SetTextColor(hDC, RGB(0, 0, 0));
	
	TextOut(hDC, x, y, pString, nCount);
	SetBkMode(hDC, oldBk);
	SetTextColor(hDC, oldColor);
	
	BOOL rslt = BitBlt(hDC, rect.left, rect.top, 
					rect.right-rect.left, rect.bottom - rect.top, 
					hMemDC, 0, 0, SRCINVERT);

	SelectObject(hMemDC, hOld);
	DeleteObject(hMemDC);

	return rslt;
}


BOOL BitmapText2(HDC hDC, int x, int y, LPCTSTR pString, int nCount, HBITMAP hBmp)
{
	RECT rect;
	GetOpaqueBox(hDC, pString, nCount, & rect, x, y);

	HDC hMemDC = CreateCompatibleDC(hDC);
	HGDIOBJ hOld = SelectObject(hMemDC, hBmp);

	BeginPath(hDC);
	SetBkMode(hDC, TRANSPARENT);
	TextOut(hDC, x, y, pString, nCount);
	EndPath(hDC);
	SelectClipPath(hDC, RGN_COPY);

	BOOL rslt = BitBlt(hDC, rect.left, rect.top, 
				rect.right-rect.left, 
				rect.bottom - rect.top, hMemDC, 0, 0, SRCCOPY);

	SelectObject(hMemDC, hOld);
	DeleteObject(hMemDC);

	return rslt;
}

BOOL OffsetTextOut(HDC hDC, int x, int y, LPCTSTR pStr, int nCount, 
				   int dx1, int dy1, COLORREF cr1,
				   int dx2, int dy2, COLORREF cr2)
{
	COLORREF cr = GetTextColor(hDC);
	int		 bk = GetBkMode(hDC);

	if ( bk==OPAQUE )
	{
		RECT rect;

		GetOpaqueBox(hDC, pStr, nCount, & rect, x, y);

		rect.left  += min(min(dx1, dx2), 0);
		rect.right += max(max(dx1, dx2), 0);
		rect.top   += min(min(dy1, dy2), 0);
		rect.bottom+= max(max(dy1, dy2), 0);

		ExtTextOut(hDC, x, y, ETO_OPAQUE, & rect, NULL, 0, NULL);
	}

	SetBkMode(hDC, TRANSPARENT);

	if ( (dx1!=0) || (dy1!=0) )
	{
		SetTextColor(hDC, cr1);
		TextOut(hDC, x + dx1, y + dy1, pStr, nCount);
	}

	if ( (dx1!=0) || (dy1!=0) )
	{
		SetTextColor(hDC, cr2);
		TextOut(hDC, x + dx2, y + dy2, pStr, nCount);
	}

	SetTextColor(hDC, cr);

	BOOL rslt = TextOut(hDC, x, y, pStr, nCount);
	SetBkMode(hDC, bk);

	return rslt;
}


double dis(double x0, double y0, double x1, double y1)
{
	x1 -= x0;
	y1 -= y0;

	return sqrt( x1 * x1 + y1 * y1 );
}

const double pi = 3.141592654;


BOOL DrawChar(HDC hDC, double x0, double y0, double x1, double y1, TCHAR ch)
{
	x1 -= x0;
	y1 -= y0;

	int escapement = 0;

	if ( (x1<0.01) && (x1>-0.01) )
		if ( y1>0 )
			escapement = 2700;
		else
			escapement =  900;
	else
	{
		double angle = atan(-y1/x1);
		
		escapement = (int) ( angle * 180 / pi * 10 + 0.5);

//		TCHAR temp[MAX_PATH];
//		sprintf(temp, "%8.5f %8.5f %8.5f %8.5f -> %d\n", x0, y0, x1, y1, escapement);
//		OutputDebugString(temp);
	}

	LOGFONT lf;
	GetObject(GetCurrentObject(hDC, OBJ_FONT), sizeof(lf), &lf);

	if ( lf.lfEscapement != escapement )
	{
		lf.lfEscapement = escapement;

		HFONT hFont = CreateFontIndirect(&lf);

		if ( hFont==NULL )
			return FALSE;

		DeleteObject(SelectObject(hDC, hFont));
	}
	
	TextOut(hDC, (int)x0, (int)y0, &ch, 1);

	return TRUE;
}


void PathTextOut(HDC hDC, LPCTSTR pString, POINT point[], int no)
{
//	MoveToEx(hDC, point[0].x, point[0].y, NULL);

//	for (int i=1; i<no; i++)
//		LineTo(hDC, point[i].x, point[i].y);

	double x0 = point[0].x;
	double y0 = point[0].y;

	for (int i=1; i<no; i++)
	{
		double x1 = point[i].x;
		double y1 = point[i].y;

		double curlen = dis(x0, y0, x1, y1);

		while ( true )
		{
			int length;
			GetCharWidth(hDC, * pString, * pString, & length);

			if ( curlen < length )
				break;

			double x00 = x0; 
			double y00 = y0;

			x0 += (x1-x0) * length / curlen;
			y0 += (y1-y0) * length / curlen;

			DrawChar(hDC, x00, y00, x0, y0, * pString);

			curlen -= length;
			pString ++;

			if ( * pString==0 )
			{
				i = no;
				break;
			}
		}
	}
}



BOOL PathTextOut(HDC hDC, LPCTSTR pString)
{
	if ( ! FlattenPath(hDC) ) // conver to polyline
		return FALSE;

	POINT * pp;
	BYTE  * pf;

	int no = GetPath(hDC, NULL, NULL, 0); // query point no

	if ( no<2 )	// at least two points
		return FALSE;

	pp = new POINT[no];
	pf = new  BYTE[no];

	no = GetPath(hDC, pp, pf, no); // real data

	PathTextOut(hDC, pString, pp, no); // aligning

	delete pp;
	delete pf;

	return TRUE;
}


void KTextBitmap::Blur(void)
{
	Average<4>(m_pBits, m_width*4, m_width, m_height);
}



BOOL KTextBitmap::RenderText(HDC hDC, int x, int y, const TCHAR * pString, int nCount)
{
	HGDIOBJ hOldFont = SelectObject(m_hMemDC, GetCurrentObject(hDC, OBJ_FONT));
	SetTextColor(m_hMemDC, GetTextColor(hDC));
	SetBkMode   (m_hMemDC, GetBkMode(hDC));
	SetBkColor  (m_hMemDC, GetBkColor(hDC));
	
	SetTextAlign(m_hMemDC, TA_LEFT | TA_TOP);
	BOOL rslt = TextOut(m_hMemDC, m_dx+x, m_dy+y, pString, nCount);
	
	SelectObject(m_hMemDC, hOldFont);

	return rslt;
}


BOOL KTextBitmap::Convert(HDC hDC, LPCTSTR pString, int nCount, int extra)
{
	RECT rect;

	ReleaseBitmap();

	SaveDC(hDC);

	SetTextAlign(hDC, TA_LEFT | TA_TOP);
	GetOpaqueBox(hDC, pString, nCount, & rect, 0, 0);

	m_width  = rect.right - rect.left + extra * 2;
	m_height = rect.bottom - rect.top + extra * 2;

	BITMAPINFOHEADER bmih;
	memset(& bmih, 0, sizeof(bmih));
	bmih.biSize     = sizeof(BITMAPINFOHEADER);
	bmih.biWidth    = m_width;
	bmih.biHeight   = m_height;
	bmih.biPlanes   = 1;
	bmih.biBitCount = 32;

	m_hBitmap = CreateDIBSection(hDC, (const BITMAPINFO *) & bmih, DIB_RGB_COLORS, (void **) & m_pBits, NULL, 0);
	m_hMemDC  = CreateCompatibleDC(hDC);
	m_hOldBmp = SelectObject(m_hMemDC, m_hBitmap);

	m_dx = extra - min(rect.left, 0);
	m_dy = extra;

	SetBkColor  (m_hMemDC, GetBkColor(hDC));

	rect.left   = 0;
	rect.top    = 0;
	rect.right  = m_width;
	rect.bottom = m_height;
	ExtTextOut(m_hMemDC, 0, 0, ETO_OPAQUE, & rect, NULL, 0, NULL);
	
	RenderText(hDC, 0, 0, pString, nCount);
	RestoreDC(hDC, -1);

	return TRUE;
}


// 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)
{
	KTextBitmap bmp;

	// generate a mask bitmap with top-left and bottom-right edges
	SetBkMode(hDC, OPAQUE);
	SetBkColor(hDC, RGB(0xFF, 0xFF, 0xFF));					  // white background
	SetTextColor(hDC, RGB(0, 0, 0));
	bmp.Convert(hDC, pString, nCount, offset*2);			  // black TL edge

	SetBkMode(hDC, TRANSPARENT);
	bmp.RenderText(hDC, offset*2, offset*2, pString, nCount); // black BR edge

	SetTextColor(hDC, RGB(0xFF, 0xFF, 0xFF));				  // white main text
	bmp.RenderText(hDC, offset, offset, pString, nCount);


	// mask destination with top-left and bottom-right edges
	bmp.Draw(hDC, x, y, SRCAND);

	// create a color bitmap with top-left and bottom-right edges
	SetBkColor(hDC, RGB(0, 0, 0));							  // black background
	SetTextColor(hDC, crTL);
	bmp.Convert(hDC, pString, nCount, offset);				  // TL edge

	SetBkMode(hDC, TRANSPARENT);
	SetTextColor(hDC, crBR);
	bmp.RenderText(hDC, offset*2, offset*2, pString, nCount); // BR edge

	SetTextColor(hDC, RGB(0, 0, 0));				
	bmp.RenderText(hDC, offset, offset, pString, nCount);	  // black main text

	// draw color top-left and bottom-right edges
	bmp.Draw(hDC, x, y, SRCPAINT);
}

⌨️ 快捷键说明

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