フォントスタイルにItalicを使っても、重なった部分を描くようにするには?

解決


かんとく  2010-03-11 02:10:09  No: 37989

お世話になっております。

Delphi2007,XPです。

1文字ずつImageのCanvas上にDrawTextで文字を書いています。
フォントスタイルにItalicを使うと、文字の右上の端が切れてしまいます。
重なった部分がうまく描けていないんだと思います。

brush.style:=bsClear;
をしても、うまくいきません。

重なった部分を描くには、どのようにしたらよろしいでしょうか?

よろしくいお願いします。

----------------------------------------------------

Form上にImage1を置いています。

procedure TForm1.Image1Click(Sender: TObject);
var
  flg:Cardinal ;
  DTRect: TRect;

  x,y:integer;
  w,h:integer;
  t:string;
  i: Integer;

begin

image1.canvas.brush.style:=bsClear;

image1.canvas.font.size:=20;

image1.canvas.font.style:=[fsItalic];

t:='あいうえおかきくけこ';
x:=0;
y:=0;

  for i := 0 to trunc(length(t)/2)-1 do
  begin

      w:=image1.canvas.TextWidth(copy(t,i*2+1,2));
      h:=image1.canvas.TextHeight(copy(t,i*2+1,2));

      dtrect.Left:=x;
      dtrect.top:=y;
      dtrect.Right :=x+w;
      dtrect.Bottom :=y+h;

      flg:=DT_center + DT_SINGLELINE + DT_VCENTER;

      DrawText( image1.Canvas.Handle, pchar( copy(t,i*2+1,2) ),  -1, dtRect, flg );

      x:=x+w;

  end;

end;


tor  2010-03-11 03:13:31  No: 37990

DrawTextを使っているので、指定した矩形の外にはみ出た分がクリップされているのではないかと思います。
・DT_CENTERをDT_LEFTに変えてみる
・DT_NOCLIPを指定する
のいずれかをやってみたらどうなるでしょうか?

ちなみに、斜体の文字が次の文字のセルに食い込む量をオーバーハングと呼びます。
TextWidthはオーバーハングの分を含めた幅を返すので、
そのままxに足していくと、文字間がオーバーハングの分だけ余分に空いてしまいます。
斜体の文字を自分で並べる場合は、オーバーハングの分を文字間から引くのが正しいらしいです。
(オーバーハングの幅は、GetTextMetricsしてtmOverhangを見るとわかります)


かんとく  2010-03-11 04:17:09  No: 37991

ありがとうございます。

・DT_CENTERをDT_LEFTに変えてみる
→現象は変わりませんでした。

・DT_NOCLIPを指定する
→うまくいきました。

ただ、調べてみたところ、TextWidthはオーバーハングの分を含めない幅を返しているようです。

下の3パターンでは、どれも終点のx座標が200となり、余分な空白が足されてないように思います。

逆に、オーバーハングの幅を知りたいです。
(オーバーハングの幅は、GetTextMetricsしてtmOverhangを見るとわかります)がよく分かりませんでした。教えていただいたのに、すみません。

オーバーハングの幅のとり方を、自分で調べてみますが、もしよかったら、教えていただけると、ありがたいです。

分かったら、解決チェックします。

---------------------------------------------------------

procedure TForm1.Image1Click(Sender: TObject);
var
  flg:Cardinal ;
  DTRect: TRect;

  x,y:integer;
  w,h:integer;
  t:string;
  i: Integer;

begin

image1.canvas.brush.style:=bsClear;

image1.canvas.font.size:=20;

image1.canvas.font.style:=[fsItalic];

t:='あいうえおかきくけこ';
x:=0;
y:=0;

  for i := 0 to trunc(length(t)/2)-1 do
  begin

      w:=image1.canvas.TextWidth(copy(t,i*2+1,2));
      h:=image1.canvas.TextHeight(copy(t,i*2+1,2));

      dtrect.Left:=x;
      dtrect.top:=y;
      dtrect.Right :=x+w;
      dtrect.Bottom :=y+h;

      flg:=DT_center + DT_SINGLELINE + DT_VCENTER;

      DrawText( image1.Canvas.Handle, pchar( copy(t,i*2+1,2) ),  -1, dtRect, flg );

      x:=x+w;

  end;

      t:=inttostr(x)+'DT_NOCLIPなし';

      w:=image1.canvas.TextWidth(t);

      dtrect.Left:=x;
      dtrect.top:=y;
      dtrect.Right :=x+w;
      dtrect.Bottom :=y+h;

      DrawText( image1.Canvas.Handle, pchar( t ),  -1, dtRect, flg );

///////////////////////////////////

  t:='あいうえおかきくけこ';
  x:=0;
  y:=y+h;

  for i := 0 to trunc(length(t)/2)-1 do
  begin

      w:=image1.canvas.TextWidth(copy(t,i*2+1,2));
      h:=image1.canvas.TextHeight(copy(t,i*2+1,2));

      dtrect.Left:=x;
      dtrect.top:=y;
      dtrect.Right :=x+w;
      dtrect.Bottom :=y+h;

      flg:=DT_center + DT_SINGLELINE + DT_VCENTER+DT_NOCLIP;

      DrawText( image1.Canvas.Handle, pchar( copy(t,i*2+1,2) ),  -1, dtRect, flg );

      x:=x+w;

  end;

  t:=inttostr(x)+'DT_NOCLIPあり';
  w:=image1.canvas.TextWidth(t);

      dtrect.Left:=x;
      dtrect.top:=y;
      dtrect.Right :=x+w;
      dtrect.Bottom :=y+h;

      DrawText( image1.Canvas.Handle, pchar( t ),  -1, dtRect, flg );

///////////////////////////////////////

image1.canvas.font.style:=[];

t:='あいうえおかきくけこ';
x:=0;
y:=y+h;

  for i := 0 to trunc(length(t)/2)-1 do
  begin

      w:=image1.canvas.TextWidth(copy(t,i*2+1,2));
      h:=image1.canvas.TextHeight(copy(t,i*2+1,2));

      dtrect.Left:=x;
      dtrect.top:=y;
      dtrect.Right :=x+w;
      dtrect.Bottom :=y+h;

      flg:=DT_center + DT_SINGLELINE + DT_VCENTER;

      DrawText( image1.Canvas.Handle, pchar( copy(t,i*2+1,2) ),  -1, dtRect, flg );

      x:=x+w;

  end;

      t:=inttostr(x)+'style:=[]';

      w:=image1.canvas.TextWidth(t);

      dtrect.Left:=x;
      dtrect.top:=y;
      dtrect.Right :=x+w;
      dtrect.Bottom :=y+h;

      DrawText( image1.Canvas.Handle, pchar( t ),  -1, dtRect, flg );

end;


かんとく  2010-03-11 04:24:56  No: 37992

たまたま気付いたんですが、FontSize=20の文字を、10個並べて描いたら、全体の幅が200になるということは、FontSizeを指定する数字は、文字の横幅のピクセル数を指定する数字ということですか?
それとも、今回たまたまFontSize20を10個描いたら幅が200になっただけで、200にならない場合もありますか?
(誰に質問しているか分かりませんが、知っている方がいたらお願いします。)


tor  2010-03-11 05:04:48  No: 37993

>下の3パターンでは、どれも終点のx座標が200となり、余分な空白が足されてないように思います。
TextWidthが使っているのはGetTextExtentPoint32で、MSDNによればオーバーハングを含んだ幅を返すとなっています。
ただ、TrueTypeフォントではオーバーハングは常に0だという記述もあるので、あまり意味がなかったかもしれませんね。
1文字ずつではなく一かたまりで出力した場合と比べて、差がなければまあそれでいいんじゃないでしょうか。

一応、TextMetricを取るには次のようにします。

var tm: TEXTMETRIC;
...
GetTextMetrics(Canvas.Handle, tm);

これでtm.tmOverhangの値を見るとオーバーハングの値がわかります。
他にも色々、選択されたフォントの性質を調べるのに役立つ値が入っています。

> FontSizeを指定する数字は、文字の横幅のピクセル数を指定する数字ということですか?
いいえ、Sizeはあくまでも「高さ」です。
欧米の文字は高さが揃っていて、幅は文字ごとにまちまち(プロポーショナル)というのが普通ですから。
ただ、日本語は正方形のマスの中に文字を収める文化ですから
MSゴシック(Pが付かない方)のような固定ピッチフォントを選んだ場合、
幅と高さが一致しているという可能性も高いでしょう。

ちなみにフォントが固定ピッチフォントか、平均的な幅はいくつかといった情報もTEXTMETRICで得られます。


tor  2010-03-11 05:14:18  No: 37994

言い忘れていましたが、TFontのSizeはヘルプを見るとわかるように
ピクセルではなくポイント数です。(Heightの方はピクセル数です)
計算式もヘルプに載っていますが、例えば96DPIの解像度なら
20ポイントは約27ピクセルになります。

Font.Sizeを20に設定して結果が200ピクセルだったということなら、
PixelsPerInchがちょうど72だったか、でなければ本当に偶然の一致でしょう。


KHE00221  2010-03-11 07:00:23  No: 37995

ABCじゃないの???


Taka  2010-03-11 11:01:29  No: 37996

>フォントスタイルにItalicを使うと、文字の右上の端が切れてしまいます
私の場合、文字列の最後にスペースを置いています。
それで文字切れは無くなります。


かんとく  2010-03-11 20:33:04  No: 37997

ありがとうございます。

torさん

TEXTMETRICのことよく分かりました。
とても役に立ちそうです。

フォントの指定の数字のことも分かりました。
ありがとうございました。

Takaさん

今回は、文字列をそのまま描くのではなく、文字列からCopyで1文字ずつ取り出して描くので、1文字描くたびにスペースを入れるのは無理そうなので、今回はこの方法では無理そうです。
でも、ありがとうございました。


Taka  2010-03-12 05:09:24  No: 37998

解決済みとなっていますが
こんな感じでどうでしょう?

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  i, W, H: integer;
  S: string;
  DRect: TRect;
  Flg:Cardinal ;
begin
  S:='あいうえおかきくけこ';
  Canvas.Brush.Style:= bsClear;
  Canvas.font.size:=20;
  Canvas.font.style:=[fsItalic];
  for i := 0 to trunc(length(S)/2)-1 do
  begin
    w:=canvas.TextWidth(copy(S,i*2+1,2));
    h:=canvas.TextHeight(copy(S,i*2+1,2));
    Drect.Left:=x;
    Drect.top:=y;
    Drect.Right :=x+w+ Canvas.TextWidth(' ');
    Drect.Bottom :=y+h;
    flg:=DT_center + DT_SINGLELINE + DT_VCENTER;
    DrawText(Canvas.Handle, pchar(copy(S,i*2+1,2)),  -1, DRect, flg );
    x:=x+w;
  end;
end;


KHE00221  2010-03-12 09:12:13  No: 37999

http://khe00221.image.coocan.jp/index.php?FrontPage%2FComponent2%2FCSV

の StringListLabel でも見てくれ


かんとく  2010-03-13 02:02:20  No: 38000

Taka さん

ありがとうございます。
試してみましたが、教えてもらったぶんでは、文字描画の開始位置がもともとの描画開始位置から右にずれてしまいます。
そこで、DT_centerをDT_leftにしたら、描画開始位置はもともとのものとそろいました。
これは、DT_NOCLIPを追加した場合と同じように描けたので、この方法もよいと思います。
ありがとうございました。

KHE00221 さん

ありがとうございます。
KHE00221さんはいろいろ作っていて、とてもすごいと思いました。
また分からないことがあったら、たずねたいなと思いました。
よろしくお願いします。
 

----------------------------------------------------

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  r,i, W, H: integer;
  S: string;
  DRect: TRect;
  Flg:Cardinal ;

  StartX:integer;

begin

  StartX:=x;

  canvas.MoveTo(startx,0 );
  canvas.LineTo(startx,height );

  S:='あいうえおかきくけこ';
  Canvas.Brush.Style:= bsClear;
  Canvas.font.size:=20;
  Canvas.font.style:=[fsItalic];

  //①教えてもらったぶん
  for i := 0 to trunc(length(S)/2)-1 do
  begin

    w:=canvas.TextWidth(copy(S,i*2+1,2));
    h:=canvas.TextHeight(copy(S,i*2+1,2));
    Drect.Left:=x;
    Drect.top:=y;
    Drect.Right :=x+w+ Canvas.TextWidth(' ');
    Drect.Bottom :=y+h;
    flg:=DT_center + DT_SINGLELINE + DT_VCENTER;
    DrawText(Canvas.Handle, pchar(copy(S,i*2+1,2)),  -1, DRect, flg );
    x:=x+w;

  end;

  canvas.MoveTo(x,0 );
  canvas.LineTo(x,height );

  //②もともとのぶん
  x:=StartX;
  y:=y+h;
  for i := 0 to trunc(length(S)/2)-1 do
  begin

    w:=canvas.TextWidth(copy(S,i*2+1,2));
    h:=canvas.TextHeight(copy(S,i*2+1,2));
    Drect.Left:=x;
    Drect.top:=y;
    Drect.Right :=x+w;//+ Canvas.TextWidth(' ');
    Drect.Bottom :=y+h;
    flg:=DT_center + DT_SINGLELINE + DT_VCENTER;
    DrawText(Canvas.Handle, pchar(copy(S,i*2+1,2)),  -1, DRect, flg );
    x:=x+w;

  end;

  //③おしえてもらったものをDT_LEFTにしたぶん
  x:=StartX;
  y:=y+h;
  for i := 0 to trunc(length(S)/2)-1 do
  begin

    w:=canvas.TextWidth(copy(S,i*2+1,2));
    h:=canvas.TextHeight(copy(S,i*2+1,2));
    Drect.Left:=x;
    Drect.top:=y;
    Drect.Right :=x+w+ Canvas.TextWidth(' ');
    Drect.Bottom :=y+h;
    flg:=DT_left + DT_SINGLELINE + DT_VCENTER;
    DrawText(Canvas.Handle, pchar(copy(S,i*2+1,2)),  -1, DRect, flg );
    x:=x+w;

  end;

  //④もともとのにDT_NOCLIPを追加したぶん
  x:=StartX;
  y:=y+h;
  for i := 0 to trunc(length(S)/2)-1 do
  begin

    w:=canvas.TextWidth(copy(S,i*2+1,2));
    h:=canvas.TextHeight(copy(S,i*2+1,2));
    Drect.Left:=x;
    Drect.top:=y;
    Drect.Right :=x+w;//+ Canvas.TextWidth(' ');
    Drect.Bottom :=y+h;
    flg:=DT_center + DT_SINGLELINE + DT_VCENTER + DT_NOCLIP ;
    DrawText(Canvas.Handle, pchar(copy(S,i*2+1,2)),  -1, DRect, flg );
    x:=x+w;

  end;

end;


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加