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 + -
显示快捷键?