What is the formula to draw a line in x, y space given b-spline coordinates in a TrueType font?
Please note that Truetype allows for bspline curves AND straight lines within a glyph definition.
If you need to change these commands into a series of MoveTo's and LineTo's you can use the following:
Convert the TrueType data into a list of hinted coordinates. This is something your OS can do for you (following code uses the Windows APIs).
Walk all coordinates and translate the curves into lines (see code sniplet below):
procedure TGlyphEvaluator.EvaluateFromBuffer( Action: TGlyphEvaluatorAction );
var
H : TTPOLYGONHEADER;
C : TTPOLYCURVE;
Points : array of TPointFX;
P, PE : DWORD;
i, j : Integer;
F : Double;
PA, PB, PC : TPoint;
begin
SetLength( Points, 10 );
P := 0;
repeat
// Eat the polygon header
Move( FBuffer[ P ], H, sizeof( H ) );
if H.dwType <> TT_POLYGON_TYPE then Break; // Sanity check!
PE := P + H.cb;
Inc( P, sizeof( H ) );
Points[ 0 ] := H.pfxStart;
// Eat all the curve records
while P < PE do begin
// Get the curve record
Move( FBuffer[ P ], C, sizeof( C ) - sizeof( TPointFX ) );
Inc( P, sizeof( C ) - sizeof( TPointFX ) );
// Get the points from the curve record
if Length( Points ) < C.cpfx + 1 then Setlength( Points, C.cpfx + 1 );
Move( FBuffer[ P ], Points[ 1 ], sizeof( TPointFX ) * C.cpfx );
Inc( P, sizeof( TPointFX ) * C.cpfx );
case C.wType of
TT_PRIM_LINE: begin
MoveTo( Action, Points[ 0 ].x.value, Points[ 0 ].y.value );
for i := 1 to C.cpfx do
LineTo( Action, Points[ i ].x.value, Points[ i ].y.value );
end;
TT_PRIM_QSPLINE: begin
MoveTo( Action, Points[ 0 ].x.value, Points[ 0 ].y.value );
PA.X := Points[ 0 ].x.value;
PA.Y := Points[ 0 ].y.value;
for i := 1 to C.cpfx - 1 do begin // DrawQSpline is called C.cpfx - 1 times
PB.X := Points[ i ].x.value;
PB.Y := Points[ i ].y.value;
PC.X := Points[ i + 1 ].x.value;
PC.Y := Points[ i + 1 ].y.value;
if i < C.cpfx - 1 then begin
PC.X := ( PC.X + PB.X ) div 2;
PC.Y := ( PC.Y + PB.Y ) div 2;
end;
for j := 1 to 8 do begin
F := j / 8;
LineTo( Action, Round( ( PA.x - 2 * PB.x + PC.x ) * Sqr( F ) + ( 2 * PB.x - 2 * PA.x ) * F + PA.x ),
Round( ( PA.y - 2 * PB.y + PC.y ) * Sqr( F ) + ( 2 * PB.y - 2 * PA.y ) * F + PA.y ) );
end;
PA := PC;
end;
end;
end;
// Update last point.
Points[ 0 ] := Points[ C.cpfx ];
end;
MoveTo( Action, Points[ 0 ].x.value, Points[ 0 ].y.value );
LineTo( Action, H.pfxStart.x.value, H.pfxStart.y.value );
until P >= Longword( Length( FBuffer ) );
end;