Thread: GDIPLUS::Image: how save it on a file in stream way?

  1. #1
    Registered User
    Join Date
    Aug 2013
    Posts
    451

    GDIPLUS::Image: how save it on a file in stream way?

    i did these code for overloading << and >> operators on my image class:
    Code:
    int GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
    {
       UINT  num = 0;          // number of image encoders
       UINT  size = 0;         // size of the image encoder array in bytes
    
       ImageCodecInfo* pImageCodecInfo = NULL;
    
       GetImageEncodersSize(&num, &size);
       if(size == 0)
          return -1;  // Failure
    
       pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
       if(pImageCodecInfo == NULL)
          return -1;  // Failure
    
       GetImageEncoders(num, size, pImageCodecInfo);
    
       for(UINT j = 0; j < num; ++j)
       {
          if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 )
          {
             *pClsid = pImageCodecInfo[j].Clsid;
             free(pImageCodecInfo);
             return j;  // Success
          }
       }
    
       free(pImageCodecInfo);
       return -1;  // Failure
    }
    ////............
    //for save it on file
    friend std::ostream& operator << (std::ostream& lhs, const image& rhs)
        {
            /*if(IfFileExists(rhs.strfilename)==true)
                lhs<<rhs.strfilename;
            else
            {*/
                IStorage* pIStorage = NULL;
                IStream* pIStream1 = NULL;
                HRESULT hr;
                Status stat = Ok;
                hr = CoInitialize(NULL);
    
                hr = StgCreateDocfile( L"CompoundFile.cmp", STGM_READWRITE|STGM_CREATE|STGM_SHARE_EXCLUSIVE,0, &pIStorage);
    
                CLSID jpgClsid;
                GetEncoderClsid(L"image/gif", &jpgClsid);
                pIStorage->CreateStream(L"StreamImage1", STGM_READWRITE|STGM_SHARE_EXCLUSIVE, 0, 0,&pIStream1);
                rhs.img->Save(pIStream1, &jpgClsid, NULL);
            //}
            return lhs;
        }
    or i miss something or i don't know.
    i'm trying save the img data to file in stream way, instead file name.
    i don't get anyerrors. the problem is that i don't get any image.

  2. #2
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    >> i'm trying save the img data to file in stream way, instead file name.
    Why?
    What is wrong with Image::Save(const WCHAR *filename, ...)?

    gg

  3. #3
    Registered User
    Join Date
    Aug 2013
    Posts
    451
    Quote Originally Posted by Codeplug View Post
    >> i'm trying save the img data to file in stream way, instead file name.
    Why?
    What is wrong with Image::Save(const WCHAR *filename, ...)?

    gg
    because i'm trying overloading the ostream << and istream >> operators. i need these

  4. #4
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    https://msdn.microsoft.com/en-us/lib...(v=vs.85).aspx

    That will give you an IStream that writes to memory - then you can do a lhs.write() of that memory.

    gg

  5. #5
    Registered User
    Join Date
    Aug 2013
    Posts
    451
    Quote Originally Posted by Codeplug View Post
    https://msdn.microsoft.com/en-us/lib...(v=vs.85).aspx

    That will give you an IStream that writes to memory - then you can do a lhs.write() of that memory.

    gg
    i continue with memory leak

    Code:
    friend std::ostream& operator << (std::ostream& lhs, const image& rhs)
        {
            /*if(IfFileExists(rhs.strfilename)==true)
                lhs<<rhs.strfilename;
            else
            {*/
                IStream* pIStream1 = NULL;
                CreateStreamOnHGlobal(NULL,FALSE,&pIStream1);
                CLSID pngClsid;
                GetEncoderClsid(L"image/gif", &pngClsid);
                rhs.img->Save(pIStream1,&pngClsid,NULL);
                lhs<< pIStream1;
            //}
            return lhs;
        }
    
    
        friend std::istream& operator >> (std::istream& lhs, image& rhs)
        {
    
            /*lhs>>rhs.strfilename;
            if(IfFileExists(rhs.strfilename)==true)
                rhs.readimagefile(rhs.strfilename);//FileName it's a property
            else
            {*/
                IStream* pIStream1 = NULL;
    
                lhs>> (char*)pIStream1;
                rhs.img->FromStream(pIStream1,FALSE);
            //}
            return lhs;
        }
    what i'm doing wrong?

  6. #6
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    >> what i'm doing wrong?
    To start, you are not checking any error codes.

    >> lhs<< pIStream1;
    >> [lhs>> (char*)pIStream1;
    Explain what you think these lines are doing.

    gg

  7. #7
    Registered User
    Join Date
    Aug 2013
    Posts
    451
    Quote Originally Posted by Codeplug View Post
    >> what i'm doing wrong?
    To start, you are not checking any error codes.

    >> lhs<< pIStream1;
    >> [lhs>> (char*)pIStream1;
    Explain what you think these lines are doing.

    gg
    honestly i don't have the answer... sorry
    what i know is that if i don't casting it, i will get a compiler error:
    Code:
    cannot bind 'std::istream {aka std::basic_istream<char>}' lvalue to 'std::basic_istream<char>&&'
    now teel me why

  8. #8
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    >>lhs>> (char*)pIStream1;
    I've told you that this is always (almost) wrong. You can't just treat anything like some raw buffer. So stop doing that. You don't know what you're doing or how IStream works internally, so you cannot do any assumptions. You need to use its public interface to do operations on the object. That means calling Read/Write or whatever interface it exposes. The same goes for any other object, such as std::string. Stop using casts. The casts are just masking the actual error. The compiler is nice enough to tell you that you're doing something wrong. Casts should only be used when you are absolutely sure that you know better than the compiler.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  9. #9
    Registered User
    Join Date
    Aug 2013
    Posts
    451
    Quote Originally Posted by Elysia View Post
    >>lhs>> (char*)pIStream1;
    I've told you that this is always (almost) wrong. You can't just treat anything like some raw buffer. So stop doing that. You don't know what you're doing or how IStream works internally, so you cannot do any assumptions. You need to use its public interface to do operations on the object. That means calling Read/Write or whatever interface it exposes. The same goes for any other object, such as std::string. Stop using casts. The casts are just masking the actual error. The compiler is nice enough to tell you that you're doing something wrong. Casts should only be used when you are absolutely sure that you know better than the compiler.
    i'm sorry, but how can i read the IStream?

  10. #10
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    what exactly to you want to put in the stream? Is it supposed to be the image data in some particular file format?

    gg

  11. #11
    Registered User
    Join Date
    Aug 2013
    Posts
    451
    Quote Originally Posted by Codeplug View Post
    what exactly to you want to put in the stream? Is it supposed to be the image data in some particular file format?

    gg
    i need put the Image stream on a file format, on actual file position. that's why i need overloading the operator

  12. #12
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    https://msdn.microsoft.com/en-us/lib...(v=vs.85).aspx
    https://msdn.microsoft.com/en-us/lib...(v=vs.85).aspx
    https://msdn.microsoft.com/en-us/lib...(v=vs.85).aspx
    https://msdn.microsoft.com/en-us/lib...(v=vs.85).aspx

    Those functions will give you a raw memory pointer to the IStream data and the size of that data - that was written by Image::Save(). Once you have that, you put that data in your ostream by calling ostream::write().

    For the reverse process, there is example code in the first link on how to create an HGLOBAL, fill it's memory, and construct an IStream from it. You can then construct an Image from that IStream. If you are saving multiple binary elements to this ostream, then you will need to save the stream size as well.

    Read each of those links carefully and completely. Understand them. Always check for error codes and report them.

    Create a simple console application that has just the << and >> operators, with test code that tries to use it. Then you'll have a complete application that can you post so that others can compile it in order to help.

    gg

  13. #13
    Registered User
    Join Date
    Aug 2013
    Posts
    451
    for write on file seems ok(i think, because i don't get errors):
    Code:
    friend std::ostream& operator << (std::ostream& lhs, const image& rhs)
        {
            STATSTG stats = {0};
    
            //Create an empty IStream:
            IStream* pIStream = nullptr;
            HGLOBAL hg=NULL;
            if(CreateStreamOnHGlobal(hg, FALSE, (LPSTREAM*)&pIStream)!=S_OK)
                DebugText("error on creating an empty IStream");
    
            //choose image format for save it on IStream:
            // Get encoder class id for jpg compression
            // for other compressions use
            //    image/bmp
            //    image/jpeg
            //    image/gif
            //    image/tiff
            //    image/png
            CLSID pngClsid;
            GetEncoderClsid(L"image/gif", &pngClsid);
    
            // Setup encoder parameters
            EncoderParameters encoderParameters;
            encoderParameters.Count = 1;
            encoderParameters.Parameter[0].Guid = EncoderQuality;
            encoderParameters.Parameter[0].Type = EncoderParameterValueTypeLong;
            encoderParameters.Parameter[0].NumberOfValues = 1;
    
            // setup compression level
            ULONG quality = 50;
            encoderParameters.Parameter[0].Value = &quality;
    
            //  Save the image to the stream
            Status SaveStatus = rhs.img->Save(pIStream, &pngClsid, &encoderParameters);
            if(SaveStatus != Ok)
            {
                pIStream->Release();
                DebugText("error on saving to IStream");
            }
    
            //getting the stream size:
            int buffsize=GlobalSize(&hg);
    
            char *pBuff = new char[buffsize];
            ULONG ulBytesRead;
    
            //Read the stream to pBuff
            if(pIStream->Read(pBuff,buffsize, &ulBytesRead)!=S_OK)
                DebugText("error on saving IStream to buffer");
    
            //write the stream size on file
            lhs << buffsize;
    
            //write pBuff data on file
            lhs << pBuff;
    
            //clean resources
            delete pBuff;
            pIStream->Release();
    
            return lhs;
        }
    but for read it:
    Code:
    friend std::istream& operator >> (std::istream& lhs, image& rhs)
        {
            STATSTG stats = {0};
            IStream* pIStream = nullptr;
    
            // Create stream with 0 size
            if(CreateStreamOnHGlobal(nullptr, TRUE, (LPSTREAM*)&pIStream)!=S_OK)
                DebugText("error on creating an empty IStream");
    
            // Get encoder class id for jpg compression
            // for other compressions use
            //    image/bmp
            //    image/jpeg
            //    image/gif
            //    image/tiff
            //    image/png
    
            CLSID pngClsid;
            GetEncoderClsid(L"image/gif", &pngClsid);
    
            // Setup encoder parameters
            EncoderParameters encoderParameters;
            encoderParameters.Count = 1;
            encoderParameters.Parameter[0].Guid = EncoderQuality;
            encoderParameters.Parameter[0].Type = EncoderParameterValueTypeLong;
            encoderParameters.Parameter[0].NumberOfValues = 1;
    
            // setup compression level
            ULONG quality = 50;
            encoderParameters.Parameter[0].Value = &quality;
    
            ULONG streamsize;
            lhs >> streamsize;
            char *pBuff = new char[streamsize];
            lhs >> pBuff;
            ULONG ulBytesRead;
            if(pIStream->Write(pBuff, streamsize, &ulBytesRead)!=S_OK)
                DebugText("error reading stream from a buffer");
    
            if(rhs.img->FromStream(pIStream,FALSE)!=S_OK)
                DebugText("error reading stream to Image");
            pIStream->Release();
            delete pBuff;
            return lhs;
        }
    
    };
    i get the error with FromStream(). what i'm doing wrong?

  14. #14
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    Here is my code review:

    operator <<
    Line 8 - The second parameter should be true. See documentation.
    Line 20 - No error checking
    Line 23 - Consider storing CLSID in the image class
    Line 23 - Consider storing EncoderParameters in the image class
    Line 42 - hg is still NULL at this point. You forgot to call GetHGlobalFromStream()
    Line 44+ - Access the HGLOBAL directly instead of allocating more memory.
    Line 52,55 - You should be using lhs.write(), not lhs<<

    operator >>
    Line 3 - Not used, remove.
    Line 4 - NULL vs nullptr usage inconsistency (in other method)
    Line 18 - Not used, remove.
    Line 22 - Not used, remove.
    Line 29 - Not used, remove.
    Line 33,35 - You should be using lhs.read(), not lhs>>
    Line 34 - You could read directly into an HGLOBAL and then call CreateStreamOnHGlobal() so the stream contents will already be in place.

    I would get it working properly before making changes to read/write from/to HGLOBAL's.

    gg

  15. #15
    Registered User
    Join Date
    Aug 2013
    Posts
    451
    i'm so sorry, but i continue with problems for reading the IStream
    Code:
    friend std::ostream& operator << (std::ostream& lhs, const image& rhs)
        {
    
            //Create an empty IStream:
            IStream* pIStream = nullptr;
            HGLOBAL hg=NULL;
            if(CreateStreamOnHGlobal(hg, TRUE, (LPSTREAM*)&pIStream)!=S_OK)
                DebugText("error on creating an empty IStream");
    
            //choose image format for save it on IStream:
            // Get encoder class id for jpg compression
            // for other compressions use
            //    image/bmp
            //    image/jpeg
            //    image/gif
            //    image/tiff
            //    image/png
            CLSID pngClsid;
            if(GetEncoderClsid(L"image/gif", &pngClsid)!=S_OK)
                DebugText("error on image format");
    
            // Setup encoder parameters
            EncoderParameters encoderParameters;
            encoderParameters.Count = 1;
            encoderParameters.Parameter[0].Guid = EncoderQuality;
            encoderParameters.Parameter[0].Type = EncoderParameterValueTypeLong;
            encoderParameters.Parameter[0].NumberOfValues = 1;
    
            // setup compression level
            ULONG quality = 50;
            encoderParameters.Parameter[0].Value = &quality;
    
            //  Save the image to the stream
            Status SaveStatus = rhs.img->Save(pIStream, &pngClsid, &encoderParameters);
            if(SaveStatus != Ok)
            {
                pIStream->Release();
                DebugText("error on saving to IStream");
            }
    
            //getting the stream size:
            if(GetHGlobalFromStream(pIStream,&hg)!=S_OK)
                DebugText("error on IStream information");
    
            int buffsize=GlobalSize(&hg);
    
            char *pBuff = new char[buffsize];
            ULONG ulBytesRead;
    
            //Read the stream to pBuff
            if(pIStream->Read(pBuff,buffsize, &ulBytesRead)!=S_OK)
                DebugText("error on saving IStream to buffer");
    
            //write the stream size on file
            lhs.write(reinterpret_cast<char*>(&buffsize),sizeof(int));
    
            //write pBuff data on file
            lhs.write(pBuff,sizeof(pBuff));
    
            //clean resources
            delete pBuff;
            pIStream->Release();
    
            return lhs;
        }
    
        friend std::istream& operator >> (std::istream& lhs, image& rhs)
        {
            //getting IStream size:
            ULONG streamsize;
            lhs.read(reinterpret_cast<char*>(&streamsize), sizeof(ULONG));
    
            IStream* pIStream = nullptr;
    
            // Create stream with 0 size
            HGLOBAL hg=NULL;
            lhs.read(reinterpret_cast<char*>(&hg),sizeof(streamsize));
            if(CreateStreamOnHGlobal(&hg, TRUE, (LPSTREAM*)&pIStream)!=S_OK)
                DebugText("error on creating an empty IStream");
    
            //reading IStream on Image class:
            if(rhs.img->FromStream(pIStream,FALSE)!=S_OK)
                DebugText("error reading stream to Image");
    
            //realease resources:
            pIStream->Release();
            return lhs;
        }
    theres 2 things that i didn't understand:
    1 - 'Consider storing CLSID in the image class';
    2 - 'Consider storing EncoderParameters in the image class'.
    i'm sorry, but i'm totaly new with these code.. it's very complex, but i need it

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Displaying Image from stream
    By NetCoder in forum C++ Programming
    Replies: 5
    Last Post: 02-25-2013, 03:04 AM
  2. How can I save an image to file.
    By vmars316 in forum Windows Programming
    Replies: 1
    Last Post: 12-26-2010, 09:44 AM
  3. Low level program to save a mjpeg stream
    By Rufe0 in forum Linux Programming
    Replies: 6
    Last Post: 09-22-2009, 05:53 AM
  4. how to save one svg image by programing
    By sfguofen in forum C++ Programming
    Replies: 9
    Last Post: 09-04-2009, 08:11 PM
  5. How to get image from the screen and then save it to a file?
    By nomer in forum Windows Programming
    Replies: 2
    Last Post: 05-25-2006, 08:46 AM