windows矢量字体点阵数据的提取(转)
1.提取原理
在windows系统当中提取矢量字体的字模有很多方法,下面介绍一种利用GetGlyphOutline来实现字模点数数据的提取。
GetGlyphOutline是windows系统的API函数,利用这个函数,可以方便快捷提取矢量字体字符点阵数据,并且可以很好的支持从文本文件中读取字符。面对用大量字符数据输入时,获取点阵数据所需要的时间量也是很少。
GetGlyphOutline函数声明如下:
DWORD GetGlyphOutline( HDC hdc, // handle to DC UINT uChar, // character to query UINT uFormat, // data format LPGLYPHMETRICS lpgm, // glyph metrics DWORD cbBuffer, // size of data buffer LPVOID lpvBuffer, // data buffer CONST MAT2 *lpmat2 // transformation matrix );
GetGlyphOutline函数是windows系统的API函数,在使用VC++开发时,这个函数被封装在DC类中,是DC类的一个成员函数。
2.字符点阵数据提取的实现
当应用程序调用GetGlyphOutline函数时,这个函数可以通过LPGLYPHMETRIC这个结构体指针返回我们所需要的字符点阵数据所占的矩形区域信息。该函数所得到的点阵数据是的是gmBlackBoxX与gmBlackBoxY所组成的最小矩形区域的点阵数据,如图1所示,而我们在实际应用中所需要显示的字符点阵数据却是gmCellIncX与gmCellIncY所组成的大矩形区域内的点阵数据,所以当我们调用GetGlyphOutline所得到的字符的点阵数据时,还需要把最小矩形以外的边框区域加上,这需要通过相应的的矩阵变换把最小矩形的点阵数据区平移到以gmCellIncX与gmCellIncY所组成的大矩形区域的中间位置。
在windows 操作系统当中实践表明,GetGlyphOutlinep这个函数返回的结构体LPGLYPHMETRICS中gmCellIncY这个数值返回是0,这是操作系统版本本身的原因,因此需要通过另外的方法来获取。我们采用GetTextExtent(CString,int)和GetTextMetrics(TEXTMETRIC *tm),通过以上两个函数我们可以获取字符的宽度与高度信息,然后通过相应矩阵变换的变换,就可以得到所需的字符字模点阵数据!GetGlyphOutline 函数获取的字符点阵数据的宽度是4字节对齐,所以要做4字节对齐处理。对于宽度不是以8位对齐的字符数据,应该在补足8位后,再做4字节对齐处理。获取字符点阵数据的程序如下:
CString str ( “华”);//字符 CDC dc;//CDC 类,这个类有GetGlyphOutline这个方法 dc.CreateDC(_T("DISPLAY"),NULL, NULL, NULL); CFont *poldfont=dc.SelectObject(&m_font);//字体设置 TEXTMETRIC tm;//这是个结构体这个结构体包含了字体的信息, GLYPHMETRICSpGL;//这个结构体包含了一个基本字符单元的位置与方向的信息 MAT2 mat2 = {{0,1},{0, 0},{0, 0},{0, 1}}; //转换矩阵 dc.GetTextMetrics(&tm); //获取当前选择字体宽度与高度 int bitWidth=tm.tmAveCharWidth;//字符宽度的平均值 int bitHeigh =tm.tmHeight;//字符高度 int ch = str.GetAt(0); int len =dc.GetGlyphOutline(ch,GGO_BITMAP, &pGL, 0, NULL, &mat2);//所得//到数据缓存区的大小 CSize cs = pDC->GetTextExtent(str,1);//重新获得字符的宽度,修正值 int widthEx =cs.cx; bitWidth =widthEx; if(bitWidth %8==0) { bitWidth= bitWidth /8; //字符宽度8位对齐,不足8位,补齐8位 } else { bitWidth= bitWidth /8+1; } int boxXByteWidth = ALIGN(pGL.gmBlackBoxX, 4);// 最小矩形宽度,4字节对齐 int FontOffY = tm.tmAscent - pGL.gmptGlyphOrigin.y;//获取Y方向偏移 int FontOffX = pGL.gmptGlyphOrigin.x < 0 ? 0 :pGL.gmptGlyphOrigin.x;//获取X方向偏移 int bufSize = bitWidth* bitHeigh;//字符点阵数据大小 unsigned char *pBuf =new unsigned char[bufSize];//databuf if(pBuf != NULL) { memset(pBuf, 0, bufSize); if(len > 0) { unsigned char *pSrc = newunsigned char [len]; unsigned char *pDest =(unsigned char *)pBuf; dc.GetGlyphOutline(ch, GGO_BITMAP,&pGL, len, pSrc, &mat2);//得到点阵数据 for(int i = 0; i < len / boxXByteWidth;i++) { //copy databuf to pDest memcpy(pDest + i * (bitWidth/8), pSrc + i * boxXByteWidth, boxXByteWidth); } //转换矩阵,把GetGlyphOutline得到的点阵转换成含有边框的点阵数据 MartixCovert(pDest,bitWidth,bitHeigh ,FontOffX, FontOffY); } } dc.SelectObject(poldfont); dc.DeleteDC(); delete []pSrc; delete []pDest;
下面是点阵数据的显示效果