zoukankan      html  css  js  c++  java
  • 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位图的相互转换。

  • 相关阅读:
    解决命令行乱码问题(中文乱码)
    Outlook 修改归档文件顶层目录名
    (职员)2015-11-11 星期三 日志
    职员)2015-11-10 星期二 日志
    职员)2015-11-09 星期一 日志
    (职员)2015-11-05 星期四 日志
    (职员)2015-11-04 星期三 日志
    (职员)2015-11-03 星期二 日志
    (职员)2015-11-02 星期一 日志
    (职员)2015-10-31 星期六 周志
  • 原文地址:https://www.cnblogs.com/blogpro/p/11426640.html
Copyright © 2011-2022 走看看