The image and derived classes of GDI + involve istream streams. tstream widely used in Delphi and C ++ Builder cannot be passed directly as parameters. VCL provides a tstreamadapter class, it is used to convert VCL stream tstream to istream. The following is a prototype of the tstreamadapter construction process:
Constructor create (Stream: tstream; Ownership: tstreamownership = soreference );
The tstreamownership Enumeration type has two values: soreference and. If it is soowned, The tstream object is released by the tstreamadapter. Otherwise, the user will process the tstream object. See the following Delphi code for creating an image using a stream:
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;
In the code, first create a memory stream and install an image file from the disk. Then, use tstreamadapter to encapsulate the stream and convert it to istream for tgpimage creation. Note: I used soowned when creating a tstreamadapter object. In this way, the adapter is responsible for releasing stream. Otherwise, it must be followed by stream. Free after image. Free. But why didn't the tstreamadapter Object Adapter release code? Because tstreamadapter is an interface implementation class, it is passed to tgpimage as istream. after create, the system automatically traces and releases it. If we release it free, it will cause an error. If we want to release it explicitly, we must use VaR I: istream; I: = adapter; I: = nil;, and must be in the image. before free, because in the image. the adapter is also released along with istream.
C ++ builder and Delphi have the same VCL and can also use tstream according to the Delphi method. However, since the GDI + code used by C ++ builder is included in the gdiplus namespace, all functions use the inline method instead of the real function call method. According to the Delphi method, tstreamadapter is used to convert tstream to the istream passed to the image constructor, and a runtime error will occur, because if the image constructor is a real function, the interface object will be implicitly referenced and called when the interface parameters are passed, the inline function only inserts the content of the function body directly into the place where the function is called, without actually passing the parameter process. Therefore, we must explicitly make a reference call. See the C ++ code snippet that saves the image to the stream below:
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 );
}
In the code, the _ addref () and _ release () Functions of the tstreamadapter are explicitly called. If this call is omitted, an error occurs during running.
Because I am a hobbyist, the level and skill is limited, the error is inevitable, welcome to the letter to guide: maozefa@hotmail.com
Supplement (2008.9.7): From the example in this article, we can see that when tstreamadapter is used in the C ++ builder's GDI +, it must explicitly call its _ addref () and _ release () function. Otherwise, an error occurs. If you use tstreamadapter in Delphi, you do not need to explicitly call _ addref and _ release. The program works well, but if you use the same object of tstreamadapter multiple times, an error also occurs. You also need to explicitly call _ addref and _ release. The _ addref and _ release of the tstreamadapter of Delphi are not public methods and can only be converted to istream and called. See the following code snippet:
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;
The image in the Code is a tgpimage parameter in the function. The code first saves the image to the memory stream, and then uses the stream to create a temporary tgpbitmap object, which facilitates operations and completes operations, release a temporary object. To adapt to the istream interface of GDI +, tstreamadapter is used in the Code for conversion. If _ addref and _ release are not explicitly called, this code cannot run at all.