1

I am currently trying to figure out how to properly store a CImage file within a CArchive (JPEG). My current approach to this is the following (pseudo) code:

BOOL CPicture::Serialize(CArchive &ar)
{
  IStream *pStream = NULL;  
  HRESULT hr;
  CImage *img = GetImage();

  if (ar.IsLoading())
  {
    HGLOBAL hMem = GlobalAlloc(GMEM_FIXED, 54262);
    hr = CreateStreamOnHGlobal(hMem, FALSE, &pStream);
    if(SUCCEEDED(hr))
    {
      ar.Read(pStream, 54262);
      img->Load(pStream);
      pStream->Release();
      GlobalUnlock(hMem);
      GlobalFree(hMem);
    }
  }
  else
  {   
    hr = CreateStreamOnHGlobal(0, TRUE, &pStream);
    if (SUCCEEDED(hr))
    {
      hr = img->Save(pStream, Gdiplus::ImageFormatJPEG);
      if (SUCCEEDED(hr))
      ar.Write(pStream, 54262);
    }
  }

...

I am just now getting back into C++ and have only done a little with it in the past. Any help would be very much appreciated.

Thank you very much in advance.

IInspectable
  • 46,945
  • 8
  • 85
  • 181
Faceless
  • 19
  • 2
  • 4
    It's generally a good idea to ask a question on a Q&A site. You failed to ask a question. It's not at all clear what issue you are trying to solve. Does your code work? Does your code fail (if so, how)? Do you just need feedback on your code? Are you looking for a developer to write the code for you? Something else? – IInspectable Jan 06 '17 at 16:17

1 Answers1

2

I'm not an expert on IStream, but I think you may not be using it correctly. The following code seems to work. It currently archives in png format, but it can easily be changed through Gdiplus::ImageFormatPNG. It owes a lot to the tutorial "Embracing IStream as just a stream of bytes" by S. Arman on CodeProject.

void ImageArchive(CImage *pImage, CArchive &ar)
{
    HRESULT hr;
    if (ar.IsStoring())
    {
// create a stream
        IStream *pStream = SHCreateMemStream(NULL, 0);
        ASSERT(pStream != NULL);
        if (pStream == NULL)
            return;

// write the image to a stream rather than file (the stream in this case is just a chunk of memory automatically allocated by the stream itself)
        pImage->Save(pStream, Gdiplus::ImageFormatPNG); // Note: IStream will automatically grow up as necessary.

// find the size of memory written (i.e. the image file size)
        STATSTG statsg;
        hr = pStream->Stat(&statsg, STATFLAG_NONAME);
        ASSERT(hr == S_OK);
        ASSERT(statsg.cbSize.QuadPart < ULONG_MAX);
        ULONG nImgBytes = ULONG(statsg.cbSize.QuadPart);    // any image that can be displayed had better not have more than MAX_ULONG bytes

// go to the start of the stream
        LARGE_INTEGER seekPos;
        seekPos.QuadPart = 0;
        hr = pStream->Seek(seekPos, STREAM_SEEK_SET, NULL);
        ASSERT(hr == S_OK);

// get data in stream into a standard byte array
        char *bytes = new char[nImgBytes];
        ULONG nRead;
        hr = pStream->Read(bytes, nImgBytes, &nRead);   // read the data from the stream into normal memory.  nRead should be equal to statsg.cbSize.QuadPart.
        ASSERT(hr == S_OK);
        ASSERT(nImgBytes == nRead);

// write data to archive and finish
        ar << nRead;    // need to save the amount of memory needed for the file, since we will need to read this amount later
        ar.Write(bytes, nRead);     // write the data to the archive file from the stream memory
        pStream->Release();
        delete[] bytes;
    }
    else
    {
// get the data from the archive
        ULONG nBytes;
        ar >> nBytes;
        char *bytes = new char[nBytes]; // ordinary memory to hold data from archive file
        UINT nBytesRead = ar.Read(bytes, nBytes);   // read the data from the archive file
        ASSERT(nBytesRead == UINT(nBytes));

// make the stream
        IStream *pStream = SHCreateMemStream(NULL, 0);
        ASSERT(pStream != NULL);
        if (pStream == NULL)
            return;

// put the archive data into the stream
        ULONG nBytesWritten;
        pStream->Write(bytes, nBytes, &nBytesWritten);
        ASSERT(nBytes == nBytesWritten);
        if (nBytes != nBytesWritten)
            return;

// go to the start of the stream
        LARGE_INTEGER seekPos;
        seekPos.QuadPart = 0;
        hr = pStream->Seek(seekPos, STREAM_SEEK_SET, NULL);
        ASSERT(hr == S_OK);

// load the stream into CImage and finish
        pImage->Load(pStream);  // pass the archive data to CImage
        pStream->Release();
        delete[] bytes;
    }
}
Andrew Truckle
  • 17,769
  • 16
  • 66
  • 164
Bill Heitler
  • 187
  • 3
  • 13