アンチエイリアスを効かせるにはどうしたらいいでしょうか

解決


ぴ〜  2011-11-23 18:54:10  No: 41248

Delphi6です。初心者と中級者の間ぐらいのレベルです。
フォームにボタンとチェックボックスとイメージを用意します。
uses に Clipbrd を追加します。

procedure TForm1.Button1Click(Sender: TObject);
var
  Metafile: TMetafile;
  MetafileCanvas: TMetafileCanvas;
  DispW, DispH, MMPerPixelW, MMPerPixelH: Integer;
  Format: Word;
  Data: THandle;
  Palette: HPALETTE;
  r: TRect;

begin
   DispW := GetDeviceCaps( Canvas.Handle, HORZSIZE );
   DispH := GetDeviceCaps( Canvas.Handle, VERTSIZE );
   MMPerPixelW := Round( DispW * 100 / Screen.Width );
   MMPerPixelH := Round( DispH * 100 / Screen.Height );
   Metafile := TMetafile.Create;
   try
     with Metafile do
     begin
        Enhanced := True;
        MMWidth := Image1.Width * MMPerPixelW;
        MMHeight := Image1.Height * MMPerPixelH;
        Width := Image1.Width;
        Height := Image1.Height;
     end;
     MetafileCanvas := TMetafileCanvas.Create( Metafile, Canvas.Handle );

      // 図形描画
     MetafileCanvas.Ellipse(0, 0, 40, 40);

      // 文字列描画
     r := Rect(50,15,Image1.Width,Image1.Height);
     if Checkbox1.Checked = true then
       DrawText(MetafileCanvas.Handle, '文字列', -1, r, DT_LEFT );

     MetafileCanvas.Free;
     Image1.Picture.Assign(Metafile);
     Metafile.SaveToClipboardFormat( Format, Data, Palette );
     Clipboard.SetAsHandle( Format, Data );
   finally
     Metafile.Free;
   end;
end;

ボタンをクリックするとクリップボードにコピーされます。
これをWORDに貼り付けると、チェックボックスの状態によってWORD
に貼り付けた図形のアンチエイリアスが、効いたり効かなかったりします。

チックボックスがOFFの時・・・図形にアンチエイリアスが働く
チックボックスがONの時・・・・図形にアンチエイリアスが働かない
                                文字列にアンチエイリアスが働く

つまり、図形だけの時はアンチエイリアスが働くのに、文字列を追加すると
図形のアンチエイリアスが解除されてしまいます。
この挙動の原因がつかめないで困っています。

メインの質問とは別件ですが、Imageコンポーネントの表示は常にアンチ
エイリアスが働かない状態ですが、これにアンチエイリアスを効かせる
ことはできるのでしょうか?

ご存知の方がいらっしゃいましたら、よろしくお願いいたします。


DEKO  2011-11-24 00:26:45  No: 41249

GDI+ のライブラリを使うしかないかもです。

[2010/12/28 及び 12/29 の雑談]
http://ht-deko.minim.ne.jp/ft1012.html#101228_01


ぴ〜  2011-11-24 03:56:14  No: 41250

素早いお返事ありがとうございます。
GDI+ですか。いきなり難しそうですね。まだまだ私には手の出せない領域です。

2010/12/29 の雑談より
> TImage では EMF+ (GDI+) の描画ができませんから、"GDI+ のコマンド" 部分は
> 正確に再生されません。

これはImageコンポーネントにアンチエイリアスが働かない原因ですね。
納得しました。

本題の方ですが、
> "Metafile を表示する" というのは "GDI コマンドを再生する" 事に他なりません。
とありますので、メタファイルにはアンチエイリアス処理のコマンドを含むことが
できるということですね。

つまり上記のプログラムでは、そもそもアンチエイリアス処理のコマンドが含まれて
いないので、WORDに貼り付けた時きれいに表示できないと。

うーん、文字列がないときにアンチエイリアスが働いている理由がよく分かりませんが、
なんとなくは納得できました。

ありがとうございました。


monaa  2011-11-24 07:53:23  No: 41251

ぱっと見ですが、MS Wordはメタファイルを独自で描画しているみたいですね。
MS Word上で一度でも編集すると全てにアンチエイリアスがかかるみたいですよ。
MS ペイントに描かせるとやはりアンチエイリアスはかかりません。
どの環境でもアンチエイリアスをかけるのはDEKOさんの方法しか無いようですが、
せめて自分のアプリ内だけでも…というならそのままでもいける方法はあります。
メタファイルを2倍の大きさでBmpに出力後、1/2するとアンチエイリアスが掛かった描画になります。
手持ちソースの切り抜きですがよかったらどうぞ。

type
  TByteARGB = record
    B:Byte;
    G:Byte;
    R:Byte;
    A:Byte;
  end;
  PByteARGB = ^TByteARGB;

procedure BmpHalf(SrcBmp,DestBmp:TBitmap);
var
  aW,aH,x,y,p,step:Integer;
  pS: array [0..1] of PByteARGB;
  pD:PByteARGB;
  R,G,B:Integer;
begin
  aW := SrcBmp.Width  div 2;
  aH := SrcBmp.Height div 2;
  step := SrcBmp.Width;
  DestBmp.SetSize(aW,aH);
  pS[0] := SrcBmp.ScanLine[SrcBmp.Height-1];
  for p := 1 to 1 do
  begin
    pS[p] := pS[p-1];
    inc(pS[p], SrcBmp.Width);
  end;
  pD := DestBmp.ScanLine[DestBmp.Height-1];
  for y := 0 to aH-1 do
  begin
    for x := 0 to aW-1 do
    begin
      R:=0; G:=0; B:=0;
      for p := 0 to 1 do
      begin
        R:=R+ps[p]^.R;
        G:=G+ps[p]^.G;
        B:=B+ps[p]^.B;
        inc(pS[p]);
        R:=R+ps[p]^.R;
        G:=G+ps[p]^.G;
        B:=B+ps[p]^.B;
        inc(pS[p]);
      end;
      R := R shr 2;
      G := G shr 2;
      B := B shr 2;
      pD^.R := R;
      pD^.G := G;
      pD^.B := B;
      inc(pD);
    end;
    for p := 0 to 1 do
      inc(pS[p], step);
  end;
end;

procedure EMFToBMPwithAntialiasing(aMetafile: TMetafile; var aBmp:TBitmap);
var
  aBmp2:TBitmap;
begin
  aBmp.PixelFormat:=pf32bit;
  aBmp.SetSize(aMetafile.Width,aMetafile.Height);
  aBmp2:=TBitmap.Create;
  aBmp2.PixelFormat:=pf32bit;
  aBmp2.SetSize(aMetafile.Width*2,aMetafile.Height*2);
  aBmp2.Canvas.StretchDraw(Rect(0,0,aBmp2.Width,aBmp2.Height),aMetafile);
  BmpHalf(aBmp2,aBmp);
  aBmp2.Free;
end;

//-----------------------------------------------------------------------
aBmp:=TBitmap.Create;
aBmp.SetSize(Metafile.Width,Metafile.Height);
EMFToBMPwithAntialiasing(Metafile,aBmp);
Image1.Picture.Assign(aBmp);
aBmp.Free;
//Image1.Picture.Assign(Metafile);


ライブラリ  2011-11-24 17:33:51  No: 41252

解決策とか関係ありませんが。。。

これとか?
TNkDIB
http://www.asahi-net.or.jp/~HA3T-NKMR/deldown.htm

これとか?
Graphics32 Project Homepage - Main.HomePage
http://graphics32.org/wiki/とか


ぴ〜  2011-11-25 07:29:08  No: 41253

monaaさん

> メタファイルを2倍の大きさでBmpに出力後、1/2するとアンチエイリアス
> が掛かった描画になります。

プログラムを作れるだけではなく、こういう発想ができるようにもならない
とダメですね。勉強になりました。

> 手持ちソースの切り抜きですがよかったらどうぞ。

なぜかSetSizeで未定義の識別子としてコンパイルが止まってしまいます。
原因を探し中です。

ライブラリさん
両方ともちょっと私には難しそうです。せっかく教えていただいたのに、
活用できないのが残念です。


monaa  2011-11-25 08:10:55  No: 41254

D6でしたね、スミマセン。
TBitmap.Seisize(Width,Height)なので
TBitmap.Width := Width;
TBitmap.Height:= Height;
に書き換えてください。


ぴ〜  2011-11-26 06:33:22  No: 41255

できましたー。
これで自アプリだけでも綺麗に表示できます。
見た目だけの問題で実害はないのですが、やはりちょっとでも綺麗に見えると
気持ちがいいもんです。
ありがとうございました。


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

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






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