`
sogotobj
  • 浏览: 653856 次
  • 性别: Icon_minigender_2
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

GDI+ 在Delphi、C++Builder程序的应用 -- IStream

阅读更多

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__fastcallGetImageEncoderClsid(AnsiStringformat,PGUIDClsid)
{
UINTnum,size
=0;
DllExports::GdipGetImageEncodersSize(
&num,&size);
if(size==0)returnfalse;
ImageCodecInfo
*Info=(ImageCodecInfo*)DllExports::GdipAlloc(size);
if(Info==NULL)returnfalse;
UINTi
=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);
}
returni<num?true:false;
}

void__fastcallTGdipBitmap::SaveToStream(Classes::TStream*Stream)
{
TGUIDClsid;
if(ImageFormat!=""&&GetImageEncoderClsid(ImageFormat,&Clsid))
{
Gdiplus::BitmapImage(Handle,Palette);
TStreamAdapter
*Adapter=newTStreamAdapter(Stream,soReference);
Adapter
->_AddRef();
try
{
if(Image.Save((IStream*)*Adapter,&Clsid)!=Ok)
thrownewException("SaveImagefail");
}
__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,这段代码根本就运行不下去。

分享到:
评论

相关推荐

    VB 经典GDI+模块

    在VB6(Visual Basic 6)环境中,GDI+(Graphics Device Interface Plus)是一个强大的图形绘制和处理库,它极大地扩展了VB6的图形能力。本经典GDI+模块是VB6开发者的一个宝贵资源,提供了丰富的图形操作功能,如...

    VB6 GDI+入门教程(最新版)

    2. **设备无关性**:GDI+允许开发者编写设备无关的应用程序,这意味着开发者无需关心特定显示设备的细节,只需调用GDI+提供的API即可完成绘图任务。 3. **丰富的图形处理能力**:GDI+支持矢量图形、位图、路径绘制等...

    GDI+ 函数封装 IStream.rar

    在IT领域,GDI+(Graphics Device Interface Plus)是一种图形绘制和处理的API,由Microsoft开发,用于Windows应用程序。GDI+提供了丰富的图形绘制功能,包括2D图形、图像处理和文字渲染。在这个名为"IStream.rar"的...

    VC GDI+ 窗口截图内存BMP转JPG,压缩、JPG再转IStream流,IStream流再转 BYTE

    VC GDI+ 窗口截图内存BMP转JPG,压缩、JPG再转IStream流,IStream流再转 BYTE 上体见 http://blog.csdn.net/q610098308/article/details/78181933

    VB6 gdi+图形处理封装mGdip.bas

    GDI+内存创建bitmap,并将其保存为各种图像。以及将其与byte()、IStream、StdPicture、Bitmap的转换

    Visual C++实践与提高-COM和COM+篇『PDF』

    5.6.1 COM在多层Web应用程序中的重要作用 5.6.2 在客户端使用ActiveX控件 5.6.3 在服务器端使用代码组件 小结 第6章 用VC 4开发COM应用 6.1 VC对COM的支持 6.1.1 类库支持:MFC和ATL 6.1.2 比较MFC和ATL 6.2 MFC对...

    C++程序设计报告--复数计算器[文].pdf

    【C++程序设计报告——复数计算器】 在C++编程中,复数计算器是一个常见的练习项目,用于提高程序员对类的封装、运算符重载...通过这个项目,程序员不仅可以掌握C++的基础知识,还能提升在实际编程情境中的应用能力。

    通讯录+++++++++c++代码

    在C++中,构建这样的系统涉及到数据结构、文件操作和面向对象编程等核心概念。 首先,通讯录系统的核心是存储联系人信息的数据结构。我们可以选择使用类(Class)来设计这个数据结构,例如创建一个名为`Contact`的...

    IStream.zip IStream.tlb

    在IT领域,`IStream`接口是COM(Component Object Model)接口之一,它定义了一种通用的流操作接口,允许程序读写数据流,不论是内存中的数据还是存储设备上的数据。`IStream`接口通常用于处理文件、网络数据或者...

    C++操作符优先级、可重载型

    - C++的输入输出操作通常涉及`iostream`库,`istream`和`ostream`是处理输入和输出流的基础类,`iostream`是它们的派生类,支持双向I/O。 - 输入操作符`&gt;&gt;`(析取操作符)从输入流中抽取数据,输出操作符`(插入...

    数据结构(C++描述)--复数类

    这不仅加深了对C++语言的理解,也强化了数据结构和算法的应用能力,特别是在处理自定义类型时。通过实践这样的项目,开发者可以更好地掌握面向对象设计原则,提高编程技能,这对于任何IT职业生涯都是至关重要的。

    【最新】C++ http 服务端,接收来自http post form_data文件(图片)源码

    在IT领域,C++是一种强大的编程语言,常用于构建高性能的应用程序,包括网络服务器。本文将深入探讨如何在C++中实现一个HTTP服务端,尤其是处理HTTP POST请求,特别是接收form_data类型的文件,如图片。这在现代Web...

    c++程序 文件的应用

    根据提供的文件信息,我们可以归纳出...以上是基于给定文件的 C++ 程序设计中涉及的关键知识点。通过对这些知识点的学习和理解,可以更好地掌握如何在 C++ 中使用文件进行类的设计和实现,以及如何进行有效的代码组织。

    C++程序设计 谭浩强 电子版,文字版非扫描

    - **兼容性**: C++ 完全兼容 C 语言,这意味着大多数 C 语言编写的程序可以在不修改的情况下直接在 C++ 环境下运行。 - **面向对象**: C++ 支持面向对象编程(OOP),包括封装、继承和多态等特性,使得大型软件项目...

    c++特殊运算符重载---流运算符重载(csdn)————程序.pdf

    在C++编程语言中,运算符重载是一种强大的特性,允许程序员为自定义类型赋予特定的行为,以便它们能像内置类型一样使用。本篇将详细探讨流运算符重载,也就是`和`&gt;&gt;`这两个运算符在处理输入输出流时如何被重载。 ...

    C++期末复习--1.练习题-选择.pdf

    在C++编程语言中,面向对象程序设计是核心概念之一。面向对象编程(OOP)是一种编程范式,它基于“对象”的概念,这些对象包含了数据(即属性或成员变量)和操作这些数据的方法(函数)。以下是一些关于C++ OOP的...

    用IStream读取保存图像

    总的来说,`IStream`和`IStorage`是Windows编程中处理数据流和存储的强大工具,它们提供了灵活的方式来读取和保存图像,以及其他类型的数据,适合在各种复杂的应用场景中使用。通过熟练掌握这两个接口,开发者能够...

Global site tag (gtag.js) - Google Analytics