使用 GDI+ 旋转的图形看起来比原来的大
Graphic rotated with GDI+ appears bigger than the original
下面是我用GDI+画姿态指示器的实验
只要我用就
image.Canvas.Draw(-25, -410-slider1.Position * 4, horizonBitmap);
horizonBitmap
转1:1到image
.
但是当我尝试使用 GDI+ 旋转传输图像时,它出现在 image
上大约大 0.75 倍,我不得不使用
Matrix.Scale(SCALE_FACTOR, SCALE_FACTOR);
然后到处除以 SCALE_FACTOR
。
我做错了什么?
horizon.bmp
是 350 x 1120 像素。
下面是AI单元的完整代码。
unit AIMainform;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
Vcl.StdCtrls, Vcl.ComCtrls, Vcl.ExtCtrls, Winapi.GDIPOBJ, Winapi.GDIPAPI;
type
TForm1 = class(TForm)
procedure FormPaint(Sender: TObject);
private
image: TImage;
slider1: TTrackBar;
slider2: TTrackBar;
slider3: TTrackBar;
horizonGPImage: TGPImage;
horizonBitmap: TBitmap;
bezelBitmap: TBitmap;
headingBitmap: TBitmap;
wingsBitmap: TBitmap;
PitchAngle: Double;
RollAngle: Double;
YawAngle: Double;
procedure slider1_Scroll(Sender: TObject);
procedure slider2_Scroll(Sender: TObject);
procedure slider3_Scroll(Sender: TObject);
procedure drawRotated(rotAngle: Integer);
protected
procedure DoCreate(); override;
public
destructor Destroy(); override;
end;
var
Form1: TForm1;
implementation
uses
System.Math;
{$R *.dfm}
procedure TForm1.DoCreate();
var
s: string;
begin
inherited;
image := TImage.Create(Self);
image.Parent := Self;
image.SetBounds(0, 0, 300, 300);
image.Canvas.Brush.Color := clBlack;
image.Canvas.Pen.Color := clBlack;
image.Canvas.FillRect(Rect(0,0,image.Width, image.Height));
slider1 := TTrackBar.Create(Self);
slider1.Parent := Self;
slider1.Name := 'slider1';
slider1.Orientation := trVertical;
slider1.SetBounds(328, 21, 45, 190);
slider1.Max := 90;
slider1.Min := -90;
slider1.TabOrder := 1;
slider1.OnChange := slider1_Scroll;
slider2 := TTrackBar.Create(Self);
slider2.Parent := Self;
slider2.Name := 'slider2';
slider2.SetBounds(26, 329, 190, 45);
slider2.Max := 180;
slider2.Min := -180;
slider2.TabOrder := 2;
slider2.OnChange := slider2_Scroll;
slider3 := TTrackBar.Create(Self);
slider3.Parent := Self;
slider3.Name := 'slider3';
slider3.SetBounds(226, 329, 147, 45);
slider3.Max := 180;
slider3.Min := -180;
slider3.TabOrder := 3;
slider3.OnChange := slider3_Scroll;
Cursor := crHandPoint;
horizonBitmap := TBitmap.Create();
horizonBitmap.LoadFromFile('horizon.bmp');
bezelBitmap := TBitmap.Create();
bezelBitmap.LoadFromFile('bezel.bmp');
bezelBitmap.Transparent := True;
bezelBitmap.TransparentColor := clYellow;
headingBitmap := TBitmap.Create();
headingBitmap.LoadFromFile('heading.bmp');
headingBitmap.Transparent := True;
headingBitmap.TransparentColor := clBlack;
wingsBitmap := TBitmap.Create();
wingsBitmap.LoadFromFile('wings.bmp');
wingsBitmap.Transparent := True;
wingsBitmap.TransparentColor := clYellow;
horizonGPImage := TGPImage.Create('horizon.bmp');
PitchAngle := 0;
RollAngle := 0;
YawAngle := 0;
//ptBoule := Point(-25, -410); //Ground-Sky initial location
//ptHeading := Point(-592, 150); // Heading ticks
//ptRotation := Point(150, 150); // Point of rotation
DoubleBuffered := True;
end;
destructor TForm1.Destroy();
begin
horizonGPImage.Free();
inherited;
end;
procedure TForm1.slider1_Scroll(Sender: TObject);
begin
PitchAngle := slider1.Position;
RollAngle := DegToRad(slider2.Position);
YawAngle := DegToRad(slider3.Position);
Invalidate();
end;
procedure TForm1.slider2_Scroll(Sender: TObject);
begin
PitchAngle := slider1.Position;
RollAngle := DegToRad(slider2.Position);
YawAngle := DegToRad(slider3.Position);
Invalidate();
end;
procedure TForm1.slider3_Scroll(Sender: TObject);
begin
PitchAngle := slider1.Position;
RollAngle := DegToRad(slider2.Position);
YawAngle := DegToRad(slider3.Position);
Invalidate();
end;
procedure TForm1.drawRotated(rotAngle: Integer);
const
SCALE_FACTOR = 0.75;
var
GPGraphics: TGPGraphics;
Matrix: TGPMatrix;
cx, cy: Single;
begin
GPGraphics := TGPGraphics.Create(image.Canvas.Handle);
Matrix := TGPMatrix.Create;
try
//Matrix.Translate(0, 0);
Matrix.Scale(SCALE_FACTOR, SCALE_FACTOR);
cx := image.Width div 2;
cy := image.Height div 2;
Matrix.RotateAt(rotAngle, MakePoint(cx / SCALE_FACTOR, cy / SCALE_FACTOR));
GPGraphics.SetTransform(Matrix);
GPGraphics.DrawImage(horizonGPImage, -35, (-410-slider1.Position * 4) / SCALE_FACTOR);
finally
Matrix.Free();
GPGraphics.Free();
end;
end;
procedure TForm1.FormPaint(Sender: TObject);
begin
inherited;
//image.Canvas.Draw(-25, -410-slider1.Position * 4, horizonBitmap);
drawRotated(slider2.Position);
//0..1260
image.Canvas.Draw(-592-slider3.Position * 4, 150, headingBitmap);
image.Canvas.Draw(0, 0, bezelBitmap);
image.Canvas.Draw(75, 125, wingsBitmap);
end;
end.
与旋转无关。问题是由于 DPI 写在图像内。
在我的实验中,根据需要显示没有 DPI 的 bmp。当我设置 72 DPI 分辨率(使用 IrfanView 程序)时,它以更大的尺寸绘制。
DPI 设置为 120(我的屏幕比通常的 96 dpi 高 125%)绘制 1:1。
所以 GDIPLus 在这里太聪明了 - 它试图在 cm/inches 中绘制具有 "correct" 物理尺寸的图像。
解决方案可能相当简单 - 在输出过程中使用目标矩形参数和源图像的像素大小:
GPGraphics.DrawImage(horizonGPImage, 0, 0,
horizonGPImage.GetWidth, horizonGPImage.GetHeight);
下面是我用GDI+画姿态指示器的实验
只要我用就
image.Canvas.Draw(-25, -410-slider1.Position * 4, horizonBitmap);
horizonBitmap
转1:1到image
.
但是当我尝试使用 GDI+ 旋转传输图像时,它出现在 image
上大约大 0.75 倍,我不得不使用
Matrix.Scale(SCALE_FACTOR, SCALE_FACTOR);
然后到处除以 SCALE_FACTOR
。
我做错了什么?
horizon.bmp
是 350 x 1120 像素。
下面是AI单元的完整代码。
unit AIMainform;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
Vcl.StdCtrls, Vcl.ComCtrls, Vcl.ExtCtrls, Winapi.GDIPOBJ, Winapi.GDIPAPI;
type
TForm1 = class(TForm)
procedure FormPaint(Sender: TObject);
private
image: TImage;
slider1: TTrackBar;
slider2: TTrackBar;
slider3: TTrackBar;
horizonGPImage: TGPImage;
horizonBitmap: TBitmap;
bezelBitmap: TBitmap;
headingBitmap: TBitmap;
wingsBitmap: TBitmap;
PitchAngle: Double;
RollAngle: Double;
YawAngle: Double;
procedure slider1_Scroll(Sender: TObject);
procedure slider2_Scroll(Sender: TObject);
procedure slider3_Scroll(Sender: TObject);
procedure drawRotated(rotAngle: Integer);
protected
procedure DoCreate(); override;
public
destructor Destroy(); override;
end;
var
Form1: TForm1;
implementation
uses
System.Math;
{$R *.dfm}
procedure TForm1.DoCreate();
var
s: string;
begin
inherited;
image := TImage.Create(Self);
image.Parent := Self;
image.SetBounds(0, 0, 300, 300);
image.Canvas.Brush.Color := clBlack;
image.Canvas.Pen.Color := clBlack;
image.Canvas.FillRect(Rect(0,0,image.Width, image.Height));
slider1 := TTrackBar.Create(Self);
slider1.Parent := Self;
slider1.Name := 'slider1';
slider1.Orientation := trVertical;
slider1.SetBounds(328, 21, 45, 190);
slider1.Max := 90;
slider1.Min := -90;
slider1.TabOrder := 1;
slider1.OnChange := slider1_Scroll;
slider2 := TTrackBar.Create(Self);
slider2.Parent := Self;
slider2.Name := 'slider2';
slider2.SetBounds(26, 329, 190, 45);
slider2.Max := 180;
slider2.Min := -180;
slider2.TabOrder := 2;
slider2.OnChange := slider2_Scroll;
slider3 := TTrackBar.Create(Self);
slider3.Parent := Self;
slider3.Name := 'slider3';
slider3.SetBounds(226, 329, 147, 45);
slider3.Max := 180;
slider3.Min := -180;
slider3.TabOrder := 3;
slider3.OnChange := slider3_Scroll;
Cursor := crHandPoint;
horizonBitmap := TBitmap.Create();
horizonBitmap.LoadFromFile('horizon.bmp');
bezelBitmap := TBitmap.Create();
bezelBitmap.LoadFromFile('bezel.bmp');
bezelBitmap.Transparent := True;
bezelBitmap.TransparentColor := clYellow;
headingBitmap := TBitmap.Create();
headingBitmap.LoadFromFile('heading.bmp');
headingBitmap.Transparent := True;
headingBitmap.TransparentColor := clBlack;
wingsBitmap := TBitmap.Create();
wingsBitmap.LoadFromFile('wings.bmp');
wingsBitmap.Transparent := True;
wingsBitmap.TransparentColor := clYellow;
horizonGPImage := TGPImage.Create('horizon.bmp');
PitchAngle := 0;
RollAngle := 0;
YawAngle := 0;
//ptBoule := Point(-25, -410); //Ground-Sky initial location
//ptHeading := Point(-592, 150); // Heading ticks
//ptRotation := Point(150, 150); // Point of rotation
DoubleBuffered := True;
end;
destructor TForm1.Destroy();
begin
horizonGPImage.Free();
inherited;
end;
procedure TForm1.slider1_Scroll(Sender: TObject);
begin
PitchAngle := slider1.Position;
RollAngle := DegToRad(slider2.Position);
YawAngle := DegToRad(slider3.Position);
Invalidate();
end;
procedure TForm1.slider2_Scroll(Sender: TObject);
begin
PitchAngle := slider1.Position;
RollAngle := DegToRad(slider2.Position);
YawAngle := DegToRad(slider3.Position);
Invalidate();
end;
procedure TForm1.slider3_Scroll(Sender: TObject);
begin
PitchAngle := slider1.Position;
RollAngle := DegToRad(slider2.Position);
YawAngle := DegToRad(slider3.Position);
Invalidate();
end;
procedure TForm1.drawRotated(rotAngle: Integer);
const
SCALE_FACTOR = 0.75;
var
GPGraphics: TGPGraphics;
Matrix: TGPMatrix;
cx, cy: Single;
begin
GPGraphics := TGPGraphics.Create(image.Canvas.Handle);
Matrix := TGPMatrix.Create;
try
//Matrix.Translate(0, 0);
Matrix.Scale(SCALE_FACTOR, SCALE_FACTOR);
cx := image.Width div 2;
cy := image.Height div 2;
Matrix.RotateAt(rotAngle, MakePoint(cx / SCALE_FACTOR, cy / SCALE_FACTOR));
GPGraphics.SetTransform(Matrix);
GPGraphics.DrawImage(horizonGPImage, -35, (-410-slider1.Position * 4) / SCALE_FACTOR);
finally
Matrix.Free();
GPGraphics.Free();
end;
end;
procedure TForm1.FormPaint(Sender: TObject);
begin
inherited;
//image.Canvas.Draw(-25, -410-slider1.Position * 4, horizonBitmap);
drawRotated(slider2.Position);
//0..1260
image.Canvas.Draw(-592-slider3.Position * 4, 150, headingBitmap);
image.Canvas.Draw(0, 0, bezelBitmap);
image.Canvas.Draw(75, 125, wingsBitmap);
end;
end.
与旋转无关。问题是由于 DPI 写在图像内。
在我的实验中,根据需要显示没有 DPI 的 bmp。当我设置 72 DPI 分辨率(使用 IrfanView 程序)时,它以更大的尺寸绘制。
DPI 设置为 120(我的屏幕比通常的 96 dpi 高 125%)绘制 1:1。
所以 GDIPLus 在这里太聪明了 - 它试图在 cm/inches 中绘制具有 "correct" 物理尺寸的图像。
解决方案可能相当简单 - 在输出过程中使用目标矩形参数和源图像的像素大小:
GPGraphics.DrawImage(horizonGPImage, 0, 0,
horizonGPImage.GetWidth, horizonGPImage.GetHeight);