GDI+ 在Delphi程序的应用 -- Matrix应用心得(转)
2007-09-27 10:06
597 查看
关于GDI+的几何变换类Matrix的理论和应用有很多书籍和文章介绍,本文只是谈一点自己的应用心得。
使用GDI+的Matrix类,可以很方便的进行提供了Rotate(旋转)、Scale( 缩放)、Shear(切变)等线性变换和Translate(平移),还可以通过这几个基本的变换组成更复杂的复合变换。通过变换后的图形及原点坐标变化很大,如下面的语句:
g.DrawEllipse(Pens.Blue, 0, 0, 100, 50);
g.ScaleTransform(1.0, 0.5);
g.TranslateTransform(50.0, 0.0, moAppend);
g.RotateTransform(30, moAppend);
g.DrawEllipse(Pens.Blue, 0, 0, 100, 50);
将产生下面的图像:
function CalcTransRect(Origin: TGpRectF; e: TMatrixElements): TGpRectF;
function GetTransPoint(x, y: Single): TGpPointF;
begin
Result.X := e.m11 * x + e.m21 * y;
Result.Y := e.m12 * x + e.m22 * y;
end;
var
R: TGpRectF;
pf: array[0..3] of TGpPointF;
I: Integer;
begin
R := Origin;
// 分别计算四个角的相对坐标
pf[0] := GetTransPoint(R.X, R.Y);
pf[1] := GetTransPoint(R.Width + R.X, R.Y);
pf[2] := GetTransPoint(R.X, R.Height + R.Y);
pf[3] := GetTransPoint(R.Width + R.X, R.Height + R.Y);
// 取得左上角和右下角的坐标点
R := GpRect(pf[0].X, pf[0].Y, 0.0, 0.0);
for I := 0 to 3 do
begin
if R.X > pf[I].X then R.X := pf[I].X
else if R.Width < pf[I].X then R.Width := pf[I].X;
if R.Y > pf[I].Y then R.Y := pf[I].Y
else if R.Height < pf[I].Y then R.Height := pf[I].Y;
end;
// 求出矩形尺寸
R.Width := R.Width - R.X;
R.Height := R.Height - R.Y;
// 求得左上角实际坐标
R.X := R.X + e.dx;
R.Y := R.Y + e.dy;
Result := R;
end;
procedure TMainForm.Button1Click(Sender: TObject);
var
Image: TGpImage;
g: TGpGraphics;
m: TGpMatrix;
r: TGpRectF;
begin
Image := TGpImage.Create('....Mediamsn.jpg');
g := TGpGraphics.Create(Handle, False);
m := TGpMatrix.Create;
try
r := GpRect(20.0, 20.0, Image.Width, Image.Height);
g.Clear(ARGBFromTColor(Color));
g.DrawImage(Image, r);
m.Rotate(30);
m.Scale(1.8, 0.8);
m.Shear(0.3, 0.2);
g.SetTransform(m);
g.DrawImage(Image, r);
r := CalcTransRect(r, m.Elements);
g.ResetTransform;
g.DrawRectangle(Pens.Red, r);
finally
Image.Free;
g.Free;
m.Free;
end;
end;
运行结果如下图,红色的矩形是计算出的变换后的坐标,与变换后的图像完全吻合:
g.DrawImage(Image, 20, 20, Image.Width, Image.Height); //用绝对坐标画原图
m.Translate(20, 20); // 坐标转换
m.Rotate(30);
m.Scale(1.8, 0.8);
m.Shear(0.3, 0.2);
g.SetTransform(m);
g.DrawImage(Image, 0, 0, Image.Width, Image.Height); //用相对坐标画图
其结果为下图,完全符合要求:
procedure ScaleAt(m: TGpMatrix; ScaleX, ScaleY, x, y: Single; Order: TMatrixOrder = moPrepend);
begin
if order = moAppend then
begin
x := -x;
y := -y;
end;
m.Translate(x, y, Order);
m.Scale(ScaleX, ScaleY, Order);
m.Translate(-x, -y, Order);
end;
procedure ShearAt(m: TGpMatrix; ShearX, ShearY, x, y: Single; Order: TMatrixOrder = moPrepend);
begin
if order = moAppend then
begin
x := -x;
y := -y;
end;
m.Translate(x, y, Order);
m.Shear(ShearX, ShearY, Order);
m.Translate(-x, -y, Order);
end;
procedure TMainForm.Button2Click(Sender: TObject);
var
Image: TGpImage;
g: TGpGraphics;
m: TGpMatrix;
begin
Image := TGpImage.Create('....Mediamsn.jpg');
g := TGpGraphics.Create(Handle, False);
m := TGpMatrix.Create;
try
g.DrawImage(Image, 20, 20, Image.Width, Image.Height);
m.RotateAt(30, GpPoint(20.0, 20.0), moAppend);
ScaleAt(m, 1.8, 0.8, 20, 20, moAppend);
ShearAt(m, 0.3, 0.2, 20, 20, moAppend);
g.SetTransform(m);
g.DrawImage(Image, 20, 20, Image.Width, Image.Height);
finally
Image.Free;
g.Free;
m.Free;
end;
end;
运行结果如下图,如果改为默认操作顺序,则和前面平移坐标后的运行结果完全一样:
说明,本文所用GDI+代码与网上流通的不兼容,如上面例子中的TMatrixElements,定义为:
TMatrixElements = packed record
case Integer of
0: (Elements: array[0..5] of Single);
1: (m11, m12, m21, m22, dx, dy: Single);
end;
而网上流通的则定义为一个数组:
TMatrixArray = array[0..5] of Single;
使用GDI+的Matrix类,可以很方便的进行提供了Rotate(旋转)、Scale( 缩放)、Shear(切变)等线性变换和Translate(平移),还可以通过这几个基本的变换组成更复杂的复合变换。通过变换后的图形及原点坐标变化很大,如下面的语句:
g.DrawEllipse(Pens.Blue, 0, 0, 100, 50);
g.ScaleTransform(1.0, 0.5);
g.TranslateTransform(50.0, 0.0, moAppend);
g.RotateTransform(30, moAppend);
g.DrawEllipse(Pens.Blue, 0, 0, 100, 50);
将产生下面的图像:
function CalcTransRect(Origin: TGpRectF; e: TMatrixElements): TGpRectF;
function GetTransPoint(x, y: Single): TGpPointF;
begin
Result.X := e.m11 * x + e.m21 * y;
Result.Y := e.m12 * x + e.m22 * y;
end;
var
R: TGpRectF;
pf: array[0..3] of TGpPointF;
I: Integer;
begin
R := Origin;
// 分别计算四个角的相对坐标
pf[0] := GetTransPoint(R.X, R.Y);
pf[1] := GetTransPoint(R.Width + R.X, R.Y);
pf[2] := GetTransPoint(R.X, R.Height + R.Y);
pf[3] := GetTransPoint(R.Width + R.X, R.Height + R.Y);
// 取得左上角和右下角的坐标点
R := GpRect(pf[0].X, pf[0].Y, 0.0, 0.0);
for I := 0 to 3 do
begin
if R.X > pf[I].X then R.X := pf[I].X
else if R.Width < pf[I].X then R.Width := pf[I].X;
if R.Y > pf[I].Y then R.Y := pf[I].Y
else if R.Height < pf[I].Y then R.Height := pf[I].Y;
end;
// 求出矩形尺寸
R.Width := R.Width - R.X;
R.Height := R.Height - R.Y;
// 求得左上角实际坐标
R.X := R.X + e.dx;
R.Y := R.Y + e.dy;
Result := R;
end;
procedure TMainForm.Button1Click(Sender: TObject);
var
Image: TGpImage;
g: TGpGraphics;
m: TGpMatrix;
r: TGpRectF;
begin
Image := TGpImage.Create('....Mediamsn.jpg');
g := TGpGraphics.Create(Handle, False);
m := TGpMatrix.Create;
try
r := GpRect(20.0, 20.0, Image.Width, Image.Height);
g.Clear(ARGBFromTColor(Color));
g.DrawImage(Image, r);
m.Rotate(30);
m.Scale(1.8, 0.8);
m.Shear(0.3, 0.2);
g.SetTransform(m);
g.DrawImage(Image, r);
r := CalcTransRect(r, m.Elements);
g.ResetTransform;
g.DrawRectangle(Pens.Red, r);
finally
Image.Free;
g.Free;
m.Free;
end;
end;
运行结果如下图,红色的矩形是计算出的变换后的坐标,与变换后的图像完全吻合:
g.DrawImage(Image, 20, 20, Image.Width, Image.Height); //用绝对坐标画原图
m.Translate(20, 20); // 坐标转换
m.Rotate(30);
m.Scale(1.8, 0.8);
m.Shear(0.3, 0.2);
g.SetTransform(m);
g.DrawImage(Image, 0, 0, Image.Width, Image.Height); //用相对坐标画图
其结果为下图,完全符合要求:
procedure ScaleAt(m: TGpMatrix; ScaleX, ScaleY, x, y: Single; Order: TMatrixOrder = moPrepend);
begin
if order = moAppend then
begin
x := -x;
y := -y;
end;
m.Translate(x, y, Order);
m.Scale(ScaleX, ScaleY, Order);
m.Translate(-x, -y, Order);
end;
procedure ShearAt(m: TGpMatrix; ShearX, ShearY, x, y: Single; Order: TMatrixOrder = moPrepend);
begin
if order = moAppend then
begin
x := -x;
y := -y;
end;
m.Translate(x, y, Order);
m.Shear(ShearX, ShearY, Order);
m.Translate(-x, -y, Order);
end;
procedure TMainForm.Button2Click(Sender: TObject);
var
Image: TGpImage;
g: TGpGraphics;
m: TGpMatrix;
begin
Image := TGpImage.Create('....Mediamsn.jpg');
g := TGpGraphics.Create(Handle, False);
m := TGpMatrix.Create;
try
g.DrawImage(Image, 20, 20, Image.Width, Image.Height);
m.RotateAt(30, GpPoint(20.0, 20.0), moAppend);
ScaleAt(m, 1.8, 0.8, 20, 20, moAppend);
ShearAt(m, 0.3, 0.2, 20, 20, moAppend);
g.SetTransform(m);
g.DrawImage(Image, 20, 20, Image.Width, Image.Height);
finally
Image.Free;
g.Free;
m.Free;
end;
end;
运行结果如下图,如果改为默认操作顺序,则和前面平移坐标后的运行结果完全一样:
说明,本文所用GDI+代码与网上流通的不兼容,如上面例子中的TMatrixElements,定义为:
TMatrixElements = packed record
case Integer of
0: (Elements: array[0..5] of Single);
1: (m11, m12, m21, m22, dx, dy: Single);
end;
而网上流通的则定义为一个数组:
TMatrixArray = array[0..5] of Single;
相关文章推荐
- GDI+ 在Delphi程序的应用 -- Matrix应用心得
- GDI+ 在Delphi程序的应用 -- 图像饱和度调整
- GDI+ 在Delphi程序的应用 -- ColorMatrix与图像灰度化
- GDI+ 在Delphi程序的应用 -- Photoshop浮雕效果
- GDI+在Delphi程序的应用:多帧(页)图像的分解与合成
- GDI+ 在Delphi程序的应用 -- FontCollection
- GDI+ 在Delphi程序的应用 -- ColorMatrix与图像亮度
- GDI+ 在Delphi程序的应用 -- 制作水印效果图片
- GDI+在Delphi程序的应用 – Photoshop色相/饱和度/明度功能
- GDI+ 在Delphi程序的应用 -- 调整图像亮度
- Delphi程序的应用GDI+制作水印效果图片
- GDI+ 在Delphi程序的应用 -- ColorMatrix与图像亮度
- GDI+ 在Delphi程序的应用 -- 可调节的文字阴影特效
- GDI+ 在Delphi程序的应用 -- 多帧(页)图像动画播放
- GDI+ 在Delphi程序的应用 -- ColorMatrix与图像灰度化
- GDI+ 在Delphi程序的应用 -- 图像的透明显示技巧
- GDI+ 在Delphi程序的应用 -- 图像饱和度调整
- GDI+ 在Delphi程序的应用 -- 线性调整图像亮度
- GDI+ 在Delphi程序的应用 -- 制作水印效果图片
- GDI+ 在Delphi程序的应用 -- 图像二值化