[TTF字体]提取TTF字体的轮廓(二)

来源:互联网 发布:现货软件开发 编辑:程序博客网 时间:2024/04/28 03:18

一. TTF字体轮廓解析与绘制


1.1 数据提取

void CHYTTFCharacter::InitTTPOLY(){if(0 == m_pTTPOLYData)// GetGlyphOutline提取到的字体轮廓数据{return;}TTPOLYGONHEADER* pTTPOLYGONHEADER = 0;TTPOLYCURVE* pTTPOLYCURVE = 0;STTTPOLYGONHEADER* pSTTTPOLYGONHEADER = 0;STTTPOLYCURVE* pSTTTPOLYCURVE = 0;unsigned int nTTPOLYDataLen = 0;unsigned char* pTTPOLYData = m_pTTPOLYData;unsigned int nCURVELen = 0;unsigned char* pCURVE = 0;int nTemp = 0;while(nTTPOLYDataLen < m_nTTPOLYDataLen){pSTTTPOLYGONHEADER = new STTTPOLYGONHEADER;m_stTTPOLYGONHEADERVector.push_back(pSTTTPOLYGONHEADER);pTTPOLYGONHEADER = (TTPOLYGONHEADER*)pTTPOLYData;memcpy(&(pSTTTPOLYGONHEADER->m_TTPOLYGONHEADER), pTTPOLYGONHEADER, sizeof(TTPOLYGONHEADER));pCURVE = pTTPOLYData + sizeof(TTPOLYGONHEADER);nCURVELen = sizeof(TTPOLYGONHEADER);while(nCURVELen < pTTPOLYGONHEADER->cb){pTTPOLYCURVE = (TTPOLYCURVE*)pCURVE;pSTTTPOLYCURVE = new STTTPOLYCURVE;pSTTTPOLYCURVE->Init(pTTPOLYCURVE->wType, pTTPOLYCURVE->cpfx);pSTTTPOLYGONHEADER->m_stTTPOLYCURVEVector.push_back(pSTTTPOLYCURVE);memcpy(pSTTTPOLYCURVE->m_p_apfx, pCURVE + sizeof(TTPOLYCURVE) - sizeof(POINTFX), sizeof(POINTFX) * pTTPOLYCURVE->cpfx);nTemp = sizeof(TTPOLYCURVE) + sizeof(POINTFX) * (pTTPOLYCURVE->cpfx - 1);pCURVE += nTemp;nCURVELen += nTemp;}nTTPOLYDataLen += pTTPOLYGONHEADER->cb;pTTPOLYData += pTTPOLYGONHEADER->cb;}}


1.2 绘制

void CHYTTFCharacter::Draw(HDC hDC, int nOffsetX, int nOffsetY){int nXTemp, nYTemp, nXBegin, nYBegin;STTTPOLYGONHEADER* pSTTTPOLYGONHEADER = 0;STTTPOLYCURVE* pSTTTPOLYCURVE = 0;int nCountH = m_stTTPOLYGONHEADERVector.size();int nCountC = 0;int i = 0, j = 0, k = 0;for(i = 0; i < nCountH; ++i){pSTTTPOLYGONHEADER = m_stTTPOLYGONHEADERVector[i];nXBegin = nOffsetX + FIXEDToInt(pSTTTPOLYGONHEADER->m_TTPOLYGONHEADER.pfxStart.x);nYBegin = nOffsetY - FIXEDToInt(pSTTTPOLYGONHEADER->m_TTPOLYGONHEADER.pfxStart.y);::MoveToEx(hDC, nXBegin, nYBegin, NULL);nCountC = pSTTTPOLYGONHEADER->m_stTTPOLYCURVEVector.size();for(j = 0; j < nCountC; ++j){pSTTTPOLYCURVE = pSTTTPOLYGONHEADER->m_stTTPOLYCURVEVector[j];// 这里可以根具线条的类型做样条曲线的绘制, 这样字体会绘制的比较圆滑.***********注意注意*****************// 我这里直接使用直线连接, 有些地方可能绘制的比较粗糙.************************注意注意******************for(k = 0; k < pSTTTPOLYCURVE->m_cpfx; ++k){::LineTo(hDC, nOffsetX + FIXEDToInt(pSTTTPOLYCURVE->m_p_apfx[k].x), nOffsetY - FIXEDToInt(pSTTTPOLYCURVE->m_p_apfx[k].y));}}::LineTo(hDC, nXBegin, nYBegin);}}


1.3 调用

void CTestTypeDlg::PaintType(){CClientDC dc(this);HDC hDC = dc.GetSafeHdc();//创建字体CFont font;VERIFY(font.CreateFont(70, 0, 0, 0, FW_NORMAL, FALSE, FALSE, 0, ANSI_CHARSET,OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, "宋体"));CFont *pOldFont = dc.SelectObject(&font);// 定义并初始化变换矩阵MAT2 mat2;memset(&mat2, 0, sizeof(mat2));mat2.eM11.value = 1;mat2.eM22.value = 1;GLYPHMETRICS metrics;// 保存字符相关信息DWORD dwDataSize = 0;// 初始化字符数据缓冲区大小//……// 通过函数GetGlyphOutline()确定存储字符结构的空间//char nChar = 'A';wchar_t nChar = L'A';::TextOut(dc.m_hDC, 0, 0, "A", 1);//dwDataSize = pDC->GetGlyphOutline((UINT)nChar, GGO_NATIVE, &metrics, 0, NULL, &mat2);dwDataSize = ::GetGlyphOutlineW(dc.m_hDC, (UINT)nChar, GGO_NATIVE, &metrics, 0, NULL, &mat2);if ((dwDataSize != 0) && (dwDataSize != GDI_ERROR)){CHYTTFCharacter hyTTFCharacter;hyTTFCharacter.InitTTPOLY(dwDataSize);dwDataSize = ::GetGlyphOutlineW(dc.m_hDC, (UINT)nChar,GGO_NATIVE,&metrics, dwDataSize, hyTTFCharacter.m_pTTPOLYData, &mat2);hyTTFCharacter.InitTTPOLY();int nXOffset = 200;int nYOffset = 200;hyTTFCharacter.Draw(dc.m_hDC, nXOffset, nYOffset);}}

// 感觉封装的不是很好!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!


1.4 网上的一些参考


http://blog.csdn.net/kingstar158/article/details/7257347

HDC hDC = pDC->GetSafeHdc();//创建字体CFont font;VERIFY(font.CreateFont(m_iFontHeight, 0, 0, 0,FW_NORMAL, FALSE, FALSE, 0, ANSI_CHARSET,OUT_DEFAULT_PRECIS,      CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS,m_sFontFaceName));CFont *pOldFont = pDC->SelectObject(&font);//定义并初始化变换矩阵MAT2 mat2;memset(&mat2, 0, sizeof(mat2));mat2.eM11 = 1;mat2.eM22 = 1;GLYPHMETRICS metrics;    //保存字符相关信息DWORD dwDataSize = 0;//初始化字符数据缓冲区大小//……//通过函数GetGlyphOutline()确定存储字符结构的空间dwDataSize = pDC->GetGlyphOutline(nChar, GGO_NATIVE, &metrics, 0, NULL, &mat2);if ((dwDataSize != 0) && (dwDataSize != GDI_ERROR)){//创建保存字符数据缓冲区大小LPBYTE pPixels = new BYTE[dwDataSize];ASSERT( pPixels != NULL );TTPOLYGONHEADER *pHeader = (TTPOLYGONHEADER*)pPixels;dwDataSize = pDC->GetGlyphOutline(nChar,GGO_NATIVE,&metrics, dwDataSize, pPixels, &mat2);while(dwDataSize > 0){//计算字符轮廓的起点,转换坐标int xOld = MapFXY(pHeader->pfxStart.x);int yOld = MapFXY(pHeader->pfxStart.y);//根据TTF字体结构获取字符轮廓::MoveToEx(hDC,iXpos + xOld,iYpos - yOld,NULL);TTPOLYCURVE *pCurrentCurve = (TTPOLYCURVE*)(pHeader + 1);  int remainByte = pHeader->cb - sizeof(TTPOLYGONHEADER);while (remainByte > 0){CPoint lpPoint[1000];CPoint bezi[2];int index;for (index = 0; index < pCurrentCurve->cpfx; ++index){lpPoint[index].x = iXpos + MapFXY(pCurrentCurve->apfx[index].x);lpPoint[index].y = iYpos - MapFXY(pCurrentCurve->apfx[index].y);}switch (pCurrentCurve->wType){case TT_PRIM_LINE:case TT_PRIM_QSPLINE:for (index =0; index < pCurrentCurve->cpfx; index++){::LineTo(hDC,lpPoint[index].x,lpPoint[index].y);}break;default:MessageBox(_T("字体不支持"));break;}int count = sizeof(TTPOLYCURVE) + (pCurrentCurve->cpfx -1)*sizeof(POINTFX);pCurrentCurve = (TTPOLYCURVE*)((char*)pCurrentCurve  + count);remainByte -= count;}::LineTo(hDC,iXpos + xOld, iYpos - yOld);dwDataSize -= pHeader->cb;pHeader = (TTPOLYGONHEADER*)((char*)pHeader + pHeader->cb);}delete [] pPixels;}    }


二. 应用

        TTF字体是一种矢量字体好处就是可以随便放大缩小旋转等例如做"仿射变换". 而对于位图字体如果位图字体很大时做这些变换都是对位图上的每一个点来操作的效率会很低而如果对矢量数据操作的话要操作的点是有限的(比位图操作的点要少很多). 所以当你提取到了TTF字体的轮廓数据后你想干嘛都可以了(做一些文字的二维处理三维处理等都可以)..

       但有个问题当我提取了TTF字体的轮廓后我想填充这些轮廓不知怎么填充!!!!!!!!!! (暂时没深入了解,) WindowsAPI TextOutDrawText是怎么填充的呢??????????