リージョンでクリッピング領域を指定して画像をコピーしたり変形したウィンドウを作成 ~Delphiソースコード集
リージョンを使用すると画像から指定したポリゴン領域や楕円領域(クリッピング領域)だけを別の画像にコピーすることが出来ます。
また、ウィンドウの形(ウィンドウ領域)をリージョンの形にすることもできます。
リージョンを作成するAPI関数
リージョンを作成するAPI関数には以下のようなものがあります。
- CreateEllipticRgn(x1,y1, x2,y2:Integer):HRGN;
-
左上座標(x1,y1) 右下座標(x2,y2)の長方形領域に内接する楕円のリージョンを作成します
var Rgn:HRGN; begin Rgn:=CreateEllipticRgn(10,10,90,90); //リージョンの破棄 DeleteObject(Rgn); end;
- CreatePolygonRgn(Points:Array of TPoint, Count:Integer, FillMode:Integer):HRGN;
-
Pointsで指定した頂点の多角形リージョンを作成します。
CountはPointsの数(頂点の数)を指定します。
FillModeは以下の何れかの値を指定します。値 説明 ALTERNATE 偶数-奇数ルールに基づいてポリゴンを塗りつぶす
ポリゴンの任意の点から無限遠に線を引き、その線がポリゴンの辺と奇数回交差する場合、その点は内部と見なすWINDING 非ゼロルールに基づいてポリゴンを塗りつぶす
ポリゴンの任意の点から無限遠に線を引き、その線がポリゴンの辺と交差した回数がゼロ以外の場合、その点は内部と見なすvar Rgn:HRGN; Points: array[0..4] of TPoint; begin Points[0] := Point(90, 10); Points[1] := Point(10, 100); Points[2] := Point(120, 110); Points[3] := Point(10, 10); Points[4] := Point(60, 140); Rgn:=CreatePolygonRgn(Points,Length(Points),WINDING); //リージョンの破棄 DeleteObject(Rgn); end;
- CreateRectRgn(x1,y1, x2,y2:Integer):HRGN;
-
左上座標(x1,y1) 右下座標(x2,y2)の長方形のリージョンを作成します
var Rgn:HRGN; begin Rgn:=CreateRectRgn(10,10,90,90); //リージョンの破棄 DeleteObject(Rgn); end;
- CreateRoundRectRgn(x1,y1, x2,y2, w,h:Integer):HRGN;
-
左上座標(x1,y1) 右下座標(x2,y2)の角が丸い(角の楕円の幅w,角の楕円の高さh)四角形のリージョンを作成します
var Rgn:HRGN; begin Rgn:=CreateRoundRectRgn(10,10, 90,90, 10,6); //リージョンの破棄 DeleteObject(Rgn); end;
リージョンを結合する
作成した2つのリージョンを結合して、新たなリージョンを作成することが出来ます。 リージョンを結合するにはCombineRgn関数を使います。
- CombineRgn(RgnDest, RgnSrc1,RgnSrc2:HRGN, iMode:Integer);
-
リージョン「RgnSrc1」とリージョン「RgnSrc2」を「iMode」モードで結合したリージョン「RgnDest」を生成します
iModeは以下の何れかの値を指定します。値 説明 RGN_AND 2つの結合領域の論理積(AND)を作成します。 RGN_COPY RgnSrc1をコピーします(RgnSrc2は無視) RGN_DIFF RGNSrc2の一部ではないRgnSrc1の部分を結合します RGN_OR 2つの結合領域の論理和(OR)を作成します。 RGN_XOR 2つの結合領域の排他論理和(XOR)を作成します。
var Rgn1,Rgn2: HRGN; begin Rgn1:=CreateRoundRectRgn(10,10, 90,90, 10,6); Rgn2:=CreateEllipticRgn(50,50,140,140); //Rgn1とRgn2をOR結合してRgn1に入れる CombineRgn(Rgn1,Rgn1,Rgn2,RGN_OR); //リージョンの破棄 DeleteObject(Rgn1); DeleteObject(Rgn2); end;
テスト用のアプリケーションの作成
テスト用のプロジェクトの作成と画面設計
[ファイル]⇒[新規作成]⇒[VCL フォーム アプリケーション -Delphi]をクリックし、新規プロジェクトを作成します。
フォーム(Form1)に右下のペイン[ツールパレット]から「TImage」を2つ、「TButton」を2つドラッグ&ドロップします。
楕円のリージョンを作成して楕円領域をクリッピングして画像をコピー
以下ソースコードをコピーして貼り付けます。
「Button1」のイベントプロパティ「Onclick」に「Button1Click」を設定し、
「Form1」のイベントプロパティ「OnCreate」に「FormCreate」を設定します。
unit Unit1; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls; type TForm1 = class(TForm) Image1: TImage; Image2: TImage; Button1: TButton; Button2: TButton; procedure Button1Click(Sender: TObject); procedure FormCreate(Sender: TObject); private { Private 宣言 } public { Public 宣言 } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); var Bmp1,Bmp2:TBitmap; Rgn1: HRGN; begin Bmp1:=Image1.Picture.Bitmap; Bmp2:=Image2.Picture.Bitmap; //楕円のリージョンを作成 (x1,y1, x2,y2) Rgn1:=CreateEllipticRgn(30, 50, 170, 150); //クリッピング領域としてリージョンを設定する SelectClipRgn(Bmp2.Canvas.Handle, Rgn1); //Image1.Picture.BitmapをImage2.Picture.Bitmapに描画 Bmp2.Canvas.Draw(0,0,Bmp1); //リージョンの破棄 DeleteObject(Rgn1); //クリッピング領域を解除する SelectClipRgn(Bmp2.Canvas.Handle, 0); end; procedure TForm1.FormCreate(Sender: TObject); var Bmp1,Bmp2:TBitmap; begin Image1.Width:=200; Image1.Height:=200; Bmp1:=Image1.Picture.Bitmap; Bmp1.SetSize(Image1.Width,Image1.Height); Image2.Width := Image1.Width; Image2.Height := Image1.Height; Bmp2:=Image2.Picture.Bitmap; Bmp2.Width:=Image1.Width; Bmp2.Height:=Image1.Height; //Image1.Picture.Bitmapに適当に描画 Bmp1.Canvas.Brush.Color:=clWhite; Bmp1.Canvas.FillRect(bmp1.Canvas.ClipRect); Bmp1.Canvas.Brush.Color:=clGreen; Bmp1.Canvas.FillRect(Rect(50,50,150,150)); Bmp1.Canvas.Pen.Width:=4; Bmp1.Canvas.Pen.Color:=clBlue; Bmp1.Canvas.MoveTo(0,0); Bmp1.Canvas.LineTo(Bmp1.Width,Bmp2.Height); Bmp1.Canvas.Pen.Color:=clYellow; Bmp1.Canvas.MoveTo(Bmp1.Width,0); Bmp1.Canvas.LineTo(0,Bmp2.Height); //Image2.Picture.Bitmapは赤色を塗りつぶす Bmp2.Canvas.Brush.Color:=clRed; Bmp2.Canvas.FillRect(bmp2.Canvas.ClipRect); end;
[実行]⇒[実行]をクリックして実行します。
「Button1」をクリックするとImage1の楕円形(30, 50, 170, 150)領域だけがImage2にコピーされていることが確認できます。
ウィンドウの形をリージョンの形に設定する
ウィンドウの形(ウィンドウ領域)をリージョンの形に設定するには SetWindowRgn API関数を使います。
- SetWindowRgn(hWnd:HWND; hRgn:HRGN; bRedraw:LongBool):HRGN;
-
ウィンドウハンドルがhWndのウィンドウの形(ウィンドウ領域)をhRgnに設定します。
bRedraw が True の場合はウィンドウを再描画します。
var Rgn:HRGN; begin Rgn:=CreateRoundRectRgn(10,10, 900,900, 20,30); //ウィンドウの形をリージョンの形にする SetWindowRgn(Self.Handle, Rgn1, True); //リージョンの破棄 DeleteObject(Rgn); end;
Button2をダブルクリックして以下ソースコードを記述します。
procedure TForm1.Button2Click(Sender: TObject); var Points: array[0..3] of TPoint; Rgn1,Rgn2: HRGN; begin //ポリゴン配列 Points[0] := Point(0, 0); Points[1] := Point(Self.Width, 0); Points[2] := Point(Self.Width, Self.Height div 3 * 2); Points[3] := Point(0, Self.Height div 2); //ポリゴンのリージョンの作成 Rgn1:=CreatePolygonRgn(Points,Length(Points),WINDING); //長方形のリージョンの作成 //Rgn2:=CreateRectRgn(100, 100, 180, 180); //楕円のリージョンの場合 Rgn2:=CreateEllipticRgn(0, Self.Height div 2, Self.Width div 2, Self.Height); //Rgn1とRgn2をOR結合してRgn1に入れる CombineRgn(Rgn1,Rgn1,Rgn2,RGN_OR); //ウィンドウの形をリージョンの形にする SetWindowRgn(Self.Handle, Rgn1, True); //リージョンの破棄 DeleteObject(Rgn1); DeleteObject(Rgn2); end;
[実行]⇒[実行]をクリックして実行します。
「Button2」をクリックするウィンドウの形が変形します。
ウィンドウ領域の解除は以下です。
SetWindowRgn(Self.Handle, 0, True);
アプリケーション起動時のウィンドウをリージョンでアニメーション表示する
TForm1のイベントプロパティ「OnActivate」に以下のソースコードを記述するとウィンドウがアニメーション表示されます。
procedure TForm1.FormActivate(Sender: TObject); var RectRgn: HRGN; i:Integer; begin for i := 0 to 50 do begin //指定した範囲で矩形リージョンを作成 RectRgn := CreateRectRgn( Width div 2 - Width * i div 100, Height div 2 - Height * i div 100, Width div 2 + Width * i div 100, Height div 2 + Height * i div 100 ); //フォームのウィンドウリージョンを設定 SetWindowRgn(Handle, RectRgn, True); //作成したリージョンオブジェクトを解放 DeleteObject(RectRgn); //10ミリ秒待機してアニメーションのスムーズさを調整 Sleep(10); //アプリケーションのメッセージを処理しUIを更新 Application.ProcessMessages; end; //リージョンをリセットして、フォームの形状を元に戻す SetWindowRgn(Handle, 0, True); end;