linux提取ttf字体轮廓,提取Windows的TTF字体轮廓矢量数据

Windows系统的TTF字体具有字体优美、可无级缩放等优点,最适合应用在CAD类图形处理等软件中。直接分析TTF字体的文件格式并读出每个字的轮廓矢量是相当困难的,我们可以借助API函数来方便地获得这些数据。

---- 调用函数GetGlyphOutline可以得到一个字的轮廓矢量或者位图。

---- 函数原型如下:

DWORD GetGlyphOutline(

HDC hdc,            // 设备句柄

UINT uChar,    // 将要读取的字符

UINT uFormat,    // 返回数据的格式

LPGLYPHMETRICS lpgm,  // GLYPHMETRICS结构地址

DWORD cbBuffer,  // 数据缓冲区的大小

LPVOID lpvBuffer,  // 数据缓冲区的地址

CONST MAT2 *lpmat2 // 转置矩阵的地址

);

---- 其中,参数uFormat取值如下:

GGO_NATIVE  - 要求函数返回字符的轮廓矢量数据;

GGO_METRICS - 函数仅返回GLYPHMETRICS结构至lpgm;

参数lpgm指向GLYPHMETRICS结构,该结构描述字符的位置。

参数lpmat2指向字符的转置矩阵。

---- 本文以下C++ Builder程序示范如何在画布上以指定的大小绘制字符串。

---- 首先,建立一个新项目,在主窗口上放置一个Image控件,一个Edit控件,一个Button控件;然后,在Button的点击事件中加入如下代码:

#include < stdlib.h >

void __fastcall TForm1::Button1Click(TObject *Sender)

{

TRect ClipRect = Rect(0,0,Image1->Width,Image1->Height);

Image1->Picture = 0;

StretchTextRect(Image1->Canvas, ClipRect, Edit1->Text);

}

---- 添加如下子程序:

//---------------------

void TForm1::StretchTextRect(TCanvas

*pCanvas, TRect ClipRect, AnsiString Text)

{

pCanvas->Font->Size = 100;

pCanvas->Font->Name = “宋体";

pCanvas->Pen->Color = clBlack;

pCanvas->Pen->Mode = pmCopy;

pCanvas->Pen->Style = psSolid;

pCanvas->Pen->Width = 1;

int XSize = ClipRect.Width() / Text.Length();

int YSize = ClipRect.Height();

MAT2 mat2;  // 转置矩阵,不用变换

mat2.eM11.value = 1;mat2.eM11.fract = 0;

mat2.eM12.value = 0;mat2.eM12.fract = 0;

mat2.eM21.value = 0;mat2.eM21.fract = 0;

mat2.eM22.value = 1;mat2.eM22.fract = 0;

GLYPHMETRICS gm,gmm;

// 首先获得字符的位置矩阵,存入gm

GetGlyphOutlineA(pCanvas->Handle,0x0b0a1,

GGO_METRICS,&gm,0,NULL,&mat2);

char *ptr = Text.c_str();

TRect TheRect;

for(int i = 0;i < Text.Length();) {

int c1 = (unsigned char)*ptr;

int c2 = (unsigned char)*(ptr + 1);

UINT nChar;

TheRect.Left = i * XSize + ClipRect.Left;

TheRect.Top = ClipRect.Top;

TheRect.Right = (i + 2) * XSize + ClipRect.Left;

TheRect.Bottom = ClipRect.Top + YSize;

if(c1 > 127) {  // 当前字符是汉字

nChar = c1 * 256 + c2;

ptr+=2;i+=2;

}

else {   // 字母或数字

nChar = c1;

ptr++;i++;

}

// 获得当前字符数据的数组的大小

DWORD cbBuffer = GetGlyphOutlineA(pCanvas->

Handle,nChar,GGO_NATIVE,&gmm,0,NULL,&mat2);

if(cbBuffer == GDI_ERROR) break;

void *lpBuffer = malloc(cbBuffer);

if(lpBuffer != NULL) {

// 读入数据置缓冲区

if(GetGlyphOutlineA(pCanvas->

Handle,nChar,GGO_NATIVE,

&gmm,cbBuffer,lpBuffer,&mat2) != GDI_ERROR) {

// 分析数据并绘制字符

TMemoryStream *MBuffer = new TMemoryStream();

MBuffer->Write(lpBuffer,cbBuffer);

MBuffer->Position = 0;

for(;MBuffer->Position < MBuffer->Size;) {

int CurPos = MBuffer->Position;

TTPOLYGONHEADER polyheader;

int ptn = 0;

MBuffer->Read(&polyheader,sizeof(polyheader));

ptn++;

for(int j = 0;j < (int)(polyheader.cb

- sizeof(polyheader));) {

WORD wtype,cpfx;

MBuffer->Read(&wtype,sizeof(WORD));

MBuffer->Read(&cpfx,sizeof(WORD));

MBuffer->Position += cpfx * sizeof(POINTFX);

j += sizeof(WORD) * 2 + cpfx * sizeof(POINTFX);

if(wtype == TT_PRIM_LINE) ptn += cpfx;

else ptn += (cpfx - 1) * 3 + 1;

}

TPoint *pts = new TPoint[ptn+1];  // 存储多边形顶点

MBuffer->Position = CurPos;

ptn = 0;

MBuffer->Read(&polyheader,sizeof(polyheader));

TPoint pt0 = POINTFX2TPoint(polyheader.pfxStart,TheRect,&gm);

pts[ptn++] = pt0;

for(int j = 0;j < (int)(polyheader.cb - sizeof(polyheader));) {

TPoint pt1;

WORD wtype,cpfx;

MBuffer->Read(&wtype,sizeof(WORD));

MBuffer->Read(&cpfx,sizeof(WORD));

POINTFX *pPfx = new POINTFX[cpfx];

MBuffer->Read((void *)pPfx,cpfx * sizeof(POINTFX));

j += sizeof(WORD) * 2 + cpfx * sizeof(POINTFX);

if(wtype == TT_PRIM_LINE) { // 直线段

for(int i = 0;i < cpfx;i++) {

pt1 = POINTFX2TPoint(pPfx[i],TheRect,&gm);

pts[ptn++] = pt1;

}

}

else {  // Bezier曲线

TPoint p0,p1,p2,p3,p11,p22,pp0,pp1,pp2,pt11,pt22;

int i;

for(i = 0;i < cpfx-1;i++) {

pt11 = POINTFX2TPoint(pPfx[i],TheRect,&gm);

pt22 = POINTFX2TPoint(pPfx[i+1],TheRect,&gm);

pp0 = pts[ptn-1];

pp1 = pt11;

pp2.x = (pt11.x + pt22.x)/2;

pp2.y = (pt11.y + pt22.y)/2;

p0 = pp0;

p1.x = pp0.x/3 + 2 * pp1.x/3;

p1.y = pp0.y/3 + 2 * pp1.y/3;

p2.x = 2 * pp1.x/3 + pp2.x/3;

p2.y = 2 * pp1.y/3 + pp2.y/3;

p3 = pp2;

for(float t = 0.0f;t <= 1.0f;t += 0.5f) {

float x = (1-t)*(1-t)*(1-t)*p0.x+

3*t*(1-t)*(1-t)*p1.x+ 3*t*t

*(1-t)*p2.x + t*t*t*p3.x;

float y = (1-t)*(1-t)*(1-t)*p0.y

+ 3*t*(1-t)*(1-t)*p1.y+3

*t*t*(1-t)*p2.y + t*t*t*p3.y;

pts[ptn].x = x;

pts[ptn].y = y;

ptn++;

}

}

pt1 = POINTFX2TPoint(pPfx[i],TheRect,&gm);

pts[ptn++] = pt1;

}

delete pPfx;

}

pts[ptn] = pts[0]; // 封闭多边形

pCanvas->Brush->Color = clWhite;

pCanvas->Pen->Mode = pmXor;

pCanvas->Pen->Style = psClear;

pCanvas->Brush->Style = bsSolid;

pCanvas->Polygon(pts,ptn);

delete pts;

}

delete MBuffer;

}

free(lpBuffer);

}

}

}

//---------------------

TPoint TForm1::POINTFX2TPoint(POINTFX pf,

TRect TheRect,GLYPHMETRICS *gm)

{

TPoint point;

float fx,fy;

fx = pf.x.value + pf.x.fract / 65536.0f + 0.5f;

fx = fx

/ (float)(gm->gmBlackBoxX + gm->gmptGlyphOrigin.x)

* (float)TheRect.Width() + (float)TheRect.Left;

fy = pf.y.value + pf.y.fract / 65536.0f + 0.5f;

fy = ((float)gm->gmBlackBoxY - fy)

/ (float)(gm->gmBlackBoxX + gm->gmptGlyphOrigin.x)

* (float)TheRect.Height() + (float)TheRect.Top;

point.x = int(fx);

point.y = int(fy);

return point;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值