2016-11-27 83 views
1

我如何使用中心GDI +一個旋轉的圖像?中心使用旋轉的圖像GDI +

我在這裏創建一個小例子說明我的問題。

GUI

空白形式與OpenPictureDialog和顏料盒,對準客戶端。添加DoubleClick事件和OnPaintEvent的顏料盒。

背後

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的大小,你就可以編寫代碼。但我相信我可以找到一個sloution,否則我會問一個新的問題:D –

+3

我沒有看到調整PaintBox的問題 - 你已經把它的尺寸考慮在內。但爲什麼你不使用位圖來存儲PaintBox的圖片(計算一次,一次又一次地使用)? – MBo

+0

來跟你說實話:我沒有看過它,因爲我接受你的答案。調整窗體大小時,我看到了一些問題。我會做一些雙緩衝。 –