Watch, Follow, &
Connect with Us

For forums, blogs and more please visit our
Developer Tools Community.


Welcome, Guest
Guest Settings
Help

Thread: Convert TGraphic to GDI+ Image



Permlink Replies: 13 - Last Post: Oct 13, 2015 9:33 AM Last Post By: Remy Lebeau (Te...
Martin Nijhoff

Posts: 75
Registered: 8/26/10
Convert TGraphic to GDI+ Image
Click to report abuse...   Click to reply to this thread Reply
  Posted: Oct 9, 2015 5:29 AM
Hi,

I have a TGraphic with some image in it (BMP, PNG, GIF, EMF, etc.) and need to convert this to a Gdiplus::Image.

I don't want to use a Gdiplus::Bitmap instead of Gdiplus::Image, because the TGraphic can also contain a vector image (WMF, EMF) and I need it to remain a vector image.

Gdiplus::Image apparently has only two public constructors; one to load from a file and one to load from an IStream.

How do I transfer the image in the TGraphic to a Gdiplus::Image?

--
Martin
Antonio Estevez

Posts: 665
Registered: 4/12/00
Re: Convert TGraphic to GDI+ Image
Click to report abuse...   Click to reply to this thread Reply
  Posted: Oct 9, 2015 11:48 AM   in response to: Martin Nijhoff in response to: Martin Nijhoff
El 9/10/15 a las 14:29, Martin Nijhoff escribió:
Hi,

I have a TGraphic with some image in it (BMP, PNG, GIF, EMF, etc.) and need to convert this to a Gdiplus::Image.

I don't want to use a Gdiplus::Bitmap instead of Gdiplus::Image, because the TGraphic can also contain a vector image (WMF, EMF) and I need it to remain a vector image.

Gdiplus::Image apparently has only two public constructors; one to load from a file and one to load from an IStream.

How do I transfer the image in the TGraphic to a Gdiplus::Image?

--
Martin

Gdiplus::Image can load WMF and EMF files.
If you need to load the image from a stream then you can use the
TAdapterStream class whitch is a bridge between TStream and IStream.

Martin Nijhoff

Posts: 75
Registered: 8/26/10
Re: Convert TGraphic to GDI+ Image
Click to report abuse...   Click to reply to this thread Reply
  Posted: Oct 12, 2015 12:54 AM   in response to: Antonio Estevez in response to: Antonio Estevez
Hi Antonio,

Thanks for your reply.

Antonio Estevez wrote:
If you need to load the image from a stream then you can use the
TAdapterStream class whitch is a bridge between TStream and IStream.

I couldn't find TAdapterStream in C++Builder XE6, but I did find TStreamAdapter.

Here's what I tried:

TGraphic* Graphic;    // Contains the image (raster or vector) to load in a Gdiplus::Image.
 
...
 
TMemoryStream* Stream = new TMemoryStream;
 
try
{
    Graphic->SaveToStream(Stream);
 
    Stream->Position = 0;
 
    TStreamAdapter* Adapter = new TStreamAdapter(Stream, soReference);
 
    try
    {
        Gdiplus::Image Img(Adapter->operator _di_IStream());
 
        ...
    }
    __finally
    {
        delete Adapter;
    }
}
__finally
{
    delete Stream;
}


The call to operator _di_IStream() throws an EInvalidPointer exception.

Any idea what I'm doing wrong?

--
Martin
Antonio Estevez

Posts: 665
Registered: 4/12/00
Re: Convert TGraphic to GDI+ Image
Click to report abuse...   Click to reply to this thread Reply
  Posted: Oct 12, 2015 4:57 AM   in response to: Martin Nijhoff in response to: Martin Nijhoff
El 12/10/15 a las 9:54, Martin Nijhoff escribió:
Hi Antonio,

Thanks for your reply.

Antonio Estevez wrote:
If you need to load the image from a stream then you can use the
TAdapterStream class whitch is a bridge between TStream and IStream.

I couldn't find TAdapterStream in C++Builder XE6, but I did find TStreamAdapter.

Sorry, that's what I meant.

Here's what I tried:

TGraphic* Graphic;    // Contains the image (raster or vector) to load in a Gdiplus::Image.
 
...
 
TMemoryStream* Stream = new TMemoryStream;
 
try
{
     Graphic->SaveToStream(Stream);
 
     Stream->Position = 0;
 
     TStreamAdapter* Adapter = new TStreamAdapter(Stream, soReference);
 
     try
     {
         Gdiplus::Image Img(Adapter->operator _di_IStream());
 
         ...
     }
     __finally
     {
         delete Adapter;
     }
}
__finally
{
     delete Stream;
}


The call to operator _di_IStream() throws an EInvalidPointer exception.

Any idea what I'm doing wrong?

Adapter is a reference counted object so it's freeded when its RefCount
value is 0 what happens when the image no longer needs the IStream
object passed in the the constructor.

try this

    TMemoryStream* Stream = new TMemoryStream;
    TStreamAdapter* Adapter = new TStreamAdapter(Stream, soOwned);
    try
    {
       Adapter->_AddRef();
 
       Graphic->SaveToStream(Stream);
       Stream->Position = 0;
 
       Gdiplus::Image Img(Adapter->operator _di_IStream());
 
       ...
     }
     __finally
     {
        Adapter->_Release();
     }
 
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Convert TGraphic to GDI+ Image
Click to report abuse...   Click to reply to this thread Reply
  Posted: Oct 12, 2015 11:53 AM   in response to: Antonio Estevez in response to: Antonio Estevez
Antonio wrote:

Adapter is a reference counted object so it's freeded when its
RefCount value is 0 what happens when the image no longer needs
the IStream object passed in the the constructor.

You should be using a _di_IStream variable instead and let it handle the
reference count for you:

TMemoryStream* Stream = new TMemoryStream;
_di_IStream Adapter(new TStreamAdapter(Stream, soOwned));
 
Graphic->SaveToStream(Stream);
Stream->Position = 0;
Gdiplus::Image Img(Adapter);
...


--
Remy Lebeau (TeamB)
Antonio Estevez

Posts: 665
Registered: 4/12/00
Re: Convert TGraphic to GDI+ Image
Click to report abuse...   Click to reply to this thread Reply
  Posted: Oct 12, 2015 12:14 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
El 12/10/15 a las 20:53, Remy Lebeau (TeamB) escribió:
Antonio wrote:

Adapter is a reference counted object so it's freeded when its
RefCount value is 0 what happens when the image no longer needs
the IStream object passed in the the constructor.

You should be using a _di_IStream variable instead and let it handle the
reference count for you:

TMemoryStream* Stream = new TMemoryStream;
_di_IStream Adapter(new TStreamAdapter(Stream, soOwned));
 
Graphic->SaveToStream(Stream);
Stream->Position = 0;
Gdiplus::Image Img(Adapter);
...

I think the declaration of Adapter should be:

_di_IStream Adapter(new TStreamAdapter(Stream, soOwned)->operator _di_IStream());


or

 _di_IStream Adapter(*(new TStreamAdapter(Stream, soOwned)));


Edited by: Antonio Estevez on Oct 12, 2015 12:29 PM
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Convert TGraphic to GDI+ Image [Edit]
Click to report abuse...   Click to reply to this thread Reply
  Posted: Oct 12, 2015 12:49 PM   in response to: Antonio Estevez in response to: Antonio Estevez
Antonio wrote:

I think the declaration of Adapter should be:

Don't invoke operators directly, let the compiler do it for you, eg:

_di_IStream Adapter = *(new TStreamAdapter(Stream, soOwned));


Or:

_di_IStream Adapter(*(new TStreamAdapter(Stream, soOwned)));


--
Remy Lebeau (TeamB)
Martin Nijhoff

Posts: 75
Registered: 8/26/10
Re: Convert TGraphic to GDI+ Image [Edit]
Click to report abuse...   Click to reply to this thread Reply
  Posted: Oct 13, 2015 12:57 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Thanks for your replies, Remy.

Changing 'soReference' to 'soOwned' causes TStreamAdapter to destroy the associated TMemoryStream object in it's destructor, right?

--
Martin
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Convert TGraphic to GDI+ Image [Edit]
Click to report abuse...   Click to reply to this thread Reply
  Posted: Oct 13, 2015 9:33 AM   in response to: Martin Nijhoff in response to: Martin Nijhoff
Martin wrote:

Changing 'soReference' to 'soOwned' causes TStreamAdapter to destroy
the associated TMemoryStream object in it's destructor, right?

Yes.

--
Remy Lebeau (TeamB)
Martin Nijhoff

Posts: 75
Registered: 8/26/10
Re: Convert TGraphic to GDI+ Image
Click to report abuse...   Click to reply to this thread Reply
  Posted: Oct 13, 2015 12:50 AM   in response to: Antonio Estevez in response to: Antonio Estevez
Hi Antonio,

Thanks for your reply.

Antonio Estevez wrote:
Adapter is a reference counted object so it's freeded when its RefCount
value is 0 what happens when the image no longer needs the IStream
object passed in the the constructor.

I couldn't find anything in the documentation of Gdiplus::Image about who freed the IStream object.

Since all COM objects are reference counted, I probably should have known better...

--
Martin
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Convert TGraphic to GDI+ Image
Click to report abuse...   Click to reply to this thread Reply
  Posted: Oct 13, 2015 9:32 AM   in response to: Martin Nijhoff in response to: Martin Nijhoff
Martin wrote:

I couldn't find anything in the documentation of Gdiplus::Image
about who freed the IStream object.

IStream is a COM interface. Standard COM interface reference counting rules
apply. Gdiplus::Image() does not free the IStream. The real problem is
that your code was misusing TStreamAdapter, causing its reference count to
rise to 1 and fall to 0 when the temp _di_IStream is created and then goes
out of scope after the Image constructor exits, thus freeing the TStreamAdapter
object before the 'delete' statement is called:

TMemoryStream* Stream = new TMemoryStream;
try
{
    Graphic->SaveToStream(Stream);
    Stream->Position = 0;
 
    TStreamAdapter* Adapter = new TStreamAdapter(Stream, soReference); // 
<-- refCount==0!
    try
    {
        Gdiplus::Image Img(Adapter->operator _di_IStream()); <-- refCount==1 
when _di_IStream is created, then refCount==0 when _di_IStream is freed!
        ...
    }
    __finally
    {
        delete Adapter; // <-- crash because Adapter has already been freed!
    }
}
__finally
{
    delete Stream;
}


--
Remy Lebeau (TeamB)
Martin Nijhoff

Posts: 75
Registered: 8/26/10
Re: Convert TGraphic to GDI+ Image
Click to report abuse...   Click to reply to this thread Reply
  Posted: Oct 12, 2015 1:55 AM   in response to: Antonio Estevez in response to: Antonio Estevez
I also tried replacing

Gdiplus::Image Img(Adapter->operator _di_IStream());


with

Gdiplus::Image Img(interface_cast<IStream>(Adapter));


but then the EInvalidPointer exception is thrown when Adapter is destroyed.

--
Martin
Antonio Estevez

Posts: 665
Registered: 4/12/00
Re: Convert TGraphic to GDI+ Image
Click to report abuse...   Click to reply to this thread Reply
  Posted: Oct 12, 2015 11:52 AM   in response to: Martin Nijhoff in response to: Martin Nijhoff
El 12/10/15 a las 10:55, Martin Nijhoff escribió:
I also tried replacing

Gdiplus::Image Img(Adapter->operator _di_IStream());


with

Gdiplus::Image Img(interface_cast<IStream>(Adapter));


but then the EInvalidPointer exception is thrown when Adapter is destroyed.

The Adapter object is freeded when the Img variable goes out of scope.
When you call "delete Adapter", the object is already destroyed.

Martin Nijhoff

Posts: 75
Registered: 8/26/10
Re: Convert TGraphic to GDI+ Image
Click to report abuse...   Click to reply to this thread Reply
  Posted: Oct 13, 2015 12:26 AM   in response to: Antonio Estevez in response to: Antonio Estevez
Hi Antonio,

Antonio Estevez wrote:
The Adapter object is freeded when the Img variable goes out of scope.
When you call "delete Adapter", the object is already destroyed.

That explains the EInvalidPointer exception.

--
Martin
Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02