|
I found this on Microsoft website (see below), as an example how to save pictures. The SaveAsFile function sets the Length to the right amount. But the file seems to be corrupted (About twice the size as the original) Did anyone find a solution to this?
void CPicture::SaveThePicture()
{
IPicture* pPicture = 0;
HRESULT hr = m_pPicture->QueryInterface(IID_IPicture,(void **)&pPicture);
if(SUCCEEDED(hr))
{
IStorage* pStg = 0;
hr = ::StgCreateDocfile(L"E:\\pictures\\mypicture.jpg",
STGM_SHARE_EXCLUSIVE |
STGM_CREATE |
STGM_READWRITE,
0, &pStg);
if(SUCCEEDED(hr))
{
IStream* pStream = 0;
hr = pStg->CreateStream(L"PICTURE",
STGM_SHARE_EXCLUSIVE |
STGM_CREATE |
STGM_READWRITE,
0, 0, &pStream);
if(SUCCEEDED(hr))
{
LONG Length;
hr = pPicture->SaveAsFile(pStream,
FALSE,
&Length);
pStream->Release();
}
pStg->Release();
}
pPicture->Release();
}
}
|
|
|
|
|
This appears to fail because an IStorage file is like a file-system within a file - you actually need to copy the IStream file data to a "normal" file. Here is how I do it (it's long winded but it works fine):
// Create the IStorage needed
IStorage* pStorage = NULL;
// Convert the name
WCHAR wName[MAX_PATH];
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, (LPCTSTR)"TEST.TMP", -1, wName, MAX_PATH);
// Create the storage
if (::StgCreateDocfile(wName, STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE,
0, &pStorage) != ERROR_SUCCESS)
{
return false;
}
// Use the COleStreamFile class
COleStreamFile file;
// Create
if (!file.CreateStream(pStorage, "PICTURE"))
{
pStorage->Release();
return false;
}
// Save
LONG lSize = 0;
// Save the data
HRESULT hResult = m_pPicture->SaveAsFile(file.GetStream(), FALSE, &lSize);
// Success?
if (!SUCCEEDED(hResult))
{
pStorage->Release();
return false;
}
// Create the final output file
CFile fileOut;
// Open
if (!fileOut.Open("PICTURE.JPG", CFile::modeCreate|CFile::modeWrite))
{
pStorage->Release();
return false;
}
// Allocate a read buffer
BYTE* pBuffer = new BYTE [PIC_BUFSIZE];
// Be defensive
if (pBuffer == NULL)
{
pStorage->Release();
return false;
}
// Write to a real file
file.SeekToBegin();
// Loop
while (true)
{
// Read...
UINT nBytesRead = file.Read(pBuffer, PIC_BUFSIZE);
// Write...
fileOut.Write(pBuffer, nBytesRead);
// Are we done?
if (nBytesRead < PIC_BUFSIZE)
break;
}
// Release
pStorage->Release();
// Done
return true;
|
|
|
|
|
Great piece of work, does its job fine in a CFormView!
But I could not manage to get it working in a CDialog (there is no WM_DRAW Message in Dialogs)
and I got a bit confused with DCs ...
Has anyone a hint?
Guenter
|
|
|
|
|
It's a wonderful and useful class. But I encountered a problem when using the class.
The class seems to support MM_TEXT mapping mode only. When I change the dc mapping mode to MM_LOGICAL, the picture can not be drawed on the dc properly. I tried to pass parameters [CPoint(100, -100), CSize(100, -100)] to method Draw(...) instead of [CPoint(100, 100), CSize(100, 100)], but it didn't work, too.
I hope someone could help me. Thanks.
|
|
|
|
|
Yes, I am noticing the same thing. My application uses MM_LOMETRIC and CPicture does not work with this map mode either. You are correct, CPicture ONLY works with MM_TEXT. Additionally, after much massaging, when the image is finally displayed, it is upside down.
Does anyone have any suggestions, or do we need to look at another application? Your help is much appreciated. MK
|
|
|
|
|
I have solved the problem by a compromise way. I change the mapping mode to MM_TEXT when drawing pictures. I rewrote the CPicture::Draw(..) method. With this new method, I can now draw pictures in all type of mapping mode. The new code is as followed. I hope it may be useful to someone.
// rect -- the area on which to draw the picture, the data in rect are just the original
// data in your mapping mode. For example, if you are using MM_LOMETRIC mapping mode, the rect
// may be something like this : top=-100, bottom=-300, left=100, right=200.
BOOL CPicture::Draw(CDC *pDC, CRect rect)
{
BOOL bResult = FALSE;
if (m_pPicture != NULL)
{
CRect rectI = rect;
CPoint startPoint(rect.TopLeft());
CPoint endPoint(rect.BottomRight());
// calculate dp
pDC->LPtoDP(rectI);
// set mapping mode to MM_TEXT
int nOldMode = pDC->SetMapMode(MM_TEXT);
// calculate lp in MM_TEXT mapping mode
pDC->DPtoLP(rectI);
long hmWidth;
long hmHeight;
m_pPicture->get_Width(&hmWidth);
m_pPicture->get_Height(&hmHeight);
int nWidth = rectI.Width();
int nHeight = rectI.Height();
bResult = Draw(pDC, rectI.left, rectI.top, nWidth, nHeight);
// reset mapping mode
pDC->SetMapMode(nOldMode);
}
return bResult;
}
|
|
|
|
|
|
Very good code, but i have a problem with some of bitmaps (jpg, bmp) which are not well rendered with this method, like low quality jpeg images.
Can anyone help me ?
thks
|
|
|
|
|
Ok pb solved. My high-quality jpeg which was rendered like low-quality images. This pb seems to be linked to color depth of windows (16 bits) and the rendering is normal with a color depth of 24 or 32 bits.
|
|
|
|
|
Perhaps that is a little stupid, but please help me!
I see how to load a picture from file, but how can I create a new CPicture with a new drawing (not from a file) or modify an existing one? Is there any way to insert a windows bitmap (CBitmap or DIBSection) into a CPicture object?
Thanks in advance.
Jessie.
|
|
|
|
|
I appreciate your class but saving image is also important. I search for a class that do reading, drawing and saving in different format for a complete package.
Jean-Yves Garneau
|
|
|
|
|
IPicture has method "SaveAsFile" it saves the picture's data into a stream in the same format that it would save itself into a file.
|
|
|
|
|
It will be more easyer:
int PImage::Load(LPCTSTR szFileName) {
...
HRESULT hr = ::OleLoadPicturePath(const_cast<lpolestr>(T2COLE(m_FileName)),
NULL, 0, 0, IID_IPicture, reinterpret_cast<lpvoid *="">(&m_pPicture));
...
}
|
|
|
|
|
Needed a quick and dirty way of loading and display any type of picture, well this is just cool.
5/5
Norm
|
|
|
|
|
Hi Peter,
Excellent class. I was looking for something just like that! It made my life a lot easier.
I added some code to one of the Draw()-functions, so the clients of this class don't need to calculate the ratio if the picture is bigger than the size of the device context. Hope you like it.
In the header file, add a default parameter to the draw function:
bool Draw(CDC* pDC, BOOL bUseDCExtends = FALSE );
In the cpp file, add the following code (and also the default parameter):
bool CPicture::Draw(CDC* pDC, BOOL bUseDCExtends )
{
if (m_pPicture != NULL)
{
long hmWidth;
long hmHeight;
m_pPicture->get_Width(&hmWidth);
m_pPicture->get_Height(&hmHeight);
int nWidth = MulDiv(hmWidth, pDC->GetDeviceCaps(LOGPIXELSX), HIMETRIC_INCH);
int nHeight = MulDiv(hmHeight, pDC->GetDeviceCaps(LOGPIXELSY), HIMETRIC_INCH);
if( bUseDCExtends != FALSE )
{
CRect rect;
double dMinRatio;
double dWidthRatio;
double dHeightRatio;
pDC->GetWindow()->GetWindowRect( &rect );
dWidthRatio = (double)rect.Width() / nWidth;
dHeightRatio = (double)rect.Height() / nHeight;
dMinRatio = ( dWidthRatio < dHeightRatio )? dWidthRatio: dHeightRatio;
if( dMinRatio < 1 )
{
return Draw( pDC, dMinRatio );
}
}
return Draw(pDC, 0, 0, nWidth, nHeight);
}
return false;
}
Of course you can also add the same code in the function Draw( CDC *pDC, CPoint Pos),
but then you should adjust the calculation of dWidthRatio and dHeightRatio, by extracting the CPoint-values from the width and height of the WindowRect.
Have Fun!
|
|
|
|
|
I have been unable to use this class with TIF files.
It seems to work for JPEG,GIF,BMP,ICO,WMF.
Any other formats with which it should work ? I tried PNG as
well and that doesn't seem to work either.
Thanks,
Bruno
|
|
|
|
|
To make this class UNICODE compatible change the following:
GetResource(LPSTR lpName, LPSTR lpType, void* pResource, int& nBufSize);
to
GetResource(LPCTSTR lpName, LPCTSTR lpType, void* pResource, int& nBufSize);
|
|
|
|
|
Hi Michael!
Thankx a lot to Peter for this wonderful article and project, But first we must make sure if we can use the code into our apps; actually afford it or not! as it appears from the discussions here, we every individual of us here must obtain a user license from unisys inc., which is truly heart breaking sad!
"Socrates is a man. All men are mortal.
Therefore Socrates is mortal."
-- Aristotle (syllogism)
Cheers
Masoud Samimi Go!
|
|
|
|
|
there is no problem at all with using this to read JPG, (most) TIFF, PNG, PCX, etc..
you only need to worry about the Unisys license if you are reading GIFs.
-c
|
|
|
|
|
True! The article is great and very much useful!
One thing I cried over, I wished most if I could use the GIF stuff!
"Socrates is a man. All men are mortal.
Therefore Socrates is mortal."
-- Aristotle (syllogism)
Cheers
Masoud Samimi Go!
|
|
|
|
|
YES you can use it for GIF !!!
Microsoft already paid for it.
You only pay the licence when you implement the GIF algorithm,
not when you use third parties libraries (who paid to release it).
|
|
|
|
|
Hi!
Thankx for the YES! But I as well as others got to make sure first and then have it used! Right?
I don't want to hurt any one here and especially Peter! But what about posting a general but direct question to Unisys or Microsoft to just enquire status or the permission of use of the OLEPicture! Isn't this better than the hassle as I mentioned earlier!
To my understanding, what the Unisys lawyers have outlined is a connecting chain that covers the implementor as well as the user! Meaning that if I use the LZW in a DLL (by a programmer for a programmer), the DLL programmer must get the license as well as the DLL user for programming! Enlightem me if wrong, please!
"Socrates is a man. All men are mortal.
Therefore Socrates is mortal."
-- Aristotle (syllogism)
Cheers
Masoud Samimi Go!
|
|
|
|
|
see http://www.microsoft.com/DEVONLY/Unisys.htm
|
|
|
|
|
Sorry, you are 100% wrong.
read what Microsoft says about this:
http://www.microsoft.com/DEVONLY/Unisys.htm
-c
|
|
|
|
|
Uni$ys wants their fee for reading TIFF also. The LZW algorithm is used there apparently. I went through the license application process for my app that formerly handled both GIF and TIFF. Those SOBs wanted a $2500 fee for "advance royalties" on a FREE app that I was going to submit to this site with source code. I couldn't believe it. And they explicitly forbade publishing of any source code.
It will be a joyous day when the LZW patent expires.
|
|
|
|
|