Delphi Programming / Object Pascal
サイトのトップページへ リンクのページへ ロゴマーク
[掲載 2012年10月25日] [更新 2014年07月09日] GDI+ 関係サンプル
GDI+ 関係サンプル
概要
動作確認等 サンプルよって異なる
全てのサンプルがダウンロード可能 (実行ファイル同梱)
gdiplus.zip [1,144 KB] 2002年02月15日版 (Delphi XE 以前用)







GDI+ 関係サンプル


GDI+ は Windows XP で実装されたグラフィクスサブシステムですです。
GDI+を使うと、.NET Frameworkと同等のグラフィック機能を Windows API ベースのプログラムから使用することができます。GDI+ を使用しない場合は GDI による描画ということになります。

GDI+ の関数類は、Gdiplus.dll が提供しています。Delphi XE2 では GDI+ の API を利用するためライブラリが標準実装されました。
Microsoft Office 関連でも、少なくも Office XP, 2003 では GDI+ を使用しています。GDI+ のサンプルは、ネット上に多くありますが、若干のテストプログラムを作成してみました。
Delphi で使用可能な GDI+ Library には、この他、.NET Framework 互換の

   Delphi GDI+ Library for use with Delphi 2009 (version 1.2)

があります。MSDN の記事のほとんどが .NET Framework 対応のものですから、今後はこちらの方の利用を考えてもいいのかも知れません。Delphi XE2 に実装されているのが .NET 互換の方ではないので、今回は使用しませんでした。
上のリンクの Delphi 2009 以降で使用可能な .NET 互換の GDI+ には、Blur (ブラー) というガウスばかしのクラスがありますが、本サンプルで使用している GDI+ には実装されていません。Delphi XE2 の GDI+ ライブラリには、拡張された Blur クラスが実装されています。

GDI+ ライブラリの機能を使用するには、uses に GDIPAPI, GDIPOBJ 等を追加します。






Delphi XE 以前で GDI+ ライブラリを使用する ( gdiplus.zip )


Delphi XE 以前で GDI+を使用するには、本ページから GDI+ ライブラリ (2002年02月15日版) を別途ダウンロードしてください。
これは progdigy.com というサイトで提供されていたものですが、2013年07月11日現在入手できません。MPL1.1 のライセンスに基づき、当サイトで再配布しています。。
次の手順で導入します。

  • gdiplus.zip をダウンロード
  • ダウンロードした gdiplus.zip を適当なフォルダに解凍
  • 解凍したフォルダ内の [pas] フォルダにパスを通す
  • uses に GDIPAPI と GDIPOBJ を追加する
Delphi 7 以前であれば、このまま使用できます。それ以降のバージョンでは、以下のエラーが発生して、プロジェクトのコンパイルに失敗します。

[DCC エラー] DirectDraw.pas(358): E2154 'IDirectDrawSurface' 型は終了処理が必要です - 構造体の可変部に置くことは許されません

ダウンロードした GDI+ のバージョン定義ファイル Jedi.inc は Delphi 7 までの対応です。そのために必要なコードが実行されないのが原因で発生します (情報源 : Dephi-fan の GDI+ を使う)。
そこで、筆者は次のリストのように修正しました。つまり、Delphi のバージョンを全て Delphi 7 にごまかす設定です。この修正をしても、[ヒント] や [警告] は表示されますが、使用可能です。


リスト1
[pas] フォルダ内の Jedi.inc を修正。Delphi 7 以降全てで使用可能に
VERXXX to COMPILERX, DELPHIX and BCBX mappings の部分を以下に変更
//------------------------------------------------------------------------------
// VERXXX to COMPILERX, DELPHIX and BCBX mappings
//------------------------------------------------------------------------------

{$IF CompilerVersion > 14.99}
  {$DEFINE COMPILER7}
  {$IFDEF BCB}
    {$DEFINE BCB7}
    {$DEFINE BCB}
  {$ELSE}
    {$DEFINE DELPHI7}
    {$DEFINE DELPHI}
  {$ENDIF}
{$IFEND}


どうしても [ヒント] や [警告] が気になるのであれば、


は、大文字あるいは小文字に修正します。これは、主にメソッド名の先頭文字です。また、


は、下のコードのように、reintroduce 指令を追加します。


リスト2
reintroduce 指令を追加
    function Equals(region: TGPRegion; g: TGPGraphics): BOOL; reintroduce;




GDI+ における図形や画像等の描画先


GDI+ のグラフィックスのオブジェクト、TGPGraphics のインスタンス (実体) は、以下のように、描画対象の TCanvas のハンドルを引数に指定して作成します。

例えば、TBitmap の Canvas に描画する場合は、TBitmap.Canvas.Handle とします。
TImage の Canvas に描画する場合は、TImage.Canvas.Handle とします。
TBitmap や TImage はクラス名です。実際にはそれらのインスタンスの名前とします、Image1 であれば Image1.Canvas.Handle となります。


  //描画先を指定してTGPGraphicsオブジェクトを生成する
  LGPGraphic := TGPGraphics.Create(Canvas.Handle);


そして、この TGPGraphics の描画用のプロパティである色等を設定し、描画用のメソッドで図形や画像を描画します。すると、指定した TCanvas に図形なり画像が描画されることになります。描画先が TImage 等であれば描画結果は目に見えます。
TBitmap の場合は、描画コードを実行しても実際には目には見えません。処理結果としての、そのビットマップを何かに表示するとか、保存するとことになります。

ペンやブラシ等の設定は、TCanvas のようなプロパティではなく、それそれのオブジェクトを生成して設定します。ペンや線のプロパティを設定するためのオブジェクト類は、この TGPGraphics のオブジェクトがなくても、独立して設定できます。




  //描画座標値をポイントで指定
  P1 := MakePoint(20,  150);
  P2 := MakePoint(200, 150);
  //TGPPenのペンの設定で線を引く(描画する)
  LGPGraphic.DrawLine(LGPPen, P1, P2);




サンプルで使用している TMyPanel


サンプルの多くは、フォームに配置したパネル、あるいは、TPanel を継承した TMyPanel というコントロールの Paint メソッドで、その Canvas に画像や図形を描画しています。

アプリケーションを開発する際、多くの場合、複数のフォームあるいはユニットを使用します。そしてそれらのフォームあるいはユニットと変数のやりとりが必要となります。
この時、グローバルな変数を介するよりも、プロパティ、あるいはメソッド類で行うのが一般的です。このことを意識して TPanel の派生クラスを作成して、他のフォーム、ユニット内のクラスとのやりとりの代わりとしています。

描画コード自体は Paint メソッド以外にはありません。フォームの OnPaint イベント、あるいは、TPaintBox の OnPaint イベント等に、この TMyPanel メソッドのコードをコピーして貼り付け、コード内のプロパティ等の変数に直接値を代入すれば、ネット上の多くのサンプル、デモプログラムと同じように扱えます。

TImage に描画するサンプルもありますが、TImage は内部で「オフスクリーンビットマップ」というビットマップを生成して描画内容を表示します。そのため、描画内容を変更する際、一度描画内容をクリアしてから再度描画コードを実行するという作業が必要な場合があります。

TImage は、他のウィンドウが上に重なっても、描画の更新を内部で自動で実行してくれます。また重ね描画も自動で処理してくれます。GDI+ で描画する場合は、追加の描画もコードを追加しなければなりません。そのため、TImage のような追加描画の機能を実装するには、オフスクリーンビットマップのような仕組みが必要となることがあります。



[備考]
ほとんどのサンプルは、継承元を TPanel から TGraphicControl の TPaintBox に変更してもそのまま動作しますが、座標値の変換が必要な場合があります。





GDI+ を使用した描画コードの印刷


GDI+ の描画コードをプリンタに出力する時は、印刷のコーディングにもよりますが、次のように、描画コードを実行する前にマッピングが必要な場合があります。GDI+ の関数の中には、UnitPixelを引数で指定するものがあります。その場合は必要ありません。
この現象は、.NET 互換の GDI+ では必要ありません。なくても正しく印刷できます。


リスト3
GDI+ を使用した描画コードを印刷する際は、描画コードを実行する前にマッピングが必要
procedure TplResizeZLine.DrawRoutine(ACanvas: TCanvas; OffSetX: Integer=0;
  OffSetY: Integer=0);
var
  LGraphic : TGPGraphics;
begin

  //----------- 略 -------------------------

  LGraphic := TGPGraphics.Create(ACanvas.Handle);
  SetMapMode (ACanvas.Handle, MM_TEXT);
  LGraphic.SetPageUnit(UnitPixel);

  //----------- 描画コード ------------------

end;




サンプルプログラムのダウンロード方法とブロックの解除


各ページの上の方、最初の方に、下図のような画像があります。これをクリックしてください。サンプル単位ではなく、そのページのサンプルの一括ダウンロードとなっています。
各サンプルの個別ダウンロードの要望がありましたが、対応の予定はありません。
ダウンロードしたら [ブロックの解除] をしてください。




記事内のコードをコピーして利用する場合は、各サンプルコードの左上のコピーボタンをクリックするとクリップボードにコピーできます。