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重新修订过,增加了一个旋转显示过程。

procedure BitmapFileToPNG(const Source, Dest: String); var Bitmap: TBitmap; PNG: TPNGObject; begin Bitmap := TBitmap.Create; PNG := TPNGObject.Create; {In case something goes wrong, free booth Bitmap and PNG} try Bitmap.LoadFromFile(Source); PNG.Assign(Bitmap); //Convert data into png PNG.SaveToFile(Dest); finally Bitmap.Free; PNG.Free; end end; Converting from PNG file to Windows bitmap file The above inverse. Loads a png and saves into a bitmap procedure PNGFileToBitmap(const Source, Dest: String); var Bitmap: TBitmap; PNG: TPNGObject; begin PNG := TPNGObject.Create; Bitmap := TBitmap.Create; {In case something goes wrong, free booth PNG and Bitmap} try PNG.LoadFromFile(Source); Bitmap.Assign(PNG); //Convert data into bitmap Bitmap.SaveToFile(Dest); finally PNG.Free; Bitmap.Free; end end; Converting from TImage to PNG file This method converts from TImage to PNG. It has full exception handling and allows converting from file formats other than TBitmap (since they allow assigning to a TBitmap) procedure TImageToPNG(Source: TImage; const Dest: String); var PNG: TPNGObject; BMP: TBitmap; begin PNG := TPNGObject.Create; {In case something goes wrong, free PNG} try //If the TImage contains a TBitmap, just assign from it if Source.Picture.Graphic is TBitmap then PNG.Assign(TBitmap(Source.Picture.Graphic)) //Convert bitmap data into png else begin //Otherwise try to assign first to a TBimap BMP := TBitmap.Create; try BMP.Assign(Source.Picture.Graphic); PNG.Assign(BMP); finally BMP.Free; end; end; //Save to PNG format PNG.SaveToFile(Dest); finally PNG.Free; end end;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值