//IntelliCADで袋文字を作る・・・の主要部分。
//TrueTypeFontから文字の輪郭を得る
//PointFx型をdoubleに変換
procedure PointFixToXY(var pfix:TPOINTFX;var x,y:double);
begin
x:=pfix.x.value+pfix.x.fract/65536.0;
y:=pfix.y.value+pfix.y.fract/65536.0;
end;
//GetGlyphOutLine
procedure TForm1.DrawGlyph(moji:LongInt);
var
GlyphSize: Longint; //グリフの大きさを保持
GlyphBits: Pointer; //グリフの開始ポインタを保持
P:Pointer; //作業用ポインタ
GlyphMetrics: TGlyphMetrics;//グリフのメトリックス
Matrix: TMat2; //回転行列を保持
Header:^TTPOLYGONHEADER; //アウトラインのヘッダー部分のポインタ
Curve:^TTPOLYCURVE; //アウトラインの情報のポインタ
PointA:^TPOINTFX; //固定小数点型のPointのポインタ
siz,n,nc:Longint;
i:integer;
typ,typC,num:integer;
x,y:Double;
stx,sty:Double;//開始座標を保持
begin
//回転行列を初期化
Matrix.eM11 := MakeFixed(1.0);
Matrix.eM12 := MakeFixed(0.0);
Matrix.eM21 := MakeFixed(0.0);
Matrix.eM22 := MakeFixed(1.0);
//確保するバッファの大きさを得る
//mojiはShift-JISコードで指定する
GlyphSize := GetGlyphOutline(Form1.Canvas.Handle, moji, GGO_NATIVE,
GlyphMetrics, 0, NIL, Matrix);
//情報をもらうバッファを用意
//確保できた先頭アドレスGlyphBitsを取得
GetMem(GlyphBits, GlyphSize);
//moji:アウトラインを取得しようとする文字のコード
//ANK文字の場合
//moji:=Ord((PChar('A'));
//全角文字の場合、moji はShift-JISコードに変換する必要がある
//var Chars:PChar;
//Chars:=PChar('あ');
//moji :=((Ord(Chars[0]) and $000000ff) shl 8) +(Ord(Chars[1]) and $000000ff);
//アウトライン情報を取得
//GlyphBitsを開始アドレスとして情報をもらう
GetGlyphOutline(Form1.Canvas.Handle, moji, GGO_NATIVE, GlyphMetrics,
GlyphSize,GlyphBits, Matrix);
//情報が書き込まれた先頭アドレスを作業用にコピー
P:=GlyphBits;
//最初のポインタ(格納先)にTPOLYGONHEADER構造体をあてはめ、
//ヘッダー部分の情報を読み出す。
Header:=P;
//Header.cbには全体のデータの大きさが格納されている
//全体のデータの大きさは、TTPOLYGONHEADERデータ+TPOLYCURVEデータの大きさ
//Header.dwTypeにはヘッダーのタイプが格納されている
//これが24であれば取得成功と判断する
//Header.pfxStartにはアウトラインの開始座標格納されている
//ヘッダーのタイプをここで取得しておく
//typ=24であれば取得成功と判断する
typ:=Header.dwType;
//ひとつの構造体の大きさ
n:=sizeof(TTPOLYGONHEADER);
while typ=24 do begin
//全体のデータの大きさはHeader.cbに格納されている
//TTPOLYGONHEADERデータ+TPOLYCURVEデータの大きさ
siz:=Header.cb;
//アウトラインの開始座標を取得
//取得したPointFXをDoubleに変換
PointFixToXY(Header.pfxStart,x,y);
stx:=x;sty:=y;//開始座標を記憶
//Headerの大きさの分だけポインタを進めて次の情報を読む
//開始ポインタからTPOLYGONHEADER構造体の大きさだけ進んだところが
//POLYCURVEの情報を取得する始まりとなる
Inc(Header);//POINERを進める
P:=Header;
//カーブの情報を読む
Curve:=P;
siz:=siz-n;//取得済みのTTPOLYGONHEADERの大きさを引く
//サイズが0になるまで情報を取得
while siz > 0 do begin
//カーブ開始座標=アウトラインの開始座標または前回の最終の座標
Memo1.Lines.Add(Format('%f,%f',[x,y]);
//カーブのタイプを取得
//カーブのタイプ 1=直線、2=曲線
typC:=Curve.wType;
Memo1.Lines.Add('Curve.wType:'+IntToStr(typC));
//カーブの種類1(直線)か2(曲線)でなければエラーと考える
if (typC<>1) and (typC<>2) then Break;
//格納されているカーブの数
num:=Curve.cpfx;
if num > 0 then begin
//座標の格納先にポインタを移動
PointA:=@Curve.apfx;
for i:=0 to num-1 do begin
//取得したPointFXをDoubleに変換
PointFixToXY(PointA^,x,y);
Memo1.Lines.Add(Format('%f,%f',[x,y]);
//直線であればここで描画用にセット
if typC=1 then begin
//直線の場合はこのまま描画座標として使える
;;
end
//曲線であれば座標を記憶するだけ
else begin
//曲線の場合は前回終了座標+曲線として取得した座標2点を
//スプラインに変換する必要がある。
//ここでは、座標を記憶するだけでスプライン変換はまとめて行う。
//Win95の場合はCureve点は前回終了座標を含めて3点とは限らず、
//4点の時がある。(つまりカーブ点が3つの時)
//その場合は2点目と3点目の中点をとって3点の倍数にし、
//3点ずつをスプライン変換する
// 第1点、第2点、第2点と第3点の中点の3点
// 第2点と第3点の中点、第3点、第4点の3点
;
end;
//次を読むためにポインターを進める
Inc(PointA);
end;
//次の処理のためにポインタを保持
P:=PointA;
end
else begin
//次を読むためにポインターを進める
Inc(Curve);
//次の処理のためにポインタを保持
P:=Curve;
end;
nc:=(sizeof(TTPOLYCURVE)+sizeof(POINTFX)*(num-1));
siz:=siz-nc;
//次のループのためにカーブを取得しておく
Curve:=P;
//曲線であれば極小線分の集合に変換して描画用に追加
if typC=2 then begin
//記憶した座標を2次B-SPLINEに変換
//取得した座標3点を(xA,yA)、(xB,yB)、(xC,yC)とすると
//x:=(xA-xB*2.0+xC)*sqr(t)+(xB*2.0-xA*2.0)*t+xA;
//y:=(yA-yB*2.0+yC)*sqr(t)+(yB*2.0-yA*2.0)*t+yA;
//のtの値を0.0〜1.0の間で変化させ、
//得られたx,yの値をプロットしていく
//tの値(0.0〜1.0)を細かく変化ほど滑らかな点の変化となる
;;
end;
//開始座標と終了座標が違っている時
if (stx<>x) or (sty<>y) then begin
//開始座標と終了座標をつなぐ処理
;;
end;
end;
Header:=P;
//終了ポインタからHeaderを読む
//Header.dwType=24の時は、これまでの処理を繰り返す
typ:=Header.dwType;
end;
//メモリを解放
FreeMem(GlyphBits, GlyphSize);
end;