How do I convert a FILE* to an IStream!

Using GDI+, I want to save an HBITMAP to a disk file as JPG.

However, I am doing this within a legacy function that provides an already opened FILE* as a parameter.

I have found nothing in the docs.

static Bool sys_ImageToFileJPEG (HBITMAP hImage, FILE* pFile)
{
    Bool	fRet	= FALSE;

  if (hImage && pFile)
  {
      Gdiplus::Bitmap	image ((HBITMAP)hImage, (HPALETTE)0);

      if (image.GetLastStatus() == Gdiplus::Ok)
      {
          CLSID  encoderClsid;

          wimg_GetEncoderClsid (L"image/jpg", encoderClsid);

          // will not work - Save() wants an IStream!!!
          Gdiplus::Status hr = image.Save (pFile, &encoderClsid);

          if (Gdiplus::Ok == hr)
          {
             fRet = true;
          }
      }
  }

  return (fRet);
}
Ancient Dragon commented: Thanks for using code tags correctly +18

Dani AI

Generated

Short answer: GDI+ needs an IStream. Two practical options are commonly used: (A) the memory-stream trick that writes the image into an HGLOBAL-backed IStream and then dumps those bytes into the FILE (the quick, copy-based approach that showed), or (B) implement a small IStream wrapper that writes directly to the supplied FILE (avoids the extra copy and is cleaner for large data). Both are valid — pick (A) for simplicity, (B) for performance/control.

Important gotchas and checklist

  • Make sure the FILE* is opened in binary mode (for example "wb") or Windows newline translations will corrupt the JPEG.
  • GDI+ may call Seek and Stat on the stream; any wrapper must implement Seek/Stat correctly (and handle 64-bit offsets). If the FILE* is not seekable (pipes/stdout) use the memory-stream route.
  • Check Gdiplus::Status return values and handle errors; release the IStream when done. Watch cbSize.HighPart for very large images when copying from a memory stream.

Minimal File-backed IStream skeleton (illustrates the idea)

// sketch only — implement full error-checking in production
class FileIStream : public IStream {
  FILE* f; LONG ref;
public:
  FileIStream(FILE* fh) : f(fh), ref(1) {}
  // QueryInterface / AddRef / Release (standard COM)
  STDMETHODIMP Read(void* pv, ULONG cb, ULONG* pcbRead) { size_t r=fread(pv,1,cb,f); if(pcbRead)*pcbRead=(ULONG)r; return r==cb?S_OK:S_FALSE; }
  STDMETHODIMP Write(const void* pv, ULONG cb, ULONG* pcbWritten) { size_t w=fwrite(pv,1,cb,f); if(pcbWritten)*pcbWritten=(ULONG)w; return w==cb?S_OK:STG_E_WRITEFAULT; }
  STDMETHODIMP Seek(LARGE_INTEGER dlibMove,DWORD dwOrigin,ULARGE_INTEGER* plibNew) { int o=(dwOrigin==STREAM_SEEK_SET?SEEK_SET:dwOrigin==STREAM_SEEK_CUR?SEEK_CUR:SEEK_END); if(_fseeki64(f,(long long)dlibMove.QuadPart,o)) return STG_E_INVALIDFUNCTION; if(plibNew) plibNew->QuadPart=_ftelli64(f); return S_OK; }
  STDMETHODIMP Stat(STATSTG* pstat, DWORD) { memset(pstat,0,sizeof(*pstat)); pstat->type=STGTY_STREAM; pstat->cbSize.QuadPart=_ftelli64(f); return S_OK; }
  // stub other IStream methods or return E_NOTIMPL
};

Usage hint: create the wrapper with your FILE*, call image.Save(pStream, &encoderClsid), then Release the stream. If you want the simplest path and the images are small, use 's memory-stream copy; for production code or large images, use a proper FileIStream implementation and ensure binary mode, correct Seek/Stat, and robust error handling.

Recommended Answers

All 2 Replies

>> // will not work - Save() wants an IStream!!!
>> Gdiplus :: status hr = image.Save (pFile, &encoderClsid);

// ......
  IStream* pstm ; assert( CreateStreamOnHGlobal( 0, TRUE, &pstm ) >= 0 ) ;
  Gdiplus::Status hr = image.Save( pstm, &encoderClsid ) ;
  STATSTG stat ; assert( pstm->Stat( &stat, STATFLAG_NONAME ) >= 0 ) ;
  size_t sz = stat.cbSize.LowPart ; assert( stat.cbSize.HighPart == 0  ) ;
  HGLOBAL hg ; assert( GetHGlobalFromStream( pstm, &hg ) >= 0 ) ;
  assert( fwrite( GlobalLock(hg), sz, sz, pFile ) ==  sz ) ;
  GlobalUnlock(hg) ; pstm->Release() ;
// .....

Thanks! I will give this a try.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.