GDI+ 在Delphi程式的應用 — GDI+映像與GDI位元影像的相互轉換

來源:互聯網
上載者:User

        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

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.