GDI+ 在Delphi程序的应用 -- GDI+图像与GDI位图的相互转换

        Delphi的TBitmap封装了Windows的GDI位图,因此,TBitmap只支持bmp格式的图像,但是在Delphi应用程序中,常常会遇到图形格式的转换,如将Delphi位图TBitmap的图像转换为其它格式保存,或者将其它图像格式转换为TBitmap等。这时候,我们往往借助一些第三方组件或代码,Delphi自带的TJPEG.pas就是jpeg格式图像转换的第三方代码单元。

        其实,利用GDI+的TGpBitmap可以很方便的和TBitmap实现一些图像格式的相互转换,下面的代码把一个PNG格式图像转换为Delphi窗口界面上的TImage图像进行显示:

var
  bmp: TGpBitmap;
begin
//   bmp := TGpBitmap.Create('D:del_gdiplusDemosMediamsn1.gif');
//   bmp := TGpBitmap.Create('D:del_gdiplusDemosMediaMultiFrame.tif');
  bmp : =  TGpBitmap.Create( ' D:del_gdiplusDemosMediaclimber.png');
  Image1.Picture.Bitmap.Handle : =  bmp.GetHBITMAP( 0 );
  bmp.Free;
end;

        代码中首先用GDI+的TGpBitmap从磁盘文件装入png格式图像,然后直接取GDI+位图的图像句柄赋给TBitmap的Handle属性,完成转换。代码中的TGpBitmap.GetHBITMAP方法中有个图像转换时背景颜色参数,对于非透明图像,这个参数是忽略的,由于Delphi的TBitmap不支持透明图像,所以,即使是有透明部分的PNG图像,该参数也不起什么作用,无论你设置什么颜色,透明背景总是黑色。只要是GDI+支持的图像格式,都可以很方便的转换为TBitmap,代码中被注释的代码分别为GIF和TIFF图像格式的转换。

        同样,我们也可以把TBitmap的图像利用GDI+转换为GDI+所支持的格式:

var
  bmp: TGpBitmap;
  g: TGpGraphics;
  Clsid: TGUID;
begin
  
//  利用TImage.Picture.Bitmap的图像句柄Handle和调色板属性Palette建立一个GDI+位图
  with Image1.Picture.Bitmap  do
  bmp :
=  TGpBitmap.Create(Handle, Palette);
  
//  转换为PNG格式保存
   if  GetEncoderClsid( ' image/png ' , Clsid) then
    bmp.Save(
' d:gdi_test.png ' , Clsid);
  
//   显示在窗口
  g : =  TGpGraphics.Create(Handle, False);
  g.DrawImage(bmp, 
0 0 );
  bmp.Free;
  g.Free;
end;

        上面例子把TImage控件的图像转换成了png格式图像,注意,如果是第三方代码转换装入的TImage图像,有可能不支持上面的转换,如利用TJPEGImage装入的图像,因TJPEGImage是从TGraphic继承而来的,没有提供HBITMAP类型的Handle属性,所以转换不会成功。

        也可利用GDI+对TBitmap位图进行压缩保存,下面的例子把TImage的图像压缩50%保存为jpeg格式图像:

var
  bmp: TGpBitmap;
  g: TGpGraphics;
  Clsid: TGUID;
  Parameters: TEncoderParameters;
  Quality: Integer;
  GUID: TGUID;
begin
  with Image1.Picture.Bitmap 
do
  bmp :
=  TGpBitmap.Create(Handle, Palette);
  
if  GetEncoderClsid( ' image/jpeg ' , Clsid) then
  begin
    Parameters.Count :
=   1 ;
    Parameters.Parameter[
0 ].Guid : =  EncoderQuality;
    Parameters.Parameter[
0 ].ValueType : =  EncoderParameterValueTypeLong;
    Parameters.Parameter[
0 ].NumberOfValues : =   1 ;
    Quality :
=   50 ;                              //  图片质量50
    Parameters.Parameter[ 0 ].Value : =  @Quality;
    bmp.Save(
' d:gdi_test.jpg ' , Clsid, @Parameters);
  end;
  g :
=  TGpGraphics.Create(Handle, False);
  g.DrawImage(bmp, 
0 0 );
  bmp.Free;
  g.Free;
end;

        目前的GDI+版本只支持jpeg图像格式的压缩,例子中的图像编码器压缩参数设置可以参见我的文章《GDI+ 在Delphi程序的应用 -- 多帧(页)图像的分解与合成》,里面有较详细的解说。

        在Delphi程序中,可以用TOpenPictureDialog和TSavePictureDialog对话框实现图像的存取,同样,没有第三方代码支持,也只有有限几种图像格式供选择,我们可以利用GDI+写个简单的转换代码单元,在程序代码单元的uses部分加入该单元,就可实现较多的图像格式选项。

unit GdipBitmap;

interface

uses
  GdipTypes, Gdiplus, Windows, SysUtils, Classes, Graphics;

type
  TGdipBitmap 
=   class (TBitmap)
  
public
    procedure LoadFromStream(Stream: TStream); 
override ;
    procedure SaveToFile(
const  Filename:  string );  override ;
    procedure SaveToStream(Stream: TStream); 
override ;
  end;

implementation

{ TGdipBitmap }

var
  ImageFormat: 
string   =   '' ;

procedure SetImageFormat(
const  Filename:  string );
begin
  ImageFormat :
=  ExtractFileExt(Filename);
  
if  ImageFormat  <>   ''  then
  begin
    Delete(ImageFormat, 
1 1 );
    
if  CompareText(ImageFormat,  ' jpg ' =   0  then
      ImageFormat :
=   ' jpeg '
    
else   if  CompareText(ImageFormat,  ' tif ' =   0  then
      ImageFormat :
=   ' tiff ' ;
  end 
else  ImageFormat : =   ' bmp ' ;
  ImageFormat :
=   ' image/ '   +  ImageFormat;
end;

procedure TGdipBitmap.LoadFromStream(Stream: TStream);
var
  Adaper: TStreamAdapter;
  tmp: TGpBitmap;
begin
  Adaper :
=  TStreamAdapter.Create(Stream, soReference);
  tmp :
=  TGpBitmap.Create(Adaper);
  
try
    Handle :
=  tmp.GetHBITMAP( 0 );
  
finally
    tmp.Free;
  end;
end;

procedure TGdipBitmap.SaveToFile(
const  Filename:  string );
begin
  SetImageFormat(Filename);
  inherited SaveToFile(Filename);
  ImageFormat :
=   '' ;
end;

procedure TGdipBitmap.SaveToStream(Stream: TStream);
var
  tmp: TGpBitmap;
  Adaper: TStreamAdapter;
  Clsid: TGUID;
begin
  
if  (ImageFormat  <>   '' ) and (GetEncoderClsid(ImageFormat, Clsid)) then
  begin
    tmp :
=  TGpBitmap.Create(Handle, Palette);
    
try
      Adaper :
=  TStreamAdapter.Create(Stream, soReference);
      tmp.Save(Adaper, Clsid);
    
finally
      tmp.Free;
    end;
  end 
else
    inherited SaveToStream(Stream);
end;

initialization
//   TPicture.RegisterFileFormat('bmp', 'BMP File', TGdipBitmap);
  TPicture.RegisterFileFormat( ' Exif ' ' TIFF File ' , TGdipBitmap);
  TPicture.RegisterFileFormat(
' tiff ' ' TIFF File ' , TGdipBitmap);
  TPicture.RegisterFileFormat(
' tif ' ' TIFF File ' , TGdipBitmap);
  TPicture.RegisterFileFormat(
' png ' ' PNG File ' , TGdipBitmap);
  TPicture.RegisterFileFormat(
' gif ' ' GIF File ' , TGdipBitmap);
  TPicture.RegisterFileFormat(
' jpeg ' ' JPEG File ' , TGdipBitmap);
  TPicture.RegisterFileFormat(
' jpg ' ' JPG File ' , TGdipBitmap);
finalization
  TPicture.UnregisterGraphicClass(TGdipBitmap);
end.

        上面就是我写的一个简单GDI+图像转换单元,在单元的initialization部分,向Delphi注册了几种图像格式的存取类TGdipBitmap,其中bmp格式注册代码被注销了,还是用缺省的TBitmap打开为好。代码中用的就是前面所说的转换原理,不过,用这种方式转换的TBitmap图像格式都是32位的,可以在TGdipBitmap.LoadFromStream方法的Handle := tmp.GetHBITMAP(0);语句后面加入代码进行图像像素格式的转换:

    Handle : =  tmp.GetHBITMAP( 0 );
    
case  tmp.PixelFormat of
      pf1bppIndexed: PixelFormat :
=  pf1bit;
      pf4bppIndexed: PixelFormat :
=  pf4bit;
      pf8bppIndexed: PixelFormat :
=  pf8bit;
      pf16bppRGB565, pf16bppRGB555, pf16bppARGB1555: PixelFormat :
=  pf16bit;
      pf24bppRGB: PixelFormat :
=  pf24bit;
      pf32bppRGB, pf32bppARGB: PixelFormat :
=  pf32bit;
      
else  PixelFormat : =  pfCustom;
    end;

        下面的代码演示了使用该单元后利用对话框打开图像,应提醒的是,在Delphi的IDE调试运行状态下,当选择png图像格式时,会弹出CPU调试窗口,这不知是Gdiplus.dll的BUG,还是Delphi的问题但是不影响程序的正确运行,脱离IDE环境,一切正常:

uses Gdiplus, GdipBitmap;
.....
......
procedure TForm1.Button5Click(Sender: TObject);
var
  bmp: TGpBitmap;
  g: TGpGraphics;
begin
  
if  OpenPictureDialog1.Execute then
  begin
    bmp :
=  TGpBitmap.Create(OpenPictureDialog1.FileName);
    g :
=  TGpGraphics.Create(Handle, False);
    g.DrawImage(bmp, 
0 0 );
    bmp.Free;
    g.Free;
  end;
end;

        其实,如果你愿意,可以把该单元通过Delphi的Component->Install Component菜单,建立一个新的包或者把单元加到缺省的包中,确定安装后,可以在设计期直接用TImage的Picture属性进行多种图像格式文件的选择。

        上面的例子代码中使用的GDI+单元是我自己改写的,如果用其它版本的GDI+单元,应作适当的修改,我的GDI+单元下载地址可以在文章《GDI+ for VCL基础 -- GDI+ 与 VCL》中找到,并注意文章最后的几处修改。

        顺便说一句,即使不使用Delphi的朋友,也可用文章中的转换方法,利用GDI的HBITMAP和HPALETTE,实现GDI+图像与GDI位图的相互转换。

        如有错误或者建议、指导,请留言或者来信:maozefa@hotmail.com

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值