TPaintBox 使用 SetWorldTransform 旋转图像
TPaintBox rotate image with SetWorldTransform
我正在将图像加载到 TPaintBox
,然后尝试使用 SetWorldTransform as suggested in this answer:
旋转它
图片通过 TPaintBox.Invalidate -> TPaintBox.OnPaint
加载正常。
但是当我点击测试按钮 BtnRotateWorldTransform
时,
我看到图像闪烁但没有旋转。
procedure TFrmRotateImage.FormCreate(Sender: TObject);
begin
FWICImage := TWICImage.Create;
end;
procedure TFrmRotateImage.BtnLoadPaintBoxClick(Sender: TObject);
begin
if DlgOpen.Execute then // PNG or JPG file
begin
try
FWICImage.LoadFromFile(DlgOpen.FileName);
FBoxLoaded := true;
PaintBox.Invalidate;
finally
end;
end;
end;
procedure TFrmRotateImage.PaintBoxPaint(Sender: TObject); // OnPaint handler
begin
if not FBoxLoaded then Exit;
PaintBox.Canvas.Draw(0,0,FWICImage);
end;
procedure TFrmRotateImage.BtnRotateWorldTransformClick(Sender: TObject); // Test button
var
lRect: TRect;
begin
lRect.Top := PaintBox.Top;
lRect.Left := PaintBox.Left;
lRect.Width := PaintBox.Width;
lRect.Height := PaintBox.Height;
StretchDrawRotated(PaintBox.Canvas,lRect,90,lRect.CenterPoint,FWICImage);
PaintBox.Invalidate;
end;
和
procedure XForm_SetRotation(out AXForm: TXForm; AAngle: Extended; ACenter: TPoint);
var
SinA, CosA: Extended;
begin
SinCos(AAngle, SinA, CosA);
AXForm.eM11 := CosA;
AXForm.eM12 := SinA;
AXForm.eM21 := -SinA;
AXForm.eM22 := CosA;
AXForm.eDx := (ACenter.X - (CosA * ACenter.X)) + ((SinA * ACenter.Y));
AXForm.eDy := (ACenter.Y - (SinA * ACenter.X)) - ((CosA * ACenter.Y));
end;
procedure StretchDrawRotated(ACanvas: TCanvas; const ARect: TRect; AAngle: Extended; ACenter: TPoint; AGraphic: TGraphic);
var
XForm, XFormOld: TXForm;
GMode: Integer;
begin
GMode := SetGraphicsMode(ACanvas.Handle, GM_ADVANCED);
try
if GetWorldTransform(ACanvas.Handle, XFormOld) then
try
XForm_SetRotation(XForm, AAngle, ACenter);
SetWorldTransform(ACanvas.Handle, XForm);
ACanvas.StretchDraw(ARect, AGraphic);
finally
SetWorldTransform(ACanvas.Handle, XFormOld);
end;
finally
SetGraphicsMode(ACanvas.Handle, GMode);
end;
end;
我忘记了什么?
我写了一个完整的例子。在此示例中,我展示了如何旋转、平移、缩放图像以及组合这些变换。
为此,我编写了 3 个函数来轻松准备旋转、缩放和平移。
在 PaintBox1Paint 事件处理程序中,我采用固定值进行旋转、缩放和平移。当然,在正常的应用程序中,它来自其他地方(例如 UI)。转换计算应在 PaintBox1Paint 过程之外,并在每次参数变化时完成。然后应调用 Invalidate,以便使用新的计算转换重新绘制它。
procedure TForm4.FormCreate(Sender: TObject);
begin
FWICImage := TWICImage.Create;
end;
procedure TForm4.FormDestroy(Sender: TObject);
begin
FreeAndNil(FWICImage);
end;
procedure TForm4.LoadImageButtonClick(Sender: TObject);
begin
FWICImage.LoadFromFile('C:\Users\fpiette\Pictures\Delphi25 ICS.jpg');
FBoxLoaded := TRUE;
PaintBox1.Invalidate;
end;
function XForm_SetRotation(
AAngle : Single;
ACenter : TPoint) : TXForm;
var
SinA, CosA: Extended;
begin
SinCos(AAngle, SinA, CosA);
Result.eM11 := CosA;
Result.eM12 := SinA;
Result.eM21 := -SinA;
Result.eM22 := CosA;
Result.eDx := (ACenter.X - (CosA * ACenter.X)) + ((SinA * ACenter.Y));
Result.eDy := (ACenter.Y - (SinA * ACenter.X)) - ((CosA * ACenter.Y));
end;
function XForm_SetScale(
const AZoomX : Single;
const AZoomY : Single;
const center: TPoint) : TXForm;
begin
Result.eM11 := AZoomX;
Result.eM12 := 0.0;
Result.eM21 := 0.0;
Result.eM22 := AZoomY;
Result.eDx := center.x - AZoomX * center.x;
Result.eDy := center.y - AZoomY * center.y;
end;
function XForm_SetTranslate(
const ADistX : Integer;
const ADistY : Integer) : TXForm;
begin
Result.eM11 := 1.0;
Result.eM12 := 0.0;
Result.eM21 := 0.0;
Result.eM22 := 1.0;
Result.eDx := ADistX;
Result.eDy := ADistY;
end;
procedure TForm4.PaintBox1Paint(Sender: TObject);
var
XFormScale : TXForm;
XFormRot : TXForm;
XFormXLat : TXForm;
XForm : TXForm;
XFormOld : TXForm;
GMode : Integer;
AZoomFactor : Single;
AAngle : Single;
ADistX : Integer;
ADistY : Integer;
ACanvas : TCanvas;
begin
if not FBoxLoaded then
Exit;
AZoomFactor := 0.25;
AAngle := 30.0;
ADistX := 100;
ADistY := 200;
ACanvas := PaintBox1.Canvas;
GMode := SetGraphicsMode(ACanvas.Handle, GM_ADVANCED);
try
if GetWorldTransform(ACanvas.Handle, XFormOld) then begin
try
XFormRot := XForm_SetRotation(
AAngle,
Point(FWICImage.Width div 2,
FWICImage.Height div 2));
XFormScale := XForm_SetScale(
AZoomFactor, AZoomFactor, Point(0, 0));
XFormXLat := XForm_SetTranslate(ADistX, ADistY);
CombineTransform(XForm, XFormRot, XFormScale);
CombineTransform(XForm, XForm, XFormXLat);
SetWorldTransform(ACanvas.Handle, XForm);
ACanvas.Draw(0, 0, FWICImage);
finally
SetWorldTransform(ACanvas.Handle, XFormOld);
end;
end;
finally
SetGraphicsMode(ACanvas.Handle, GMode);
end;
end;
我正在将图像加载到 TPaintBox
,然后尝试使用 SetWorldTransform as suggested in this answer:
图片通过 TPaintBox.Invalidate -> TPaintBox.OnPaint
加载正常。
但是当我点击测试按钮 BtnRotateWorldTransform
时,
我看到图像闪烁但没有旋转。
procedure TFrmRotateImage.FormCreate(Sender: TObject);
begin
FWICImage := TWICImage.Create;
end;
procedure TFrmRotateImage.BtnLoadPaintBoxClick(Sender: TObject);
begin
if DlgOpen.Execute then // PNG or JPG file
begin
try
FWICImage.LoadFromFile(DlgOpen.FileName);
FBoxLoaded := true;
PaintBox.Invalidate;
finally
end;
end;
end;
procedure TFrmRotateImage.PaintBoxPaint(Sender: TObject); // OnPaint handler
begin
if not FBoxLoaded then Exit;
PaintBox.Canvas.Draw(0,0,FWICImage);
end;
procedure TFrmRotateImage.BtnRotateWorldTransformClick(Sender: TObject); // Test button
var
lRect: TRect;
begin
lRect.Top := PaintBox.Top;
lRect.Left := PaintBox.Left;
lRect.Width := PaintBox.Width;
lRect.Height := PaintBox.Height;
StretchDrawRotated(PaintBox.Canvas,lRect,90,lRect.CenterPoint,FWICImage);
PaintBox.Invalidate;
end;
和
procedure XForm_SetRotation(out AXForm: TXForm; AAngle: Extended; ACenter: TPoint);
var
SinA, CosA: Extended;
begin
SinCos(AAngle, SinA, CosA);
AXForm.eM11 := CosA;
AXForm.eM12 := SinA;
AXForm.eM21 := -SinA;
AXForm.eM22 := CosA;
AXForm.eDx := (ACenter.X - (CosA * ACenter.X)) + ((SinA * ACenter.Y));
AXForm.eDy := (ACenter.Y - (SinA * ACenter.X)) - ((CosA * ACenter.Y));
end;
procedure StretchDrawRotated(ACanvas: TCanvas; const ARect: TRect; AAngle: Extended; ACenter: TPoint; AGraphic: TGraphic);
var
XForm, XFormOld: TXForm;
GMode: Integer;
begin
GMode := SetGraphicsMode(ACanvas.Handle, GM_ADVANCED);
try
if GetWorldTransform(ACanvas.Handle, XFormOld) then
try
XForm_SetRotation(XForm, AAngle, ACenter);
SetWorldTransform(ACanvas.Handle, XForm);
ACanvas.StretchDraw(ARect, AGraphic);
finally
SetWorldTransform(ACanvas.Handle, XFormOld);
end;
finally
SetGraphicsMode(ACanvas.Handle, GMode);
end;
end;
我忘记了什么?
我写了一个完整的例子。在此示例中,我展示了如何旋转、平移、缩放图像以及组合这些变换。
为此,我编写了 3 个函数来轻松准备旋转、缩放和平移。
在 PaintBox1Paint 事件处理程序中,我采用固定值进行旋转、缩放和平移。当然,在正常的应用程序中,它来自其他地方(例如 UI)。转换计算应在 PaintBox1Paint 过程之外,并在每次参数变化时完成。然后应调用 Invalidate,以便使用新的计算转换重新绘制它。
procedure TForm4.FormCreate(Sender: TObject);
begin
FWICImage := TWICImage.Create;
end;
procedure TForm4.FormDestroy(Sender: TObject);
begin
FreeAndNil(FWICImage);
end;
procedure TForm4.LoadImageButtonClick(Sender: TObject);
begin
FWICImage.LoadFromFile('C:\Users\fpiette\Pictures\Delphi25 ICS.jpg');
FBoxLoaded := TRUE;
PaintBox1.Invalidate;
end;
function XForm_SetRotation(
AAngle : Single;
ACenter : TPoint) : TXForm;
var
SinA, CosA: Extended;
begin
SinCos(AAngle, SinA, CosA);
Result.eM11 := CosA;
Result.eM12 := SinA;
Result.eM21 := -SinA;
Result.eM22 := CosA;
Result.eDx := (ACenter.X - (CosA * ACenter.X)) + ((SinA * ACenter.Y));
Result.eDy := (ACenter.Y - (SinA * ACenter.X)) - ((CosA * ACenter.Y));
end;
function XForm_SetScale(
const AZoomX : Single;
const AZoomY : Single;
const center: TPoint) : TXForm;
begin
Result.eM11 := AZoomX;
Result.eM12 := 0.0;
Result.eM21 := 0.0;
Result.eM22 := AZoomY;
Result.eDx := center.x - AZoomX * center.x;
Result.eDy := center.y - AZoomY * center.y;
end;
function XForm_SetTranslate(
const ADistX : Integer;
const ADistY : Integer) : TXForm;
begin
Result.eM11 := 1.0;
Result.eM12 := 0.0;
Result.eM21 := 0.0;
Result.eM22 := 1.0;
Result.eDx := ADistX;
Result.eDy := ADistY;
end;
procedure TForm4.PaintBox1Paint(Sender: TObject);
var
XFormScale : TXForm;
XFormRot : TXForm;
XFormXLat : TXForm;
XForm : TXForm;
XFormOld : TXForm;
GMode : Integer;
AZoomFactor : Single;
AAngle : Single;
ADistX : Integer;
ADistY : Integer;
ACanvas : TCanvas;
begin
if not FBoxLoaded then
Exit;
AZoomFactor := 0.25;
AAngle := 30.0;
ADistX := 100;
ADistY := 200;
ACanvas := PaintBox1.Canvas;
GMode := SetGraphicsMode(ACanvas.Handle, GM_ADVANCED);
try
if GetWorldTransform(ACanvas.Handle, XFormOld) then begin
try
XFormRot := XForm_SetRotation(
AAngle,
Point(FWICImage.Width div 2,
FWICImage.Height div 2));
XFormScale := XForm_SetScale(
AZoomFactor, AZoomFactor, Point(0, 0));
XFormXLat := XForm_SetTranslate(ADistX, ADistY);
CombineTransform(XForm, XFormRot, XFormScale);
CombineTransform(XForm, XForm, XFormXLat);
SetWorldTransform(ACanvas.Handle, XForm);
ACanvas.Draw(0, 0, FWICImage);
finally
SetWorldTransform(ACanvas.Handle, XFormOld);
end;
end;
finally
SetGraphicsMode(ACanvas.Handle, GMode);
end;
end;