トップへ(mam-mam.net/)

リージョンでクリッピング領域を指定して画像をコピーしたり変形したウィンドウを作成 ~Delphiソースコード集

検索:

リージョンでクリッピング領域を指定して画像をコピーしたり変形したウィンドウを作成 ~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;