Am I missing some important step? The HRESULT indicates an unknown error.
(Stepping through image.Save(), I see it succeeding until the last step
Gdiplus::Bitmap bm( m_hBitmap, NULL );
status = bm.Save( pwszFileName, &clsidEncoder, NULL );
which fails.)
================
The code:
Schematically I have
HBITMAP hBitmap = ......;
// I then call a debugging routine which displays the bitmap
// in a dialogue: it looks ok.
// I now want to save it as a GIF
TCHAR szFilename[ ] = _T(".... .gif");
// This is a UNICODE string.
// It gives the full path to a non-existent file in
// and existing directory (which is not write protected).
CImage image;
image.Attach( hBitmap );
HRESULT hResult = image.Save( szFilename );
image.Detach();
==============
Any ideas?
Dave
--
David Webber
Author of 'Mozart the Music Processor'
http://www.mozart.co.uk
For discussion/support see
http://www.mozart.co.uk/mozartists/mailinglist.htm
Hi Dave,
I think that CImage is a part of GDI+, so maybe it is required to initialize
GDI+.
Do you call GdiplusStartup() and GdiplusShutdown properly in your code?
(I'm not sure if CImage does that in its constructor and destructor.)
Giovanni
> I think that CImage is a part of GDI+, so maybe it is required to
> initialize GDI+.
> Do you call GdiplusStartup() and GdiplusShutdown properly in your code?
Sorry, I confused *C*Image (which is from ATL) with Image (GDI+) :
http://msdn.microsoft.com/en-us/library/ms534462.aspx
However, you may want to try GDI+'s Image instead of CImage.
Or, if you want to still use CImage, I would try passing an explicit value
for 'guidFileType' parameter in CImage::Save() method:
http://msdn.microsoft.com/en-us/library/ms534462.aspx
As a final note, I really like the CxImage class:
http://www.codeproject.com/KB/graphics/cximage.aspx
Giovanni
#include <atlimage.h>
DEFINE_GUID(ImageFormatBMP, 0xb96b3cab,0x0728,0x11d3,0x9d,0x7b,
0x00,0x00,0xf8,0x1e,0xf3,0x2e);
-----
void SaveImage(HBITMAP hBmp )
{
CImage img;
img.Attach(hBmp); // hBmp is a valid HBITMAP
CString str(_T("c:\\temp\\test.bmp");
img.Save(str,ImageFormatBMP);
img.Detach();
}
-SM
>> I think that CImage is a part of GDI+, so maybe it is required to
>> initialize GDI+.
>> Do you call GdiplusStartup() and GdiplusShutdown properly in your code?
Thanks Giovanni.
Yes, as it happens. And I have now moved my image saving code to the DLL
from which these are called - with no difference in result.
> Sorry, I confused *C*Image (which is from ATL) with Image (GDI+) :
>
> http://msdn.microsoft.com/en-us/library/ms534462.aspx
>
> However, you may want to try GDI+'s Image instead of CImage.
CImage::Save() actually creates a GDI+ Bitmap and uses Bitmap::Save(...);
Stepping through it, it is happy that GDI+ is initialised and appears to
retrieve the "encoder" for a gif file corectly, but Bitmap::Save() (the
last call of CImage::Save() ) fails.
> Or, if you want to still use CImage, I would try passing an explicit value
> for 'guidFileType' parameter in CImage::Save() method:
It doesn't make any difference :-(
And doing it directly from the Gdiplus::Bitmap() has exactly the same
problem.
This is really frustrating!
> As a final note, I really like the CxImage class:
>
> http://www.codeproject.com/KB/graphics/cximage.aspx
>
I'll have a look, but I was trying to do it without recourse to third party
software. I have been using the excellent "FreeImage" for many years now,
but I'd hoped that standard library functions would do the trick these days.
I still can't see why they don't.
>>> Do you call GdiplusStartup() and GdiplusShutdown properly in your code?
>
> Thanks Giovanni.
>
> Yes, as it happens. And I have now moved my image saving code to the DLL
> from which these are called - with no difference in result.
Reading the source code of CImage class in <atlimage.h> (in VS2008), it can
be observed the presence of a static private data member in CImage:
's_initGDIPlus', which is a static instance of class CInitGDIPlus, whose
purpose in life seems to be to initialize and shutdown GDI+ properly.
So, it seems that there is no need of explicit GdiplusStartup/Shutdown() to
use CImage.
> CImage::Save() actually creates a GDI+ Bitmap and uses Bitmap::Save(...);
>
> Stepping through it, it is happy that GDI+ is initialised and appears to
> retrieve the "encoder" for a gif file corectly, but Bitmap::Save() (the
> last call of CImage::Save() ) fails.
You are referring to this code, correct?
Gdiplus::Bitmap bm( m_hBitmap, NULL );
status = bm.Save( pwszFileName, &clsidEncoder, NULL );
if( status != Gdiplus::Ok )
{
return E_FAIL.
}
Have you watched the actual value of 'status' after Gdiplus::Bitmap::Save()
method returns?
This could lead to meaningful information, better than the generic E_FAIL
HRESULT value.
> And doing it directly from the Gdiplus::Bitmap() has exactly the same
> problem.
>
> This is really frustrating!
I agree with you.
There must be some subtle bug here...
Instead these common-use classes should be designed and implemented to be
easy to use, and not cause subtle bug-hunting like this...
Giovanni
<code>
void CTestCImageDlg::OnBnClickedButton1()
{
CString imageSrcFilename = TEXT("image1.gif");
CString imageDestFilename = TEXT("image1_copy.gif");
HRESULT hr;
CImage src;
hr = src.Load( imageSrcFilename );
ASSERT( SUCCEEDED(hr) );
HBITMAP hbmp = src.Detach();
ASSERT( hbmp != NULL );
CImage dest;
dest.Attach( hbmp );
hr = dest.Save( imageDestFilename );
ASSERT( SUCCEEDED(hr) );
dest.Detach();
}
</code>
and it works fine...
Weired...
Dave: are you sure that you don't have any kind of lock on the file you are
going to create? Is the directory writable?
Giovanni
>I created a simple dialog-based MFC application using VS2008, added a
>button and the following handler:
>....
> and it works fine...
Thanks for your efforts ....
> Dave: are you sure that you don't have any kind of lock on the file you
> are going to create? Is the directory writable?
It is starting to look like that might be possible. The directory is
created within my "appdata" path using default security, so it *ought* to
be writable, as that's what appdata is for!
I'll check.
I'm getting encouraged that there must be something simple wrong. Perhaps
a reboot?
> (I am using Vista).
During the successful tests I did I was instead using XP SP2...
I'm not sure if it is an OS-related issue...
Giovanni
"Seetharam" <smi...@gmail.com> wrote in message
news:92f4416b-f2c6-4151...@u28g2000hsc.googlegroups.com...
Thanks. I *thought* it ought to be as simple as that.
I have tried this pretty much directly now (except using ImageFormatBMP from
the MS header file - but it's the same value) and it still fails (so it
wasn't just a problem with the GIF option).
(I am using Vista).
This is extremely annoying!
> Dave: are you sure that you don't have any kind of lock on the file you
> are going to create? Is the directory writable?
The GDI+ Bitmap::Save() method is returning a status
Win32Error
about which, the help helpfully tells me "Indicates that the method
generated a Microsoft Win32 error".
But it is not any of
AccessDenied (Indicates that a write operation is not allowed on the
specified file. )
UnknownImageFormat (Indicates that the specified image file format is not
known.)
GdiplusNotInitialized
InvalidParameter
...
So all I have to do is work out what a "Win32Error" is when it's at home :-(
Does calling GetLastError immediately afterwards give any relevant
information?
Dave
Have you tried saving to BMP (just to test) or does that fail too?
Mark
--
Mark Salsbery
Microsoft MVP - Visual C++
"David Webber" <da...@musical-dot-demon-dot-co.uk> wrote in message
news:euex1VUK...@TK2MSFTNGP03.phx.gbl...
Also, what is the value of status after the Save() call here?
(sorry if you already answered that - I'm not seeing it anywhere :))
Thanks Mark - yes it fails on saving as a bmp as well,,,
> Also, what is the value of status after the Save() call here?
... and the error is status=Win32Error.
> (sorry if you already answered that - I'm not seeing it anywhere :))
No problem - I'm getting desperate and all attempts to help are welcome!
I'll try GetLastError as David suggests, and also I'll experiment with a
different hBitmap.
I have obtained this one by a weird and wonderful route, and whilst I can
see it in my home-made debugging dialogue for showing bitmaps, there may be
something odd about it.
(I got a CImageList from a CToolbarCtrl, and then got an icon from the image
list, and then got the hBitmap from the icon. The Gdiplus::Bitmap can be
created directly from an hIcon, and I've tried that too, but trying to save
it fails in the same way.)
Eureka!
It tells me I have made a silly programming error, and am trying to save the
file in a directory which does not exist, (but one which has a very long
name which happens to be very similar to one which does exist) :-(
Slaps forehead :-(
Correcting this has fixed it!
I thought the Gdiplus::Status would have told me this, but now, slightly
older, slightly wiser, and with a lot less hair, I know to use GetLastError,
even when I have a Gdiplus::Status.
Sincerest (and rather embarrassed) thanks to you, and everyone who has
helped on this!
Great. I'm glad that's helped.
>I thought the Gdiplus::Status would have told me this, but now, slightly
>older, slightly wiser, and with a lot less hair, I know to use GetLastError,
>even when I have a Gdiplus::Status.
I don't know for sure, but I suspect it might only be applicable to
use GLE when the status returns Win32Error.
Dave