2016-11-27 34 views
1

GDI +を使用して回転イメージの中心を合わせるにはどうすればよいですか?GDI +を使用して回転イメージを中心にする

ここで私の問題を示す小さな例を作成しました。

GUI OpenPictureDialog、クライアントに整列ペイントボックスと

ブランクフォーム。 DoubleClickイベントとOnPaintEventをPaintBoxに追加します。

unit Unit1; 

interface 

uses 

    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 
    Dialogs, Vcl.ExtCtrls, Vcl.ExtDlgs, GDIPAPI, GDIPOBJ, GDIPUTIL; 

type 
    TForm1 = class(TForm) 
    PaintBox1: TPaintBox; 
    OpenPictureDialog1: TOpenPictureDialog; 
    procedure PaintBox1Paint(Sender: TObject); 
    procedure PaintBox1DblClick(Sender: TObject); 
    private 
    { Private declarations } 
    FImage: TGPImage; 
    procedure DrawImage(aMaxWidth, aMaxHeight: Cardinal); overload; 
    procedure DrawImage; overload; 
    public 
    { Public declarations } 
    end; 

var 
    Form1: TForm1; 

implementation 


{$R *.dfm} 

procedure TForm1.DrawImage(aMaxWidth, aMaxHeight: Cardinal); 
var 
    Ratio: Double; 
    Height, Width, HeightOffset, WidthOffset: Cardinal; 
begin 
    PaintBox1.Canvas.Brush.Color := clWhite; 
    FillRect(PaintBox1.Canvas.Handle, Rect(0, 0, aMaxWidth, aMaxHeight), PaintBox1.Canvas.Brush.Handle); 

    if FImage = nil then 
    exit; 

    Ratio := FImage.GetWidth/FImage.GetHeight; 

    Height := FImage.GetHeight; 
    Width := FImage.GetWidth; 

    if (FImage.GetHeight <= aMaxHeight) and (FImage.GetWidth <= aMaxWidth) then 
    { do nothing }; // Width and height allready set 

    if (FImage.GetHeight <= aMaxHeight) and (FImage.GetWidth > aMaxWidth) then 
    Width := Round(FImage.GetHeight * Ratio); 

    if (FImage.GetHeight > aMaxHeight) and (FImage.GetWidth > aMaxWidth) then 
    if Ratio > 1 then 
    begin 
     Height := Round(aMaxWidth/Ratio); 
     Width := aMaxWidth; 
    end 
    else 
    begin 
     Width := Round(aMaxHeight * Ratio); 
     Height := aMaxHeight; 
    end; 

    HeightOffset := (aMaxHeight - Height) div 2; 
    WidthOffset := (aMaxWidth - Width) div 2; 

    with TGPGraphics.Create(PaintBox1.Canvas.Handle) do 
    try 
     // RotateTransform(30); 
     DrawImage(FImage, WidthOffset, HeightOffset, Width, Height); 
    finally 
     Free; 
    end; 
end; 

procedure TForm1.DrawImage; 
begin 
    DrawImage(PaintBox1.Width, PaintBox1.Height); 
end; 

procedure TForm1.PaintBox1DblClick(Sender: TObject); 
begin 
    if not OpenPictureDialog1.Execute then 
    exit; 
    FImage.Free; 
    FImage := TGPImage.Create(OpenPictureDialog1.FileName); 
    DrawImage; 
end; 

procedure TForm1.PaintBox1Paint(Sender: TObject); 
begin 
    DrawImage; 
end; 

end. 

背後

コード私は私のイメージ何もかもが回転しない場合は罰金workesが、私はRotateTransform(30);を呼び出すときに画像が中心から外れています。

私は、原点を移動しようとしています

with TGPGraphics.Create(PaintBox1.Canvas.Handle) do 
    try 
     TranslateTransform(WidthOffset + (Width div 2), HeightOffset + (Height div 2)); 
     RotateTransform(30); 
     DrawImage(FImage, WidthOffset, HeightOffset, Width, Height); 
    finally 
     Free; 
    end; 

しかし、その後の画像は表示されません。

結果、私はこれで終わったの下にMBOの答えを使用して

:問題の

procedure TForm1.DrawImage(aMaxWidth, aMaxHeight: Cardinal; aRotationAngle: Double); 
var 
    radAngle, Ratio: Double; 
    Height, Width: Cardinal; 
    Wanted_CX, Wanted_CY: Integer; 
    WCX_InRotated, WCY_InRotated, xr, yr: Single; 
begin 
    PaintBox1.Canvas.Brush.Color := clWhite; 
    FillRect(PaintBox1.Canvas.Handle, Rect(0, 0, aMaxWidth, aMaxHeight), PaintBox1.Canvas.Brush.Handle); 

    if FImage = nil then 
    exit; 

    Ratio := FImage.GetWidth/FImage.GetHeight; 

    Height := FImage.GetHeight; 
    Width := FImage.GetWidth; 

    if (FImage.GetHeight <= aMaxHeight) and (FImage.GetWidth <= aMaxWidth) then 
    { do nothing }; // Width and height allready set 

    if (FImage.GetHeight <= aMaxHeight) and (FImage.GetWidth > aMaxWidth) then 
    Width := Round(FImage.GetHeight * Ratio); 

    if (FImage.GetHeight > aMaxHeight) and (FImage.GetWidth > aMaxWidth) then 
    if Ratio > 1 then 
    begin 
     Height := Round(aMaxWidth/Ratio); 
     Width := aMaxWidth; 
    end 
    else 
    begin 
     Width := Round(aMaxHeight * Ratio); 
     Height := aMaxHeight; 
    end; 

    radAngle := DegToRad(aRotationAngle); 
    Wanted_CX := PaintBox1.Width div 2; 
    Wanted_CY := PaintBox1.Height div 2; 
    xr := 0.5 * (Width * Cos(radAngle) - Height * Sin(radAngle)); // shift of rotated center 
    yr := 0.5 * (Width * Sin(radAngle) + Height * Cos(radAngle)); // relative to left top corner 

    with TGPGraphics.Create(PaintBox1.Canvas.Handle) do 
    try 
     RotateTransform(aRotationAngle); 
     WCX_InRotated := Cos(radAngle) * (Wanted_CX - xr) + Sin(radAngle) * (Wanted_CY - yr); 
     WCY_InRotated := -Sin(radAngle) * (Wanted_CX - xr) + Cos(radAngle) * (Wanted_CY - yr); 
     DrawImage(FImage, WCX_InRotated, WCY_InRotated); 
    finally 
     Free; 
    end; 
end; 
+2

@NGLNを求め、この質問(+回転のためのいくつかの他の技術を)答えは[こちら](http://stackoverflow.com/q/10633400/2292722) –

答えて

4

出典:新(回転)座標系でのdrawImageの仕事、それがにそれほど単純ではありません希望の場所に絵を描く。

単純な例では、画像を回転し、指定された点を中心に出力します(黄色の円で表示)。

var 
    FImage: TGPImage; 
    w, h, Wanted_CX, Wanted_CY: Integer; 
    WCX_InRotated, WCY_InRotated, xr, yr: Single; 
    Fi, FiRad: Double; 
begin 
    FImage := TGPImage.Create('d:\distr\pics\test.bmp'); //220x250 
    Fi := 30; 
    FiRad := DegToRad(Fi); 
    w := FImage.GetWidth; 
    h := FImage.GetHeight; 
    Wanted_CX := 200;  //position of rotated image center 
    Wanted_CY := 200; 
    xr := 0.5 * (w * Cos(FiRad) - h * Sin(FiRad)); //shift of rotated center 
    yr := 0.5 * (w * Sin(FiRad) + h * Cos(FiRad)); //relative to left top corner 
    with TGPGraphics.Create(Canvas.Handle) do 
    try 
     RotateTransform(Fi); //rotates about left top corner 
     //transform windows coordinates into rotated system 
     WCX_InRotated := Cos(FiRad) * (Wanted_CX - xr) + Sin(FiRad) * (Wanted_CY - yr); 
     WCY_InRotated := -Sin(FiRad) * (Wanted_CX - xr) + Cos(FiRad) * (Wanted_CY - yr); 
     DrawImage(FImage, WCX_InRotated, WCY_InRotated); 
    finally 
     Free; 
    end; 

    Canvas.Brush.Color := clYellow; 
    Canvas.Ellipse(200 - 4, 200 - 4, 200 + 5, 200 + 5); 
end; 

enter image description here

+0

ありがとう非常に。 PaintBoxのサイズを変更しない限り、コードは動作します。しかし、私はそれについて恥ずべきを見つけることができると信じています。そうでなければ新しい質問をします:D –

+3

PaintBoxのサイズ変更に関する問題はありません。すでに寸法を考慮しています。しかし、PaintBoxのためにピクチャを格納するためにビットマップを使用しないのはなぜですか(何度も繰り返し計算します)。 – MBo

+0

あなたに正直である:私はあなたの答えを受け入れて以来、私はそれを見ていない。フォームのサイズを変更するときにいくつか問題が発生しました。ダブルバッファリングをします。 –

関連する問題