GDI+ 在Delphi、C++Builder程式的應用 — IStream

來源:互聯網
上載者:User

        GDI+的Image及衍生類別中涉及到IStream流,在Delphi和C++Builder中廣泛使用的TStream不能直接作為參數進行傳遞,VCL提供了一個TStreamAdapter類,用於把VCL流TStream轉換為IStream。TStreamAdapter的構造過程原型如下:

  constructor Create(Stream: TStream; Ownership: TStreamOwnership = soReference);

其中的TStreamOwnership枚舉類型有2個值:soReference和,如果是soOwned,TStream對象由TStreamAdapter釋放,否則由使用者自己處理。請看下面的用流建立Image的Delphi代碼:

var
  Stream: TMemoryStream;
  Adapter: TStreamAdapter;
  Image: TGpImage;
begin
  Stream := TMemoryStream.Create;
  Stream.LoadFromFile('Test.jpg');
  Adapter := TStreamAdapter.Create(Stream, soOwned);
  Image := TGpImage.Create(Adapter);
  try
    .....
  finally
    Image.Free;
  end;
end;

        代碼中,首先建立一個記憶體流,並從磁碟中裝入一個影像檔,然後用TStreamAdapter將這個流封裝起來,轉換為IStream,供建立TGpImage使用。注意,我在建立TStreamAdapter對象時使用了soOwned,這樣,由Adapter負責釋放Stream,否則,必須在Image.Free後面Stream.Free。但是TStreamAdapter對象Adapter為什麼沒有釋放代碼呢?因為TStreamAdapter是個介面實作類別,作為IStream傳遞給TGpImage.Create後,由系統自動跟蹤釋放,如果我們將它Free,會引起錯誤,如果非要顯式釋放它,必須用var I: IStream; I := Adapter; I := nil;的方法釋放,而且必須在Image.Free之前,因為在Image.Free的同時,Adapter也隨著IStream一起被釋放掉了。

        C++Builder與Delphi享有同一個VCL,也可按照Delphi的方法使用TStream,但是,由於C++Builder使用的GDI+程式碼封裝含在Gdiplus名字空間中,所有函數均採用inline方式,不是真正的函數調用方式,按照Delphi的方式,用TStreamAdapter將TStream轉換為IStream傳遞給Image的建構函式,將會出現運行時刻錯誤,因為如果Image的建構函式是真正的函數,在傳遞介面參數時,會對介面對象作隱式的引用調用,而inline函數一般只是直接將函數體內容插入調用函數的地方,沒有真正地傳遞參數的過程,所以,我們必須顯式的做一個引用調用。請看下面儲存Image到流的C++代碼片斷:

bool __fastcall GetImageEncoderClsid(AnsiString format, PGUID Clsid)
{
    UINT num, size = 0;
    DllExports::GdipGetImageEncodersSize(&num, &size);
    if (size == 0) return false;
    ImageCodecInfo *Info = (ImageCodecInfo*)DllExports::GdipAlloc(size);
    if(Info == NULL) return false;
    UINT i = 0;
    try
    {
        DllExports::GdipGetImageEncoders(num, size, Info);
        for (; i < num && CompareText(Info[i].MimeType, format) != 0; i ++);
        if (i < num)
            memcpy(Clsid, &Info[i].Clsid, sizeof(TGUID));
    }
    __finally
    {
        DllExports::GdipFree(Info);
    }
    return i < num? true : false;
}

void __fastcall TGdipBitmap::SaveToStream(Classes::TStream* Stream)
{
    TGUID Clsid;
    if (ImageFormat != "" && GetImageEncoderClsid(ImageFormat, &Clsid))
    {
        Gdiplus::Bitmap Image(Handle, Palette);
        TStreamAdapter *Adapter = new TStreamAdapter(Stream, soReference);
        Adapter->_AddRef();
        try
        {
            if (Image.Save((IStream*)*Adapter, &Clsid) != Ok)
                throw new Exception("Save Image fail");
        }
        __finally
        {
            Adapter->_Release();
        }
    }
    else
        TBitmap::SaveToStream(Stream);
}

代碼中,顯式的調用了TStreamAdapter的_AddRef()和_Release()函數,如果將這個調用省略,運行時會出現錯誤。

        由於本人是業餘愛好者,水平和功力有限,錯誤在所難免,歡迎來信指導:maozefa@hotmail.com

    補充(2008.9.7):從本文舉例中可以看到,在C++Builder的GDI+中 使用TStreamAdapter,必須顯式的調用其_AddRef()和_Release()函數,否則會出錯,而Delphi中使用TStreamAdapter,似乎不必顯式調用_AddRef和_Release,程式就工作的很好,但是如果多次使用TStreamAdapter的同一個對象,同樣也會出錯,也需要顯式調用_AddRef和_Release。而Delphi的TStreamAdapter的_AddRef和_Release不是public方法,只能轉換為IStream後調用。請看下面的代碼片斷:

 

var
  tmp: TGpBitmap;
  Adapter: TStreamAdapter;
  Stream: TStream;
  Clsid: TGUID;
begin
  Stream := TMemoryStream.Create;
  Adapter := TStreamAdapter.Create(Stream, soOwned);
  GetEncoderClsid('image/bmp', Clsid);
  IStream(Adapter)._AddRef;
  Image.Save(Adapter, Clsid);
  tmp := TGpBitmap.Create(Adapter);
  try
      ......

      ......
  finally
    tmp.Free;
    IStream(Adapter)._Release;
  end;

 

  代碼中的Image是函數中的一個TGpImage型別參數,代碼先把Image儲存到記憶體流,然後用這個流建立一個臨時TGpBitmap對象,便於進行操作,操作完畢,釋放臨時對象。為了適應GDI+的IStream介面,代碼中用TStreamAdapter進行了轉換,如果不顯式地調用_AddRef和_Release,這段代碼根本就運行不下去。

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.