|
Delphi Programming / Object Pascal
[掲載 2012年12月09日] [更新 2012年12月15日] GDI+ 関係サンプル |
GDI+ 関係サンプル
G080_RotateTransform による画像とオブジェクトの回転 |
動作確認等 |
Windows 7 U64(SP1) + Delphi XE(UP1) Pro |
|
G080_GDIPlus_RotateTransform.zip [5,101 KB] 2012年12月15日版 (EXE 同梱) |
GDI+ には,画像などのオブジェクトの回転や移動の操作として,以下のような関数類があります.
- TGPImage.RotateFlip (画像の回転と反転.TGPImage, TGPBitmap 専用)
- TGPGraphics.RotateTransform (軸の回転による描画)
- TGPMatrix (ワールド変換行列を使用するアフィイン変換)
- TGPGraphicsPath.Warp (歪曲変形.TGPGraphicsPath 専用)
このページのサンプルは,RotateFlip と RotateTransform 関数を使用したものです.前のページで説明したページ座標系を使用しています.
RotateTransform 関数による回転の手順は,次のようになります.
- (1) TranslateTransform で座標の原点 (0, 0) を設定する.ここが回転の中心となる
- (2) RotateTransform 関数で回転角度を設定する
- (3) 画像や図形の描画コードを書く
通常の描画コードに,TranslateTransform と RotateTransform 関数を実行する 2 行のコードを追加するだけです.ただし,Translateform 関数で原点を移動している場合は,描画位置に注意します.
TranslaateTrnsform 関数で座標の原点を設定しない場合は,原点 (0, 0) は描画先の Canvas の左上のままです.したがって,ここが回転の中心にとなります. |
01_RotateFlip 関数による画像の回転と反転 |
RotateFlip 関数を使用したサンプルです.RotateFlip 関数による回転と反転は,図形オブジェクトの回転とは違い,画像の中身そのものが回転あるいは反転します.
RotateFlip 関数は,次表の TRotateFlipType 列挙型の値を引数にして実行します.回転角度は時計回りが正の値となります. |
表1
TRotateFlipType の列挙型の値 |
RotateNoneFlipNone |
回転も反転もなし |
Rotate90FlipNone |
90 度回転.反転なし |
Rotate180FlipNone |
180 度回転.反転なし |
Rotate270FlipNone |
270 度回転.反転なし |
RotateNoneFlipX |
回転はなし.水平方向に反転 |
Rotate90FlipX |
90 度回転と水平方向の反転 |
Rotate180FlipX |
180度回転と水平方向の反転 |
Rotate270FlipX |
270 度回転と水平方向の反転 |
RotateNoneFlipY = Rotate180FlipX |
回転はなし垂直方向の反転 |
Rotate90FlipY = Rotate270FlipX |
90 度回転と垂直方向の反転 |
Rotate180FlipY = RotateNoneFlipX |
180 度回転と垂直方向の反転 |
Rotate270FlipY = Rotate90FlipX |
270 度回転と垂直方向の反転 |
RotateNoneFlipXY = Rotate180FlipNone |
回転なし水平垂直方向の反転 |
Rotate90FlipXY = Rotate270FlipNone |
90 度回転と水平と垂直方向の反転 |
Rotate180FlipXY = RotateNoneFlipNone |
180 度回転と水平と垂直方向の反転 |
Rotate270FlipXY = Rotate90FlipNone |
270 度回転と水平と垂直方向の反転 |
|
図1
設計時画面 |
|
図2
実行開始画面 |
|
図3
180 度回転 |
|
図4
90 度回転して横方向反転 |
リスト1
RotateFlip 関数による画像の回転と反転のテスト |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ExtCtrls, StdCtrls, GDIPAPI, GDIPOBJ;
type
TMyPanel = class(TPanel)
private
FRotateFlipNo : Integer;
procedure SetRotateFlipNo(const Value: Integer);
protected
procedure Paint; override;
public
constructor Create(AOwner: TComponent); override;
property RotateFlipNo : Integer read FRotateFlipNo write SetRotateFlipNo;
end;
TForm1 = class(TForm)
RadioGroup1: TRadioGroup;
procedure FormCreate(Sender: TObject);
procedure RadioGroup1Click(Sender: TObject);
private
{ Private 宣言 }
MyPanel : TMyPanel;
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
uses
TypInfo;
{$R *.DFM}
//=============================================================================
// フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
var
LTypeInfo : PTypeInfo;
LInfoData : PTypeData;
i : Integer;
begin
Caption := 'GDI+ RotateFlip';
//描画するコントロールを生成
MyPanel := TMyPanel.Create(Self);
with MyPanel do begin
Parent := Self;
SetBounds(160, 5, Self.ClientWidth - 168, Self.ClientHeight - 10);
DoubleBuffered := True;
ControlStyle := MyPanel.ControlStyle + [csOpaque];
BevelOuter := bvNone;
Visible := True;
Color := clWhite;
ParentBackground := False;
end;
//列挙型の最小値と最大値を取得
LTypeInfo := TypeInfo(TRotateFlipType);
LInfoData := GetTypeData(LTypeInfo);
//列挙型の値を文字列として取得.RadioGroup1に表示
for i := LInfoData^.MinValue to LInfoData^.MaxValue do begin
RadioGroup1.Items.Add(GetEnumName(TypeInfo(TRotateFlipType), i));
end;
RadioGroup1.ItemIndex := 0;
end;
//=============================================================================
// RadioGroup1のOnClickイベント処理
// RotateFilpの値を変更したら,TMyPanelを再描画
//=============================================================================
procedure TForm1.RadioGroup1Click(Sender: TObject);
begin
if not Assigned(MyPanel) then exit;
MyPanel.RotateFlipNo := RadioGroup1.ItemIndex;
end;
{ TMyPanel }
//-----------------------------------------------------------------------------
// コンストラクタ
// 各種プロパティと内部で使用する変数の初期化
//-----------------------------------------------------------------------------
constructor TMyPanel.Create(AOwner: TComponent);
begin
inherited;
FRotateFlipNo := 0;
end;
//-----------------------------------------------------------------------------
// RotateFlipNoプロパティの設定用メソッド
// 回転と反転の設定が変更になったら再描画
//-----------------------------------------------------------------------------
procedure TMyPanel.SetRotateFlipNo(const Value: Integer);
begin
if not Assigned(Parent) then exit;
if FRotateFlipNo <> Value then begin
FRotateFlipNo := Value;
Invalidate;
end;
end;
//-----------------------------------------------------------------------------
// TMyPanelクラスのPaintメソッド
// 実際の描画コード
//-----------------------------------------------------------------------------
procedure TMyPanel.Paint;
var
LObjWidth : Integer;
LObjHeight : Integer;
LImageFilePath : String;
LGPImage : TGPImage;
LGPGraphic : TGPGraphics;
begin
inherited;
//画像の表示サイズ
LObjWidth := 150;
LObjHeight := 100;
//画像ファイルを指定.TGPImaageインスタンスを生成して読み込む
LImageFilePath := ExtractFilePath(ParamStr(0)) + '503.bmp';
LGPImage := TGPImage.Create(LImageFilePath);
//このTMyPanelのCanvasを描画先にしてTGPGraphicsのインスタンスを生成
LGPGraphic := TGPGraphics.Create(Canvas.Handle);
//回転と反転を設定
LGPImage.RotateFlip(TRotateFlipType(FRotateFlipNo));
//描画
LGPGraphic.DrawImage(LGPImage, 20, 20, LObjWidth, LObjHeight);
LGPImage.Free;
LGPGraphic.Free;
end;
end.
02_RotateTransform 関数による画像オブジェクトの回転 |
これ以降は全て,RotateTransform 関数を使用したサンプルです.
サンプルコードは,前の項の RotateFlip 関数による実行結果との違いが確認できるようにしてみました.回転角度は,トラックバーで設定します.
下の図は,左から,元の画像,RotateFlip 関数による 90 度の回転,RotateTransform 関数で 90 度回転した結果です.共に時計回り (右周り) の回転結果です. |
|
図5
設計時画面 |
|
図6
実行開始画面 |
|
図7
回転した状態 |
|
図8
回転の中心を変更
|
前のページで,座標軸のスケーリングを説明しましたが,次のように,すると,座標軸のスケーリングもできます.このコードは,X 軸方向はそのままで,Y 軸方向を 1.5 倍にしています.
これを実行すると,下図のように図形が変形し,領域の形が平行四辺形になります. |
GDPGraphic.TranslateTransform(XLocation, YLocation);
GDPGraphic.ScaleTransform(1.0, 1.5);
|
図9
スケーリングの例 |
リスト2
RotateTransform による画像オブジェクトの回転 |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ExtCtrls, StdCtrls, GDIPAPI, GDIPOBJ, ComCtrls;
type
TMyPanel = class(TPanel)
private
FRotateFlipNo : Integer;
FRotateAngle : Integer;
FIsDrawCenter : Boolean;
procedure SetRotateFlipNo(const Value: Integer);
procedure SetRotateAngle(const Value: Integer);
procedure SetIsDrawCenter(const Value: Boolean);
protected
procedure Paint; override;
public
constructor Create(AOwner: TComponent); override;
property RotateFlipNo : Integer read FRotateFlipNo write SetRotateFlipNo;
property RotateAngle : Integer read FRotateAngle write SetRotateAngle;
property IsDrawCenter : Boolean read FIsDrawCenter write SetIsDrawCenter;
end;
TForm1 = class(TForm)
RadioGroup1: TRadioGroup;
TrackBar1: TTrackBar;
CheckBox1: TCheckBox;
procedure FormCreate(Sender: TObject);
procedure RadioGroup1Click(Sender: TObject);
procedure TrackBar1Change(Sender: TObject);
procedure CheckBox1Click(Sender: TObject);
private
{ Private 宣言 }
MyPanel : TMyPanel;
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
uses
TypInfo;
{$R *.DFM}
//=============================================================================
// フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
var
LTypeInfo : PTypeInfo;
LInfoData : PTypeData;
i : Integer;
begin
Caption := 'GDI+ 画像オブジェクトの回転';
//描画するコントロールを生成
MyPanel := TMyPanel.Create(Self);
with MyPanel do begin
Parent := Self;
SetBounds(5, 200, Self.ClientWidth - 10, Self.ClientHeight - 205);
DoubleBuffered := True;
ControlStyle := MyPanel.ControlStyle + [csOpaque];
BevelOuter := bvNone;
Visible := True;
Color := clWhite;
ParentBackground := False;
Anchors := [akLeft, akTop, akRight, akBottom];
end;
//列挙型の最小値と最大値を取得
LTypeInfo := TypeInfo(TRotateFlipType);
LInfoData := GetTypeData(LTypeInfo);
//列挙型の値を文字列として取得してRadioGroup1に表示
for i := LInfoData^.MinValue to LInfoData^.MaxValue do begin
RadioGroup1.Items.Add(GetEnumName(TypeInfo(TRotateFlipType), i));
end;
RadioGroup1.ItemIndex := 0;
//回転角度変更用のTrackBar1の設定
//回転角度は-360~360度とする
with TrackBar1 do begin
ShowSelRange := False;
TickStyle := tsNone;
Height := 26;
Min := -360;
Max := 360;
Position := 0;
end;
end;
//=============================================================================
// RadioGroup1のOnClickイベント処理
// 回転と反転のタイプの設定
//=============================================================================
procedure TForm1.RadioGroup1Click(Sender: TObject);
begin
if not Assigned(MyPanel) then exit;
MyPanel.RotateFlipNo := RadioGroup1.ItemIndex;
end;
//=============================================================================
// TrackBar1のOnClickイベント処理
// 画像オブジェクトの回転角度の設定の変更
//=============================================================================
procedure TForm1.TrackBar1Change(Sender: TObject);
begin
if not Assigned(MyPanel) then exit;
MyPanel.RotateAngle := TrackBar1.Position;
end;
//=============================================================================
// CheckBox1のOnClickイベント
// 回転の中心座標の指定
//=============================================================================
procedure TForm1.CheckBox1Click(Sender: TObject);
begin
if not Assigned(MyPanel) then exit;
MyPanel.IsDrawCenter := CheckBox1.Checked;
end;
{ TMyPanel }
//-----------------------------------------------------------------------------
// コンストラクタ
// 各種プロパティを初期値を設定
//-----------------------------------------------------------------------------
constructor TMyPanel.Create(AOwner: TComponent);
begin
inherited;
FRotateFlipNo := 0;
FRotateAngle := 0;
FIsDrawCenter := False;
end;
//-----------------------------------------------------------------------------
// RotateAngleプロパティ設定用メソッド
// 画像オブジェクトの回転角度の設定
//-----------------------------------------------------------------------------
procedure TMyPanel.SetRotateAngle(const Value: Integer);
begin
if not Assigned(Parent) then exit;
if FRotateAngle <> Value then begin
FRotateAngle := Value;
Invalidate;
end;
end;
//-----------------------------------------------------------------------------
// IsDrawCenterプロパティ設定用メソッド
// IsDrawCenterプロパティは,回転の中心座標の指定
//-----------------------------------------------------------------------------
procedure TMyPanel.SetIsDrawCenter(const Value: Boolean);
begin
if not Assigned(Parent) then exit;
if FIsDrawCenter <> Value then begin
FIsDrawCenter := Value;
Invalidate;
end;
end;
//-----------------------------------------------------------------------------
// RotateFlipNoプロパティ設定用メソッド
// 画像そのものの回転と反転表示の設定
//-----------------------------------------------------------------------------
procedure TMyPanel.SetRotateFlipNo(const Value: Integer);
begin
if not Assigned(Parent) then exit;
if FRotateFlipNo <> Value then begin
FRotateFlipNo := Value;
Invalidate;
end;
end;
//-----------------------------------------------------------------------------
// TMyPanelクラスのPaintメソッド
// 実際の描画コード
//-----------------------------------------------------------------------------
procedure TMyPanel.Paint;
var
LObjWidth : Integer;
LObjHeight : Integer;
LXLocation : Integer;
LYLocation : Integer;
LImageFilePath : String;
LGPImage : TGPImage;
LGPGraphic : TGPGraphics;
LGPPen : TGPPen;
begin
inherited;
//画像の表示サイズ
LObjWidth := 130;
LObjHeight := 100;
//ページ座標系の原点座標の設定
LXLocation := Width div 2;
LYLocation := Height div 2;
//画像ファイルを指定.TGPImaageインスタンスを生成して読み込む
LImageFilePath := ExtractFilePath(ParamStr(0)) + '503.bmp';
LGPImage := TGPImage.Create(LImageFilePath);
//このTMyPanelのCanvasを描画先にしてTGPGraphicsのインスタンスを生成
LGPGraphic := TGPGraphics.Create(Canvas.Handle);
//座標の原点を(LXLocation,LYLocation)のページ座標空間にする
//以後,ResetTransformを実行するまでは,この点が(0, 0)となる
LGPGraphic.TranslateTransform(LXLocation, LYLocation);
//この行を実行するとX軸とY軸の倍率を変えることができる
//LGPGraphic.ScaleTransform(1.0, 1.5);
//画像のオブジェクトを回転する
LGPGraphic.RotateTransform(FRotateAngle);
//画像そのものの回転と反転もテストしてみる
LGPImage.RotateFlip(TRotateFlipType(FRotateFlipNo));
//---------------------------------------------------------------------------
// 画像の描画
// TranslateTransformで設定した位置が描画原点(0, 0)となっている
// その原点から相対的な描画開始位置(左上の座標)を設定する
// つまり,ページ座標空間を基準とした描画コードとなる
// FIsDrawCenterがTrueの時は,描画始点を表示サイズの半分だけ左と上にずらす
//---------------------------------------------------------------------------
if FIsDrawCenter then begin
LGPGraphic.DrawImage(
LGPImage, -LObjWidth div 2, -LObjHeight div 2, LObjWidth, LObjHeight);
end else begin
LGPGraphic.DrawImage(LGPImage, 0, 0, LObjWidth, LObjHeight);
end;
//---------------------------------------------------------------------------
// 描画の基準座標をワールド座標空間に戻す
// 描画の原点がこのコントロールの左上となる
// ページ座標空間の時の(0, 0)を交点とした十字線を描く
// ページ座標空間のままで描画してもよいが,ScaleTransformを実行していると,
// 線の太さなども,設定した比率で拡大または縮小されてしまう
//---------------------------------------------------------------------------
LGPGraphic.ResetTransform;
LGPPen := TGPPen.Create(aclBlack);
LGPPen.SetDashStyle(DashStyleDash);
LGPGraphic.DrawLine(LGPPen, 0, LYLocation, Width, LYLocation);
LGPGraphic.DrawLine(LGPPen, LXLocation, 0, LXLocation, Height);
//Createしたオブジェクトは解放処理する
LGPPen.Free;
LGPImage.Free;
LGPGraphic.Free;
end;
end.
回転した画像を TImage 等に表示する場合,TImage のサイズを,回転後の画像を完全に含むサイズにしないと,描画が欠けてしまうことになります.
そのためには,回転後の画像を完全に含む矩形領域を取得する必要があります.前のページで説明で使用した座標値の変換関数では,座標の回転を含む場合,取得でないようです.
そこで,このサンプルでは,TGPMatrix とパスの性質を利用しています.TGPMatrix による画像の変換は座標軸の回転はしません.全てワールド座標値で行われます.矩形のパス図形を生成し,画像と同じ操作を TGPMatrix で設定します.その結果を,以下のリンクのサンプルで説明した GetBounds 関数で取得します. |
|
図10
設計時画面 |
|
図11
画像描画領域の矩形
|
リスト3
回転した画像オブジェクトの描画領域を取得 |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ExtCtrls, StdCtrls, GDIPAPI, GDIPOBJ, ComCtrls;
type
TMyPanel = class(TPanel)
private
FRotateAngle : Integer;
procedure SetRotateAngle(const Value: Integer);
protected
procedure Paint; override;
public
constructor Create(AOwner: TComponent); override;
property RotateAngle : Integer read FRotateAngle write SetRotateAngle;
end;
TForm1 = class(TForm)
TrackBar1: TTrackBar;
procedure FormCreate(Sender: TObject);
procedure TrackBar1Change(Sender: TObject);
private
{ Private 宣言 }
MyPanel : TMyPanel;
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
//=============================================================================
// フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
Caption := 'GDI+ オブジェクトの描画領域の矩形';
//描画するコントロールを生成
MyPanel := TMyPanel.Create(Self);
with MyPanel do begin
Parent := Self;
SetBounds(5, 40, Self.ClientWidth - 10, Self.ClientHeight - 45);
DoubleBuffered := True;
ControlStyle := MyPanel.ControlStyle + [csOpaque];
BevelOuter := bvNone;
Visible := True;
Color := clWhite;
ParentBackground := False;
Anchors := [akLeft, akTop, akRight, akBottom];
end;
//回転角度変更用のTrackBar1の設定
//回転角度は-360~360度とする
with TrackBar1 do begin
ShowSelRange := False;
TickStyle := tsNone;
Height := 26;
Min := -360;
Max := 360;
Position := 0;
end;
end;
//=============================================================================
// TrackBar1のOnClickイベント処理
// オブジェクトの回転角度の設定の変更
//=============================================================================
procedure TForm1.TrackBar1Change(Sender: TObject);
begin
if not Assigned(MyPanel) then exit;
MyPanel.RotateAngle := TrackBar1.Position;
end;
{ TMyPanel }
//-----------------------------------------------------------------------------
// コンストラクタ
// 各種プロパティを初期値を設定
//-----------------------------------------------------------------------------
constructor TMyPanel.Create(AOwner: TComponent);
begin
inherited;
FRotateAngle := 0;
end;
//-----------------------------------------------------------------------------
// RotateAngleプロパティ設定用メソッド
// オブジェクトの回転角度の設定
//-----------------------------------------------------------------------------
procedure TMyPanel.SetRotateAngle(const Value: Integer);
begin
if not Assigned(Parent) then exit;
if FRotateAngle <> Value then begin
FRotateAngle := Value;
Invalidate;
end;
end;
//-----------------------------------------------------------------------------
// TMyPanelクラスのPaintメソッド
// 実際の描画コード
//-----------------------------------------------------------------------------
procedure TMyPanel.Paint;
var
LObjWidth : Integer;
LObjHeight : Integer;
LXLocation : Integer;
LYLocation : Integer;
LImageFilePath : String;
LGPImage : TGPImage;
LGPGraphic : TGPGraphics;
LGPMatrix : TGPMatrix;
LGPPath : TGPGraphicsPath;
LSizeRect : TGPRect;
LGPPen : TGPPen;
begin
inherited;
//画像の表示サイズ
LObjWidth := 130;
LObjHeight := 100;
//ページ座標系の原点座標の設定
LXLocation := Width div 2;
LYLocation := Height div 2;
//画像ファイルを指定.TGPImaageインスタンスを生成して読み込む
LImageFilePath := ExtractFilePath(ParamStr(0)) + '503.bmp';
LGPImage := TGPImage.Create(LImageFilePath);
//このTMyPanelのCanvasを描画先にしてTGPGraphicsのインスタンスを生成
LGPGraphic := TGPGraphics.Create(Canvas.Handle);
//座標の原点を(LXLocation,LYLocation)のページ座標空間にする
//以後,ResetTransformを実行するまでは,この点が(0, 0)となる
LGPGraphic.TranslateTransform(LXLocation, LYLocation);
//この行を実行するとX軸とY軸の倍率を変えることができる
//LGPGraphic.ScaleTransform(1.0, 1.5);
//画像のオブジェクトを回転する
LGPGraphic.RotateTransform(FRotateAngle);
//---------------------------------------------------------------------------
// 画像の描画
// TranslateTransformで設定した位置が描画原点(0, 0)となっている
// その原点から相対的な描画開始位置(左上の座標)を設定する
// つまり,ページ座標空間を基準とした描画コードとなる
// 回転の中心座標を(LXLocation, LYLocation)とするために,左と上に,オブジェク
// トの幅と高さの半分だけ,描画の始点をずらす
//---------------------------------------------------------------------------
LGPGraphic.DrawImage(
LGPImage, -LObjWidth div 2, -LObjHeight div 2, LObjWidth, LObjHeight);
//---------------------------------------------------------------------------
// 以下,画像オブジェクトの描画の矩形領域取得用のコード
// 取得した領域の矩形を表示する
//
// 描画の基準座標をワールド座標空間に戻し,
// 描画の原点をこのコントロールの左上にする
// パスを生成し,四角形を追加.TGPMarixの機能を使用して,上と同じページ座標
// 空間にして,同じ操作実行後に,パスのGetBounds関数で領域を取得
//---------------------------------------------------------------------------
//ワールド座標空間に戻す
LGPGraphic.ResetTransform;
//パスを生成して四角形を追加
LGPPath := TGPGraphicsPath.Create;
LGPPath.AddRectangle(MakeRect(
-LObjWidth div 2, -LObjHeight div 2, LObjWidth, LObjHeight));
//TGPMatrixを生成して座標基準を平行移動して回転操作の情報を格納
LGPMatrix := TGPMatrix.Create;
LGPMatrix.Translate(LXLocation, LYLocation);
//TGPGraphics.ScaleTransformを実行した場合は,このコードを実行する
//LGPMatrix.Scale(1.0, 1.5);
LGPMatrix.Rotate(FRotateAngle);
//そのTGPMatrixの情報でパス情報を更新
LGPPath.Transform(LGPMatrix);
//パスが含まれる矩形領域を取得
LGPPath.GetBounds(LSizeRect);
//TGPPenを生成して,そのペンで,取得した矩形領域の矩形を描画
LGPPen := TGPPen.Create(aclBlack);
LGPGraphic.DrawRectangle(LGPPen, LSizeRect);
//Createしたオブジェクトは解放処理する
LGPMatrix.Free;
LGPPath.Free;
LGPImage.Free;
LGPGraphic.Free;
end;
end.
04_TImage のサイズを設定して回転画像を表示 |
前の項でテストした結果を,実際に TImage に適用したサンプルです.
このサンプルでは,描画用の TMyPanel は必要ないので,生成していません. |
|
図12
設計時画面 |
|
図13
実行開始画面 |
|
図14
回転した例
- 回転する度に TImage のサイズを計算して設定している
|
次のコードのように,SetColorKey で透過色を設定すれば,ビットマップを透過表示できます. |
var
LGPImageAttr : TGPImageAttributes;
LColor : Cardinal;
begin
//
//
//画像の(0, 0)の点を透過色とする
LGPImage.GetPixel(0,0, LColor);
LGPImageAttr := TGPImageAttributes.Create;
LGPImageAttr.SetColorKey(LColor, LColor);
//LGPImageを描画する
LGPGraphic.DrawImage(
LGPImage,
MakeRect(-LObjWidth div 2, -LObjHeight div 2, LObjWidth, LObjHeight),
0,
0,
LGPImage.GetWidth,
LGPImage.GetHeight,
UnitPixel,
LGPImageAttr);
//
//
|
図15
ビットマップを透過表示する |
また,Image1.Transparent := True;
とすれば,TImage も透過します. |
|
図16
Transparent をTrue にした場合 |
リスト5
TImage コントロールに回転画像を表示 |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ExtCtrls, StdCtrls, GDIPAPI, GDIPOBJ, ComCtrls;
type
TForm1 = class(TForm)
TrackBar1: TTrackBar;
Image1: TImage;
procedure FormCreate(Sender: TObject);
procedure TrackBar1Change(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
//=============================================================================
// フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
Caption := 'GDI+ RotateTransform TImage';
Self.DoubleBuffered := True;
//TrackBar1の設定
//回転角度は-360~360度とする
with TrackBar1 do begin
ShowSelRange := False;
TickStyle := tsNone;
Height := 26;
Min := -360;
Max := 360;
Position := 0;
end;
TrackBar1Change(nil);
end;
//=============================================================================
// TrackBar1のOnChangeイベント
// TrackBar1の値を変更したら,TImageに再描画
//=============================================================================
procedure TForm1.TrackBar1Change(Sender: TObject);
var
LObjWidth : Integer;
LObjHeight : Integer;
LRotateAngle : Integer;
LStartX : Integer;
LStartY : Integer;
LImageFilePath : String;
LGPImage : TGPBitmap;
LMatrix : TGPMatrix;
LGPPath : TGPGraphicsPath;
LSizeRect : TGPRect;
LGPGraphic : TGPGraphics;
begin
//回転角はTrackBar1の値
LRotateAngle := TrackBar1.Position;
//画像ファイルを指定.TGPBitmapを生成して格納
LImageFilePath := ExtractFilePath(ParamStr(0)) + '503.bmp';
LGPImage := TGPBitmap.Create(LImageFilePath);
//TGPBitmap.GetWidth,TGPBitmap.GetHeightでイメージの幅と高さが取得できるが,
//ここでは,別の幅と高さで描画する(TCanvasのStretchDraw相当の描画)
LObjWidth := 200;
LObjHeight := 150;
//描画の基準点(回転の中心座標)を表示サイズの中央とする
LStartX := LObjWidth div 2;
LStartY := LObjHeight div 2;
//---------------------------------------------------------------------------
// 以下,TImageのサイズを計算するための処理
// 画像オブジェクトの描画の矩形領域取得用のコード
// パスを生成し,四角形を追加.TGPMarixの機能を使用して,描画するオブジェク
// に対する基準座標を平行移動して,回転の操作を行う
//---------------------------------------------------------------------------
//このCanvasを描画先にしてTGPGraphicsオブジェクトを生成
LGPGraphic := TGPGraphics.Create(Canvas.Handle);
//パスを生成し,四角形を追加
LGPPath := TGPGraphicsPath.Create;
LGPPath.AddRectangle(
MakeRect(-LObjWidth div 2, -LObjHeight div 2, LObjWidth, LObjHeight));
//TGPMatrixを生成して座標基準を平行移動して回転操作の情報を格納
LMatrix := TGPMatrix.Create;
LMatrix.Translate(LStartX, LStartY);
LMatrix.Rotate(LRotateAngle);
//そのTGPMatrixの情報でパス情報を更新
LGPPath.Transform(LMatrix);
//パスの描画領域を示す矩形情報を取得
LGPPath.GetBounds(LSizeRect);
LMatrix.Free;
LGPPath.Free;
LGPGraphic.Free;
//---------------------------------------------------------------------------
// 描画の矩形情報の取得終了
// LSizeRect(TGPRect)に描画領域の矩形情報が格納されている
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// 以下,TImageへの描画コード
//---------------------------------------------------------------------------
//描画の位置とサイズの設定
LStartX := LSizeRect.Width div 2;
LStartY := LSizeRect.Height div 2;
//TImageの描画を消去し,取得したサイズに設定.背景を塗りつぶす
Image1.Picture.Assign(nil);
Image1.SetBounds(Image1.Left, Image1.Top, LSizeRect.Width, LSizeRect.Height);
Image1.Canvas.Brush.Color := clSilver;
Image1.Canvas.FillRect(Image1.Canvas.ClipRect);
//描画先をTImage.CanvasとしてTGPGraphicsオブジェクトを生成
LGPGraphic := TGPGraphics.Create(Form1.Image1.Canvas.Handle);
//ワールド座標空間に戻す
LGPGraphic.ResetTransform;
//座標原点を移動し回転する
LGPGraphic.TranslateTransform(LStartX, LStartY);
LGPGraphic.RotateTransform(LRotateAngle);
//LGPImageを描画する
LGPGraphic.DrawImage(
LGPImage, -LObjWidth div 2, -LObjHeight div 2, LObjWidth, LObjHeight);
LGPGraphic.Free;
LGPImage.Free;
end;
end.
05_RotateTransform 関数によるブラシの回転 |
ブラシも回転できますが,ソリッドブラシだけは回転できません.
たとえ回転できたとしても,何にも変化がないでしょう.
グラデーションブラシの回転で,座標原点の移動,スケーリング等を,経時的に変化させれば,幻想的な世界が創れるかも知れません.
残念ですが,このサンプルはテクスチャブラシの例です.しかも,毎度おなじみの「ヒヨコ」の画像となっています.しかも回転だけです.サイズの変化もしません.
トラックバー,または矢印キーを操作すると回転します.楽しんでください. |
|
図17
設計時画面 |
|
図18
実行開始画面 |
|
図19
回転した状態 |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ExtCtrls, StdCtrls, GDIPAPI, GDIPOBJ, ExtDlgs, ComCtrls;
type
TMyPanel = class(TPanel)
private
FRotateAngle : Integer;
procedure SetRotateAngle(const Value: Integer);
protected
procedure Paint; override;
public
constructor Create(AOwner: TComponent); override;
property RotateAngle : Integer read FRotateAngle write SetRotateAngle;
end;
TForm1 = class(TForm)
TrackBar1: TTrackBar;
procedure FormCreate(Sender: TObject);
procedure TrackBar1Change(Sender: TObject);
private
{ Private 宣言 }
MyPanel : TMyPanel;
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
//=============================================================================
// フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
Caption := 'GDI+ ブラシの回転';
//描画するコントロールを生成
MyPanel := TMyPanel.Create(Self);
with MyPanel do begin
Parent := Self;
SetBounds(5, 40, Self.ClientWidth - 10, Self.ClientHeight - 45);
DoubleBuffered := True;
ControlStyle := MyPanel.ControlStyle + [csOpaque];
BevelOuter := bvNone;
Visible := True;
Color := clWhite;
ParentBackground := False;
Anchors := [akLeft, akTop, akRight, akBottom];
end;
//回転角度変更用のTrackBar1の設定
//回転角度は-360~360度とする
with TrackBar1 do begin
ShowSelRange := False;
TickStyle := tsNone;
Height := 26;
Min := -360;
Max := 360;
Position := 0;
end;
end;
//=============================================================================
// TrackBar1のOnClickイベント処理
// オブジェクトの回転角度の設定
//=============================================================================
procedure TForm1.TrackBar1Change(Sender: TObject);
begin
if not Assigned(MyPanel) then exit;
MyPanel.RotateAngle := TrackBar1.Position;
end;
{ TMyPanel }
//-----------------------------------------------------------------------------
// コンストラクタ
// 各種プロパティを初期値を設定
//-----------------------------------------------------------------------------
constructor TMyPanel.Create(AOwner: TComponent);
begin
inherited;
FRotateAngle := 0;
end;
//-----------------------------------------------------------------------------
// RotateAngleプロパティ設定用メソッド
// オブジェクトの回転角度の設定
//-----------------------------------------------------------------------------
procedure TMyPanel.SetRotateAngle(const Value: Integer);
begin
if not Assigned(Parent) then exit;
if FRotateAngle <> Value then begin
FRotateAngle := Value;
Invalidate;
end;
end;
//-----------------------------------------------------------------------------
// TMyPanelクラスのPaintメソッド
// 実際の描画コード
//-----------------------------------------------------------------------------
procedure TMyPanel.Paint;
var
LImageFilePath : String;
LGPImage : TGPImage;
LGPGraphic : TGPGraphics;
LGPRect : TGPRect;
LGPBrush : TGPTextureBrush;
LGPPen : TGPPen;
begin
inherited;
//画像ファイルを指定.TGPImaageインスタンスを生成して読み込む
LImageFilePath := ExtractFilePath(ParamStr(0)) + '502.gif';
LGPImage := TGPImage.Create(LImageFilePath);
//このTMyPanelのCanvasを描画先にしてTGPGraphicsのインスタンスを生成
LGPGraphic := TGPGraphics.Create(Canvas.Handle);
//描画領域を指定
LGPRect := MakeRect(0, 0, Width -1 , Height - 1);
//画像をTGPTextuerBrushに指定する
LGPBrush := TGPTextureBrush.Create(LGPImage);
//リセット
LGPBrush.ResetTransform;
//回転の中心を設定
LGPBrush.TranslateTransform(Width / 2, Height / 2);
//軸の倍率を変更して,サイズを小さくする
LGPBrush.ScaleTransform(0.5, 0.5);
//回転角度の指定
LGPBrush.RotateTransform(FRotateAngle);
//楕円を描画,内部を指定したブラシで塗潰す
LGPGraphic.FillEllipse(LGPBrush, LGPRect);
//外周を描く
LGPPen := TGPPen.Create(aclGray);
LGPGraphic.DrawEllipse(LGPPen, LGPRect);
//Createしたオブジェクトは解放処理する
LGPPen.Free;
LGPImage.Free;
LGPBrush.Free;
LGPGraphic.Free;
end;
end.
06_RotateTransform 関数による文字列の回転 |
|
図20
設計時画面 |
|
図21
実行開始画面 |
|
図22
回転した状態 |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ExtCtrls, StdCtrls, GDIPAPI, GDIPOBJ, ComCtrls;
type
TMyPanel = class(TPanel)
private
FRotateAngle : Integer;
procedure SetRotateAngle(const Value: Integer);
protected
procedure Paint; override;
public
constructor Create(AOwner: TComponent); override;
property RotateAngle : Integer read FRotateAngle write SetRotateAngle;
end;
TForm1 = class(TForm)
TrackBar1: TTrackBar;
procedure FormCreate(Sender: TObject);
procedure TrackBar1Change(Sender: TObject);
private
{ Private 宣言 }
MyPanel : TMyPanel;
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
//=============================================================================
// フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
Caption := 'GDI+ 文字列の回転';
//描画するコントロールを生成
MyPanel := TMyPanel.Create(Self);
with MyPanel do begin
Parent := Self;
SetBounds(5, 45, Self.ClientWidth - 10, Self.ClientHeight - 50);
DoubleBuffered := True;
ControlStyle := MyPanel.ControlStyle + [csOpaque];
BevelOuter := bvNone;
Visible := True;
Color := clWhite;
ParentBackground := False;
Anchors := [akLeft, akTop, akRight, akBottom];
end;
//回転角度変更用のTrackBar1の設定
//回転角度は-360~360度とする
with TrackBar1 do begin
ShowSelRange := False;
TickStyle := tsNone;
Height := 26;
Min := -360;
Max := 360;
Position := 0;
end;
end;
//=============================================================================
// TrackBar1のOnClickイベント処理
// オブジェクトの回転角度の設定
//=============================================================================
procedure TForm1.TrackBar1Change(Sender: TObject);
begin
if not Assigned(MyPanel) then exit;
MyPanel.RotateAngle := TrackBar1.Position;
end;
{ TMyPanel }
//-----------------------------------------------------------------------------
// コンストラクタ
// 各種プロパティを初期値を設定
//-----------------------------------------------------------------------------
constructor TMyPanel.Create(AOwner: TComponent);
begin
inherited;
FRotateAngle := 0;
end;
//-----------------------------------------------------------------------------
// RotateAngleプロパティ設定用メソッド
// オブジェクトの回転角度の設定
//-----------------------------------------------------------------------------
procedure TMyPanel.SetRotateAngle(const Value: Integer);
begin
if not Assigned(Parent) then exit;
if FRotateAngle <> Value then begin
FRotateAngle := Value;
Invalidate;
end;
end;
//-----------------------------------------------------------------------------
// TMyPanelクラスのPaintメソッド
// 実際の描画コード
//-----------------------------------------------------------------------------
procedure TMyPanel.Paint;
var
LXLocation : Integer;
LYLocation : Integer;
LFontSize : Single;
LGPGraphic : TGPGraphics;
LGPFont : TGPFont;
LGPBrush : TGPSolidBrush;
LGPPen : TGPPen;
begin
inherited;
//座標原点の移動位置の設定
LXLocation := Width div 2;
LYLocation := Height div 2;
//このTMyPanelのCanvasを描画先にしてTGPGraphicsのインスタンスを生成
LGPGraphic := TGPGraphics.Create(Canvas.Handle);
//座標の原点を(LXLocation,LYLocation)のページ座標空間にする
//以後,ResetTransformを実行するまでは,この点が(0, 0)となる
LGPGraphic.TranslateTransform(LXLocation, LYLocation);
//回転角度の指定
LGPGraphic.RotateTransform(FRotateAngle);
//TGPFontとTGPSolidBrushのオブジェクトを生成し設定
//文字のサイズをピクセル(ドット)単位で指定
LFontSize := 20.0;
LGPFont := TGPFont.Create('Arial', LFontSize, FontStyleRegular, UnitPixel);
LGPBrush := TGPSolidBrush.Create(MakeColor(255, 0, 0, 0));
//Canvasに文字列を描画
//回転するとジャッギーが目立つのでアンチエイリアス処理を実行
LGPGraphic.SetTextRenderingHint(TextRenderingHintAntiAlias);
LGPGraphic.DrawString(
'文字列の回転', - 1, LGPFont, MakePoint(0.0, -LFontSize /2.0), LGPBrush);
//ワールド座標(Canvasの左上が(0, 0)の座標系)に変換して十字線を描画
LGPGraphic.ResetTransform;
LGPPen := TGPPen.Create(aclBlack);
LGPPen.SetDashStyle(DashStyleDash);
LGPGraphic.DrawLine(LGPPen, 0, LYLocation, Width, LYLocation);
LGPGraphic.DrawLine(LGPPen, LXLocation, 0, LXLocation, Height);
//Createしたオブジェクトは解放処理する
LGPPen.Free;
LGPFont.Free;
LGPBrush.Free;
LGPGraphic.Free;
end;
end.
07_RotateTransform 関数による図形の回転 |
図形の回転のサンプルです.
RotateTransform 関数で座標軸を回転すると,この関数実行後の描画コードは,全てこのページ空間の設定で実行されます.確認のため,文字列も描画してみました.また,X 軸と Y 軸を独立してスケーリングできるようにしています. |
|
図23
設計時画面 |
|
図24
実行開始画面 |
|
図25
回転した状態 |
下図は X 軸に対してだけスケーリングをした結果です.X 軸と Y 軸のスケールが異なっているために変形して,平行四辺形になっています. |
|
図26
スケーリング |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ExtCtrls, StdCtrls, GDIPAPI, GDIPOBJ, ComCtrls;
type
TMyPanel = class(TPanel)
private
FRotateAngle : Integer;
FXScale : Single;
FYScale : Single;
procedure SetRotateAngle(const Value: Integer);
procedure SetXScale(const Value: Single);
procedure SetYScale(const Value: Single);
protected
procedure Paint; override;
public
constructor Create(AOwner: TComponent); override;
property RotateAngle : Integer read FRotateAngle write SetRotateAngle;
property XScale : Single read FXScale write SetXScale;
property YScale : Single read FYScale write SetYScale;
end;
TForm1 = class(TForm)
TrackBar1: TTrackBar;
TrackBar2: TTrackBar;
TrackBar3: TTrackBar;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
procedure FormCreate(Sender: TObject);
procedure TrackBar1Change(Sender: TObject);
procedure TrackBar2Change(Sender: TObject);
procedure TrackBar3Change(Sender: TObject);
private
{ Private 宣言 }
MyPanel : TMyPanel;
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
//=============================================================================
// フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
Caption := 'GDI+ 図形の回転';
//描画するコントロールを生成
MyPanel := TMyPanel.Create(Self);
with MyPanel do begin
Parent := Self;
SetBounds(5, 110, Self.ClientWidth - 10, Self.ClientHeight - 115);
DoubleBuffered := True;
ControlStyle := MyPanel.ControlStyle + [csOpaque];
BevelOuter := bvNone;
Visible := True;
Color := clWhite;
ParentBackground := False;
Anchors := [akLeft, akTop, akRight, akBottom];
end;
//回転角度変更用のTrackBar1の設定
//回転角度は-360~360度とする
with TrackBar1 do begin
ShowSelRange := False;
TickStyle := tsNone;
Height := 26;
Min := -360;
Max := 360;
Position := 0;
end;
//X軸のスケーリングの設定
with TrackBar2 do begin
ShowSelRange := False;
TickStyle := tsNone;
Height := 26;
Min := 10;
Max := 30;
Position := 10;
end;
//Y軸のスケーリングの設定
with TrackBar3 do begin
ShowSelRange := False;
TickStyle := tsNone;
Height := 26;
Min := 10;
Max := 30;
Position := 10;
end;
end;
//=============================================================================
// TrackBar1のOnClickイベント処理
// オブジェクトの回転角度の設定
//=============================================================================
procedure TForm1.TrackBar1Change(Sender: TObject);
begin
if not Assigned(MyPanel) then exit;
MyPanel.RotateAngle := TrackBar1.Position;
end;
//=============================================================================
// TrackBar2のOnClickイベント処理
// X軸のスケーリングの設定
//=============================================================================
procedure TForm1.TrackBar2Change(Sender: TObject);
begin
if not Assigned(MyPanel) then exit;
MyPanel.XScale := TrackBar2.Position / 10;
end;
//=============================================================================
// TrackBar3のOnClickイベント処理
// Y軸のスケーリングの設定
//=============================================================================
procedure TForm1.TrackBar3Change(Sender: TObject);
begin
if not Assigned(MyPanel) then exit;
MyPanel.YScale := TrackBar3.Position / 10;
end;
{ TMyPanel }
//-----------------------------------------------------------------------------
// コンストラクタ
// 各種プロパティを初期値を設定
//-----------------------------------------------------------------------------
constructor TMyPanel.Create(AOwner: TComponent);
begin
inherited;
FRotateAngle := 0;
FXScale := 1.0;
FYScale := 1.0;
end;
//-----------------------------------------------------------------------------
// RotateAngleプロパティ設定用メソッド
// オブジェクトの回転角度の設定
//-----------------------------------------------------------------------------
procedure TMyPanel.SetRotateAngle(const Value: Integer);
begin
if not Assigned(Parent) then exit;
if FRotateAngle <> Value then begin
FRotateAngle := Value;
Invalidate;
end;
end;
//-----------------------------------------------------------------------------
// XScaleプロパティ設定用メソッド
// X軸のスケーリングの設定
//-----------------------------------------------------------------------------
procedure TMyPanel.SetXScale(const Value: Single);
begin
if not Assigned(Parent) then exit;
if FXScale <> Value then begin
FXScale := Value;
Invalidate;
end;
end;
//-----------------------------------------------------------------------------
// YScaleプロパティ設定用メソッド
// Y軸のスケーリングの設定
//-----------------------------------------------------------------------------
procedure TMyPanel.SetYScale(const Value: Single);
begin
if not Assigned(Parent) then exit;
if FYScale <> Value then begin
FYScale := Value;
Invalidate;
end;
end;
//-----------------------------------------------------------------------------
// TMyPanelクラスのPaintメソッド
// 実際の描画コード
//-----------------------------------------------------------------------------
procedure TMyPanel.Paint;
var
LXLocation : Integer;
LYLocation : Integer;
LFontSize : Single;
LGPGraphic : TGPGraphics;
LGPFont : TGPFont;
LGPBrush : TGPSolidBrush;
LGPPen : TGPPen;
begin
inherited;
//座標原点の移動位置の設定
LXLocation := Width div 2;
LYLocation := Height div 2;
//このTMyPanelのCanvasを描画先にしてTGPGraphicsのインスタンスを生成
LGPGraphic := TGPGraphics.Create(Canvas.Handle);
LGPGraphic.ResetTransform;
//座標の原点を(LXLocation,LYLocation)のページ座標空間にする
//以後,ResetTransformを実行するまでは,この点が(0, 0)となる
LGPGraphic.TranslateTransform(LXLocation, LYLocation);
//X軸とY軸のスケーリング
LGPGraphic.ScaleTransform(FXScale, FYScale);
//回転角度の指定
LGPGraphic.RotateTransform(FRotateAngle);
//四角形を描画
LGPPen := TGPPen.Create(aclGreen, 7);
LGPGraphic.SetSmoothingMode(SmoothingModeAntiAlias);
LGPGraphic.DrawRectangle(LGPPen, 0, 0, 80, 50);
//TGPFontとTGPSolidBrushのオブジェクトを生成し設定
//文字のサイズをピクセル(ドット)単位で指定して文字列を描画
LFontSize := 20.0;
LGPFont := TGPFont.Create('Arial', LFontSize, FontStyleRegular, UnitPixel);
LGPBrush := TGPSolidBrush.Create(MakeColor(255, 0, 0, 0));
//回転するとジャッギーが目立つのでアンチエイリアス処理を実行
LGPGraphic.SetTextRenderingHint(TextRenderingHintAntiAlias);
LGPGraphic.DrawString('図形の回転', - 1, LGPFont, MakePoint(0.0, 55), LGPBrush);
LGPPen.Free;
//ワールド座標(Canvasの左上が(0, 0)の座標系)に変換して十字線を描画
LGPGraphic.ResetTransform;
LGPPen := TGPPen.Create(aclBlack);
LGPPen.SetDashStyle(DashStyleDash);
LGPGraphic.DrawLine(LGPPen, 0, LYLocation, Width, LYLocation);
LGPGraphic.DrawLine(LGPPen, LXLocation, 0, LXLocation, Height);
//Createしたオブジェクトは解放処理する
LGPPen.Free;
LGPFont.Free;
LGPBrush.Free;
LGPGraphic.Free;
end;
end.
08_RotateTransform 関数によるパスの回転 |
パス専用の回転用の関数はありません.TGPGraphics のオブジェクトとして操作します.次のページのサンプルで使用している TGPMatrix を利用すると,パスだけを回転させることができます.
このサンプルでは,パスのオブジェクトを生成し,楕円を追加しています.そして,そのパスをクリップしています.クリップすると,それ以降の描画内容は,このパスでクリップされます.
このことを利用して,このサンプルでは画像を表示してみました.パスを回転すると,表示している画像も回転します.
バスは,直線や曲線を組み合わせて,より複雑な図形を描くことができます.また,パスの座標をマウスで操作するようにもできます.柔軟性があります.
画像の一部を,そのようなパスの形で切り取ったり,貼り付けたりすれば,いろいろな画像処理のプログラムができそうです.
リージョン (TGPRegion) を使用しても同様なことができます. |
|
図27
設計時画面 |
|
図28
実行開始画面
|
|
図29
回転した状態 |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ExtCtrls, StdCtrls, GDIPAPI, GDIPOBJ, ComCtrls;
type
TMyPanel = class(TPanel)
private
FRotateAngle : Integer;
procedure SetRotateAngle(const Value: Integer);
protected
procedure Paint; override;
public
constructor Create(AOwner: TComponent); override;
property RotateAngle : Integer read FRotateAngle write SetRotateAngle;
end;
TForm1 = class(TForm)
TrackBar1: TTrackBar;
procedure FormCreate(Sender: TObject);
procedure TrackBar1Change(Sender: TObject);
private
{ Private 宣言 }
MyPanel : TMyPanel;
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
//=============================================================================
// フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
Caption := 'GDI+ パスの回転';
//描画するコントロールを生成
MyPanel := TMyPanel.Create(Self);
with MyPanel do begin
Parent := Self;
SetBounds(5, 40, Self.ClientWidth - 10, Self.ClientHeight - 45);
DoubleBuffered := True;
ControlStyle := MyPanel.ControlStyle + [csOpaque];
BevelOuter := bvNone;
Visible := True;
Color := clWhite;
ParentBackground := False;
Anchors := [akLeft, akTop, akRight, akBottom];
end;
//回転角度変更用のTrackBar1の設定
//回転角度は-360~360度とする
with TrackBar1 do begin
ShowSelRange := False;
TickStyle := tsNone;
Height := 26;
Min := -360;
Max := 360;
Position := 0;
end;
end;
//=============================================================================
// TrackBar1のOnClickイベント処理
// オブジェクトの回転角度の設定
//=============================================================================
procedure TForm1.TrackBar1Change(Sender: TObject);
begin
if not Assigned(MyPanel) then exit;
MyPanel.RotateAngle := TrackBar1.Position;
end;
{ TMyPanel }
//-----------------------------------------------------------------------------
// コンストラクタ
// 各種プロパティを初期値を設定
//-----------------------------------------------------------------------------
constructor TMyPanel.Create(AOwner: TComponent);
begin
inherited;
FRotateAngle := 0;
end;
//-----------------------------------------------------------------------------
// RotateAngleプロパティ設定用メソッド
// オブジェクトの回転角度の設定
//-----------------------------------------------------------------------------
procedure TMyPanel.SetRotateAngle(const Value: Integer);
begin
if not Assigned(Parent) then exit;
if FRotateAngle <> Value then begin
FRotateAngle := Value;
Invalidate;
end;
end;
//-----------------------------------------------------------------------------
// TMyPanelクラスのPaintメソッド
// 実際の描画コード
//-----------------------------------------------------------------------------
procedure TMyPanel.Paint;
var
LImageFilePath : String;
LGPImage : TGPImage;
LObjWidth : Integer;
LObjHeight : Integer;
LXLocation : Integer;
LYLocation : Integer;
LGPPath : TGPGraphicsPath;
LGPGraphic : TGPGraphics;
LGPPen : TGPPen;
begin
inherited;
//画像ファイルを指定.TGPImaageインスタンスを生成して読み込む
LImageFilePath := ExtractFilePath(ParamStr(0)) + 'Hachi.bmp';
LGPImage := TGPImage.Create(LImageFilePath);
//オブジェクトの表示サイズ
LObjWidth := 250;
LObjHeight := 188;
//回転の中心座標の設定
LXLocation := Width div 2;
LYLocation := Height div 2;
//このTMyPanelのCanvasを描画先にしてTGPGraphicsのインスタンスを生成
LGPGraphic := TGPGraphics.Create(Canvas.Handle);
LGPGraphic.ResetTransform;
//座標の原点を(LXLocation,LYLocation)にする
//以後,ResetTransformを実行するまでは,この点が(0, 0)となる
LGPGraphic.TranslateTransform(LXLocation, LYLocation);
//回転角度の指定
LGPGraphic.RotateTransform(FRotateAngle);
//パスを生成して楕円を追加
LGPPath := TGPGraphicsPath.Create;
LGPPath.AddEllipse(-LObjWidth div 2, -LObjHeight div 2, LObjWidth, LObjHeight);
//このパスで,以降の描画をクリップ
LGPGraphic.SetClip(LGPPath);
//画像を描画
LGPGraphic.DrawImage(LGPImage, MakeRect(-LObjWidth div 2,
-LObjHeight div 2,
LObjWidth,
LObjHeight));
//クリップを解除
LGPGraphic.ResetClip;
//左上が(0, 0)の座標系に変換して十字線を描画
LGPGraphic.ResetTransform;
//描画に使用するペンを生成
LGPPen := TGPPen.Create(aclGray);
LGPPen.SetDashStyle(DashStyleDash);
LGPGraphic.DrawLine(LGPPen, 0, LYLocation, Width, LYLocation);
LGPGraphic.DrawLine(LGPPen, LXLocation, 0, LXLocation, Height);
//Createしたオブジェクトは解放処理する
LGPImage.Free;
LGPPath.Free;
LGPGraphic.Free;
LGPPen.Free;
end;
end.
|