Delphi图像处理 -- 图像显示

Delphi的TCanvas以及派生类提供了显示TGraphic图像的方法Draw,其实这个方法本身并没有显示图像的功能,只是反过来调用了一下TGraphic的Draw方法。TGraphic本身是个抽象类,其Draw方法也是个纯虚方法,所以TGraphic的所有派生类必须提供一个具体的Draw方法。TGraphic的主要派生类TBitmap也有一个Draw方法,但是该方法只能利用其Transparent属性显示透明背景图像,而不能正确显示带Alpha通道的32位图像,即使Delphi2009以上版本的TGraphic增添了一个SupportsPartialTransparency属性,但TBitmap也还是没法直接显示ARGB像素格式的图像,因为TBitmap调用的是Windows API的AlphaBlend函数,该函数似乎只能显示PARGB格式像素的图像,而且TGraphic的SupportsPartialTransparency属性还是只读性质的。

GDI+的TGpGraphics的系列DrawImage方法画ARGB32位图像倒是很好的,但如果图像真的含Alpha信息时,显示的速度却是较慢,大家可以用2张较大的图片试一下,一张含Alpha,一张不含Alpha,对比一下就知道了。

因为本系列图像处理过程中有多个方法会使Alpha分量发生变化,即使该图像原来不含Alpha信息,所以有必要写图像显示过程。而且,如果在应用程序中只是需要显示处理过的图像,就不必再将TImageData类型转换为TGraphic或者TGpBitmap了,直接使用本文的显示过程无疑是很方便的。

本文的图像显示过程是利用图像合成过程(见《Delphi图像处理 -- 图像合成》)、图像缩放过程《Delphi图像处理 -- 图像缩放》、《Delphi图像处理 -- 图像旋转》及几个Windows API来完成的,下面是具体代码:

过程定义: // 画图像数据到Canvas,Alpha为图像的不透明度(0 - 1)。 procedure DrawImage(Canvas: TCanvas; x, y: Integer; const Data: TImageData; Alpha: Single = 1.0); overload; // 拉伸画图像数据到Canvas,Alpha为图像的不透明度(0 - 1),IpMode为插值方式 procedure DrawImage(Canvas: TCanvas; x, y, Width, Height: Integer; const Data: TImageData; Alpha: Single = 1.0; IpMode: TInterpolateMode = imDefault); overload; procedure DrawImage(Canvas: TCanvas; LayoutRect: TRect; const Data: TImageData; Alpha: Single = 1.0; IpMode: TInterpolateMode = imDefault); overload; {$IF RTLVersion >= 17.00}inline;{$IFEND} // 旋转画图像数据到Canvas,其他参数参见ImageRotate procedure DrawImage(Canvas: TCanvas; x, y: Integer; const Data: TImageData; Angle: Single; Alpha: Single = 1.0; IpMode: TInterpolateMode = imDefault); overload; procedure DrawImage(Canvas: TCanvas; LayoutRect: TGpRect; Data: TImageData; Alpha: Single = 1.0; IpMode: TInterpolateMode = imDefault); overload; 代码实现: procedure DrawImage(Canvas: TCanvas; x, y: Integer; const Data: TImageData; Alpha: Single); var pbi: TBitmapInfo; r: TRect; dst, src, tmp: TImageData; begin if ImageEmpty(Data) then Exit; r := Canvas.ClipRect; if IsRectEmpty(r) then Exit; Dec(x, r.Left); Dec(y, r.Top); if x > 0 then begin Inc(r.Left, x); x := 0; end; if y > 0 then begin Inc(r.Top, y); y := 0; end; tmp := GetImageData(r.Right - r.Left, r.Bottom - r.Top, Data.Stride, Data.Scan0); dst.Scan0 := nil; dst := GetSubData(tmp, x, y, data.Width, data.Height); if dst.Scan0 = nil then Exit; if x < 0 then x := -x; if y < 0 then y := -y; src := GetSubData(Data, x, y, dst.Width, dst.Height); dst := NewImageData(dst.Width, dst.Height); try dst.InvertLine := True; pbi.bmiHeader := GetBitmapInfoHeader(dst); GetDCImageData(Canvas.Handle, r.Left, r.Top, dst, pbi); DoSysthesis(dst, src, Round(Alpha * 256)); BitBltImageData(Canvas.Handle, r.Left, r.Top, dst, pbi); finally FreeImageData(dst); end; end; procedure DrawImage(Canvas: TCanvas; x, y: Integer; const Data: TImageData; Angle, Alpha: Single; IpMode: TInterpolateMode); var pbi: TBitmapInfo; dst: TImageData; dr, cr: TRect; begin if ImageEmpty(Data) then Exit; dr.BottomRight := TPoint(GetRotateSize(Data.Width, Data.Height, Angle)); dr.Left := x; dr.Top := y; if not GetDCClipBox(Canvas.Handle, dr, cr) then Exit; dst := NewImageData(cr.Right, cr.Bottom); try dst.InvertLine := True; pbi.bmiHeader := GetBitmapInfoHeader(dst); GetDCImageData(Canvas.Handle, cr.Left, cr.Top, dst, pbi); ImageRotate(dst, dr.Left, dr.Top, Data, Angle, Alpha, IpMode); BitBltImageData(Canvas.Handle, cr.Left, cr.Top, dst, pbi); finally FreeImageData(dst); end; end; procedure DrawImage(Canvas: TCanvas; x, y, Width, Height: Integer; const Data: TImageData; Alpha: Single; IpMode: TInterpolateMode); var pbi: TBitmapInfo; dst, src: TImageData; dr, cr: TRect; ScaleX, ScaleY: Single; begin dr := Rect(x, y, Width, Height); if not GetDCClipBox(Canvas.Handle, dr, cr) then Exit; ScaleX := Width / Data.Width; ScaleY := Height / Data.Height; if dr.Left < 0 then dr.Left := -Round(dr.Left / ScaleX); if dr.Top < 0 then dr.Top := -Round(dr.Top / ScaleY); src := GetSubImageData(Data, dr.Left, dr.Top, GetInfinity(cr.Right / ScaleX), GetInfinity(cr.Bottom / ScaleY)); if src.Scan0 = nil then Exit; dst := NewImageData(cr.Right, cr.Bottom); try dst.InvertLine := True; pbi.bmiHeader := GetBitmapInfoHeader(dst); GetDCImageData(Canvas.Handle, cr.Left, cr.Top, dst, pbi); DoScale(dst, src, Alpha, IpMode); BitBltImageData(Canvas.Handle, cr.Left, cr.Top, dst, pbi); finally FreeImageData(dst); end; end; procedure DrawImage(Canvas: TCanvas; LayoutRect: TRect; const Data: TImageData; Alpha: Single; IpMode: TInterpolateMode); begin DrawImage(Canvas, LayoutRect.Left, LayoutRect.Top, LayoutRect.Right - LayoutRect.Left, LayoutRect.Bottom - LayoutRect.Top, Data, Alpha, IpMode); end; procedure DrawImage(Canvas: TCanvas; LayoutRect: TGpRect; Data: TImageData; Alpha: Single; IpMode: TInterpolateMode); begin DrawImage(Canvas, LayoutRect.X, LayoutRect.Y, LayoutRect.Width, LayoutRect.Height, Data, Alpha, IpMode); end;

文章中使用GDI+版本下载地址和说明见《GDI+ for VCL基础 -- GDI+ 与 VCL》。

文章中所用数据类型及一些过程见《Delphi图像处理 -- 数据类型及内部过程》和《Delphi图像处理 -- 图像像素结构与图像数据转换》。

尽管我十分努力,但水平有限,错误在所难免,欢迎指正和指导。邮箱地址:

maozefa@hotmail.com

说明:本文代码于2010.5.20重新修订过,增加了一个旋转显示过程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值