tantormedia
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.
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.
Oops, I called Save() twice... of course first call is wrong.
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.
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.
ASKER
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.
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
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
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.
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\\myne wimg.bmp") ) ;
myImgFile.Close() ;
m_myNewImage.Load(_T("c:\\
> "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).
> You've read the code too quickly ;) it uses a buffer (initialized a 2048, but you can increase it).
ASKER
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.GetLe ngth(), 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 ;
To optimize, you can do the following :
uiBufSize = _min((UINT)myImgFile.GetLe
char chBuf = new char[uiBufSize] ;
...
// don't forget buffer deletion after process
delete [] chBuf ;
ASKER
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::beg in);
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::beg in);
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::m odeReadWri te);
fTemp.Write(pData, s);
pPara->m_pImg = new CImage();
HRESULT res = pPara->m_pImg->Load("C:\\B ookProgram \\Book\\te mp.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.
CFile fTemp(ImpDlg.GetPathName()
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,
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,
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::m
fTemp.Write(pData, s);
pPara->m_pImg = new CImage();
HRESULT res = pPara->m_pImg->Load("C:\\B
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
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
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.GetLe ngth(), 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.
Could you please explain me what you wrote in your previous answer:
To optimize, you can do the following :
uiBufSize = _min((UINT)myImgFile.GetLe
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.
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.
ASKER
Thank you very much.
For example :
CImage myImg ;
myImg.Load(_T("c:\\temp\My
CImage myNewImg ;
myNewImg.Attach(hBmp) ; // Attach a bitmap currently displayed somewhere
myNewImage.Save() ;
m_myNewImage.Save(_T("c:\\
myNewImg.Detach() ;