Delphi Canvasで文字の輪郭パス座標を取得|TextOut+BeginPath+GetPathの使い方
このページでは、DelphiのCanvasを使って文字の輪郭パス座標を取得する方法を紹介します。
TextOutで文字を描画し、BeginPath~EndPathでパスを記録、GetPathでMoveTo・LineTo・Bezierなどの座標列を抽出する手順を、実用的なコード例とともに解説します。
取得した座標をTBitmapに描画する方法も含め、Canvas描画の内部構造を理解する一助となります。
procedure TForm1.Button1Click(Sender: TObject);
var bmp:TBitmap;
PathCount:Integer;
p,pp:TArray<TPoint>;
b:TBytes;
i,j,k:Integer;
s:string;
begin
//■文字の輪郭のパス座標(直線、ベジェ曲線)を取得する
bmp:=TBitmap.Create;
try
bmp.Width:=100;
bmp.Height:=100;
//フォントの設定
bmp.Canvas.Font.Name:='MS ゴシック';
//フォントサイズを設定する(ピクセル単位)
bmp.Canvas.Font.Height:=-80;
//背景モードを透明にする
//SetBkMode(Image1.Picture.Bitmap.Canvas.Handle,TRANSPARENT);
bmp.Canvas.Brush.Style:=bsClear;
//パスブラケットを開く
BeginPath(bmp.Canvas.Handle);
//輪郭パス座標を取得したい文字を描画
bmp.Canvas.TextOut(10,10,'鷗');
//パスブラケットを閉じる
EndPath(bmp.Canvas.Handle);
//パスの数を取得
PathCount:=GetPath(bmp.Canvas.Handle, nil, nil, 0);
if PathCount>0 then
begin
SetLength(p,PathCount);
SetLength(b,PathCount);
//パスを取得
GetPath(bmp.Canvas.Handle,@p[0],@b[0],PathCount);
end;
finally
bmp.Free;
end;
//■取得したパス座標をTMemoに出力する
for i := 0 to PathCount-1 do
begin
s:='';
if b[i]=PT_MOVETO then
s:='MoveTo'
else if (b[i]=PT_LINETO) or
(b[i]=(PT_LINETO or PT_CLOSEFIGURE)) then
s:='LIneTo'
else if b[i]=PT_BEZIERTO then
s:='Bezier';
Memo1.Lines.Add(
Format('種類:%s 座標:%d,%d',[s,p[i].X,p[i].Y])
);
end;
//■取得したパス座標をTBitmapに描画する
Image1.Picture.Bitmap.Width:=100;
Image1.Picture.Bitmap.Height:=100;
//白色で塗り潰す
Image1.Picture.Bitmap.Canvas.Brush.Style:=bsSolid;
Image1.Picture.Bitmap.Canvas.Brush.Color:=clWhite;
Image1.Picture.Bitmap.Canvas.FillRect(Image1.Picture.Bitmap.Canvas.ClipRect);
Image1.Picture.Bitmap.Canvas.Pen.Color:=rgb(255,0,0);
//取得したパスを描画
i:=0;
while i < PathCount do
begin
if b[i]=PT_MOVETO then //6
begin
//描画座標の移動
Image1.Picture.Bitmap.Canvas.MoveTo(p[i].X,p[i].Y);
inc(i);
end
else if (b[i]=PT_LINETO) or
(b[i]=(PT_LINETO+PT_CLOSEFIGURE)) then //2 or 3
begin
//線を引く
Image1.Picture.Bitmap.Canvas.LineTo(p[i].X,p[i].Y);
inc(i);
end
else if b[i] =PT_BEZIERTO then //4
begin
//ベジェ曲線を描く
j:=0;
while (b[i+j] and PT_BEZIERTO)=PT_BEZIERTO do inc(j);
SetLength(pp,j);
for k := 0 to j-1 do
pp[k]:=p[i+k];
Image1.Picture.Bitmap.Canvas.PolyBezierTo(pp);
inc(i,j);
end;
end;
end;
