//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;