Link to home
Start Free TrialLog in
Avatar of tantormedia
tantormediaFlag for United States of America

asked on

MFC: How to Write() and Read() a CImage into a file?

Dear experts,

I have an MFC application. I use VS 2008.
Could you please give me an example how I can write an image to a binary file and read from it?
I would like to use CFile's Write() and Read() methods, and probably CImage.

Thanks.
Avatar of Xper4net
Xper4net
Flag of France image

You don't have to use CFile. CImage::Save and CImage::Load do the job.

For example :

CImage myImg ;

   myImg.Load(_T("c:\\temp\MyPicture.jpg")) ;

CImage myNewImg ;

   myNewImg.Attach(hBmp) ; // Attach a bitmap currently displayed somewhere
   myNewImage.Save() ;
   m_myNewImage.Save(_T("c:\\temp\\mynewimg.bmp")) ;
   myNewImg.Detach() ;


Oops, I called Save() twice... of course first call is wrong.
Avatar of tantormedia

ASKER

I am afraid, that I have to use CFile, because CImage is not the only thing I am saving, my file contains a lot of various data. So the call to Write() my image is only one of many other Write() calls.
So, in this case, instead of CFile, maybe you could use IStream versions of Save and Load. But I'm not sure that it could work (in fact, I'm almost sure that it couldn't).
Then, my advice would be to to use separate files, and an external tool (like dzip/dunzip) to gather them in an unique file.
> In OnOpenDocument, you unzip the file in a temporary folder.
> During work, you populate/update this temprary folder.
> In OnSaveDocument, you zip the temporary folder's content.
I've use this solution in many projects, it works very fine.
Let me know if you need more details.
Thank you for your answer.
I cannot replace CFile with something else, as it would require too much change in a huge project.
Could you give me an example on your next suggestion?
What I need can be simplified in this way: An image in some form is stored among other things using CFile's Write() method.
On using Read(), the image is read into memory from where it can be used to be displayed in a View.
Thanks.
ASKER CERTIFIED SOLUTION
Avatar of Xper4net
Xper4net
Flag of France image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thank you for your answer.
I have some questions.
- "Attach a bitmap currently displayed somewhere" - I don't have such a bitmap. All I have is a path to my image file. Can I just use Load() instead?
- I seems like in your code, we read and write data byte by byte. Isn't it possible first to read the whole data into a buffer and then write it at once into the main file?
- The loading part of your code is identical to the saving part.
In second code view, first line must be removed, and the following added at the end :

myImgFile.Close() ;
m_myNewImage.Load(_T("c:\\temp\\mynewimg.bmp")) ;
> "currently displayed somewhere" figures "An image in some form" in your requirement. If your image is already in a file, you don't need CImage for the saving part.
> You've read the code too quickly ;) it uses a buffer (initialized a 2048, but you can increase it).
May I ask why we cannot use a buffer of the size returned by myImgFile.GetLength()?
You could, but with large images (> 1 Mo), it could lead to a long time process for memory allocation request taking  (system needs to allocate in one continuous block, and if memory is fragmented, it needs to de-fragment it before).
To optimize, you can do the following :

uiBufSize = _min((UINT)myImgFile.GetLength(), 0x100000) ; // Allocates for file length if < 1 Mo, or at least 1 Mo
char chBuf = new char[uiBufSize] ;
...

// don't forget buffer deletion after process
delete [] chBuf ;
Thank you for your help. Something goes wrong though. I am trying to do it simply by allocating the whole memory at once so far:

            CFile fTemp(ImpDlg.GetPathName(), CFile::modeRead | CFile::shareDenyNone);

            ULONGLONG size = fTemp.GetLength();

            BYTE* buf = new BYTE[size];

            int TotSize = 4 + sizeof(ULONGLONG) + size;

            pPara->m_WaveLoc = pc->AllocFileBlock(TotSize);
            cf->Seek(pPara->m_WaveLoc,CFile::begin);

            cf->Write("PNG ",4);
            cf->Write(&size, sizeof(size));
            cf->Write(buf, fTemp.Read(buf, size)) ;

            fTemp.Close();

Now I am reading the file thus:

                  if(pPara->m_pImg != NULL)
                  {
                        delete(pPara->m_pImg);
                  }

                  cf->Seek(pPara->m_WaveLoc,CFile::begin);
                  char tp[4];
                  cf->Read(tp,4);
                  //ASSERT(!strncmp(tp,"PNG ",4));
                  if(!strncmp(tp,"PNG ",4))
                  {
                        ULONGLONG s;
                        cf->Read(&s,sizeof(s));
                        BYTE * pData = new BYTE[s];
                        cf->Read(pData, s);

                        CFile fTemp("temp.png", CFile::modeCreate|CFile::modeReadWrite);
                        fTemp.Write(pData, s);
                        pPara->m_pImg = new CImage();
                        HRESULT res = pPara->m_pImg->Load("C:\\BookProgram\\Book\\temp.png");
                        fTemp.Close();
                  }

res is E_FAIL, though temp.png is created, and I can open it and see the right image. Why cannot I load it?
Thanks.
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thank you very much, now it worked.
Could you please explain me what you wrote in your previous answer:
To optimize, you can do the following :

uiBufSize = _min((UINT)myImgFile.GetLength(), 0x100000) ; // Allocates for file length if < 1 Mo, or at least 1 Mo
char chBuf = new char[uiBufSize] ;

Here we allocate a buffer for the first 1 MB, but what happens with the rest? Should I go in a loop as you showed before?
Thanks.
Yes, you're right.
For example, if image size is 2.3 Mo, there will be three read/write loops (1 + 1 + 0.3).
As I said, this kind of approach is faster (and more secured) than a great allocation.
Thank you very much.