When i try the same object to save it on a byte*, and then save this byte*
on disk, this memory remains empty.
IStream *buffer;
CreateStreamOnHGlobal(NULL, true, &buffer);
bitmap->Save(buffer,&m_bmpClsid,NULL);
buffer->Read(m_szBuff,m_bmpBufferSize, &m_nRead);
Any ideas on a better way to do this?
I found this code on web (on C# though...),
Rect rect(0, 0, bitmap->GetHeight(), bitmap->GetWidth());
BitmapData* bData = new BitmapData;
bitmap->LockBits(&rect,ImageLockModeRead,PixelFormat24bppRGB,bData);
int byteCount = bData->Stride*bitmap->GetHeight();
memcpy(m_szBuff,originalScanPtr,byteCount);
bitmap->UnlockBits (bData);
instead of memcpy they used a function named marshal.copy. Here, malloc
throws exception but i cannot get any meaning out of it. Any ideas what i am
doing wrong in ether case?
Thank you guys, looking forward for an answer
>I have a Bitmap (bmp) object. Using save, i can save it to disk:
>image->Save(L"C:/test.bmp", &m_bmpClsid, NULL);
****
I don't see a Bitmap object here. I see a variable called 'bitmap', but it has no known
data type. I don't find a method called 'Save' as part of CBitmap. So what is the type
of this variable? An instance of the *class* Bitmap, however, *does* have a Save method.
The term .bmp refers to a file, and bmp usually refers to an HBITMAP. If you meant that
you had an instance of the Bitmap class you could have said
Bitmap bitmap;
and I'm not sure where (bmp) applies at all.
****
>
>When i try the same object to save it on a byte*, and then save this byte*
>on disk, this memory remains empty.
****
What are you talking about?
****
>
>IStream *buffer;
>CreateStreamOnHGlobal(NULL, true, &buffer);
****
OK, this creates an internal shared memory block of size 0. What is the implication of
this? It is saving 0 bytes? Perhaps the reason the memory is empty is that you are
saving 0 bytes to this internal buffer?
****
>bitmap->Save(buffer,&m_bmpClsid,NULL);
****
If we knew the type of 'bitmap', which is NOT an HBITMAP, or a CBitmap, it might be
possible to offer an opinion on this; why did you not bother to show what this declaration
is?
Of course, you DID check the return value, didn't you? So you KNOW that this operation
succeeded, right? So you know it returned the Status value Ok, and not, for example,
InvalidParameter, OutOfMemory, InsufficientBuffer, Win32Error, ValueOverflow, or some
other value that might indicate that the operation failed. Right?
****
>buffer->Read(m_szBuff,m_bmpBufferSize, &m_nRead);
****
According to the IStream specification, this reads a specified number of bytes from the
stream. But the stream was created, according to the documentation, with a buffer of 0
length. So is it surprising that it returns 0 bytes? It only has 0 bytes to return!
In accordance with IStream::Read, of course you tested to see if &m_nRead (and why does
this need to be a class member variable?) was equal to m_bmpBufferSize, right? Not sure I
see that code here.
****
>
>Any ideas on a better way to do this?
****
Correctly?
For example, by allocating an HGLOBAL of appropriate length to hold the bitmap, so that
the Save has a place to save the data? Or using IStream::SetSize(m_bmpBufferSize) before
doing the Save to create a buffer of appropriate length? You created an IStream of 0
length, wrote to it (I notice that you did NOT test the result of the Save or Read, so it
is not clear what is happening...)
****
>
>I found this code on web (on C# though...),
>
> Rect rect(0, 0, bitmap->GetHeight(), bitmap->GetWidth());
> BitmapData* bData = new BitmapData;
> bitmap->LockBits(&rect,ImageLockModeRead,PixelFormat24bppRGB,bData);
> int byteCount = bData->Stride*bitmap->GetHeight();
> memcpy(m_szBuff,originalScanPtr,byteCount);
> bitmap->UnlockBits (bData);
>
>instead of memcpy they used a function named marshal.copy. Here, malloc
>throws exception but i cannot get any meaning out of it. Any ideas what i am
>doing wrong in ether case?
****
What do you mean "malloc throws an exception"? What is "an" exception? The last I
looked, exceptions had information. For example, the nature of the exception. Some
message comes out saying the exception occurred, and what it was. I have no idea what you
mean by "an" exception unless you give DETAILED information about the behavior. Stack
backtraces can help, the line of code that caused or intercepted the exception, etc. Even
if you can't get any meaning out of it, given enough information, there's a chance that
one of us could get meaning out of it. But we *can't* derive meaning from a description
that it is "an" exception!
Hint: you did not give sufficient information to tell what the code is doing, you wrote
code that doesn't test for or report error conditions, you use vague and meaningless
descriptions of what are very specific events ("an" exception); none of which is going to
help diagnose the problem.
What did you do wrong? Failed to specify all the values and their types, failed to read
the documentation, failed to test return values, failed to report error conditions in a
way that would make them useful.
joe
****
That should work but you may want to seek to the beginning of the stream
before Read()....you won't get any bytes starting at the end of the stream
:)
Mark
--
Mark Salsbery
Microsoft MVP - Visual C++
Here's a quickly-hacked-together version of your code that works,
demonstrating the need to seek to the beginning of the stream before trying
to read bytes:
Bitmap bitmap(320, 240, PixelFormat32bppRGB);
IStream *buffer;
::CreateStreamOnHGlobal(NULL, true, &buffer);
CLSID m_bmpClsid;
GetEncoderClsid(L"image/bmp", &m_bmpClsid);
bitmap.Save(buffer,&m_bmpClsid,NULL);
STATSTG statstg;
buffer->Stat(&statstg, STATFLAG_DEFAULT);
ULONG m_bmpBufferSize = (ULONG)statstg.cbSize.LowPart;
BYTE *m_szBuff = new BYTE[m_bmpBufferSize];
LARGE_INTEGER li = {0};
buffer->Seek(li, STREAM_SEEK_SET, NULL);
ULONG m_nRead;
buffer->Read(m_szBuff,m_bmpBufferSize, &m_nRead);
...
delete[] m_szBuff;
You'd definitely want some error checks in there...
Mark
--
Mark Salsbery
Microsoft MVP - Visual C++
>
buffer->Release();
"Joseph M. Newcomer" wrote:
Hello Joseph M. Newcomer,
First of all, sorry for not being very clear on this, I never before worked
on graphics programming, so I don’t know a lot on this. The post below,
helped me though, just wished to clear things before considering this close.
In any case, thank you a lot for trying to help me and clearing my questions
more.
1. With Bitmap, I mean GDIPlus:: Bitmap, this one has Save.
2. (Bmp) I put it to explain the format. Obviously, for you, Bitmap class
means Bitmap format (not jpeg, ppm, etc). for me, rookie on graphics and C++,
until some days before, it did not.
3.
> >When i try the same object to save it on a byte*, and then save this byte*
> >on disk, this memory remains empty.
> ****
> What are you talking about?
I have the GDIPlus::Bitmap, when I would do
bitmap->Save(L"C:/ImageToSave.bmp", &m_bmpClsid, NULL); This would be saved
as file on disk.
When I would load this on the byte array, and so as to see what has been put
on this array, I would flush it on a file at disk, I would see a file full of
0x00 which for me, meant empty array.
4.
> >IStream *buffer;
> >CreateStreamOnHGlobal(NULL, true, &buffer);
> ****
> OK, this creates an internal shared memory block of size 0. What is the implication of
> this? It is saving 0 bytes? Perhaps the reason the memory is empty is that you are
> saving 0 bytes to this internal buffer?
Hm… as I said I am beginner in c++ never used this before, but it kinda
worked with using CreateStreamOnHGlobal(NULL, true, &buffer); If I understood
correctly, the NULL in the beginning, means that program, can reserve memory
as needed for the stream. If I create my own memory and put it there, this is
correct as well, but NULL there is also correct as it seems that stream, gets
memory of the application’s stack as needed.
5.
> ****
> >bitmap->Save(buffer,&m_bmpClsid,NULL);
> ****
> If we knew the type of 'bitmap', which is NOT an HBITMAP, or a CBitmap, it might be
> possible to offer an opinion on this; why did you not bother to show what this declaration
> is?
As said before, I didn’t know more than GDIPluss Bitmap classes existed. My
apologies on this people.
6.
> Of course, you DID check the return value, didn't you? So you KNOW that this operation
> succeeded, right? So you know it returned the Status value Ok, and not, for example,
> InvalidParameter, OutOfMemory, InsufficientBuffer, Win32Error, ValueOverflow, or some
> other value that might indicate that the operation failed. Right?
Ofcourse I did… I am beginner in all these, but I do debug the applications
I create…
7.
> ****
> >buffer->Read(m_szBuff,m_bmpBufferSize, &m_nRead);
> ****
> According to the IStream specification, this reads a specified number of bytes from the
> stream. But the stream was created, according to the documentation, with a buffer of 0
> length. So is it surprising that it returns 0 bytes? It only has 0 bytes to return!
> In accordance with IStream::Read, of course you tested to see if &m_nRead (and why does
> this need to be a class member variable?) was equal to m_bmpBufferSize, right? Not sure I
> see that code here.
Ok, I put just a piece of the code, you are correct here. I will attach in
the end, my code for others to have having all the checks. m_nRead would
return 0. This was my problem… I needed to use SEEK correct as explained from
others on the post.
8.
> What do you mean "malloc throws an exception"? What is "an" exception? The last I
> looked, exceptions had information. For example, the nature of the exception. Some
> message comes out saying the exception occurred, and what it was. I have no idea what you
> mean by "an" exception unless you give DETAILED information about the behavior. Stack
> backtraces can help, the line of code that caused or intercepted the exception, etc. Even
> if you can't get any meaning out of it, given enough information, there's a chance that
> one of us could get meaning out of it. But we *can't* derive meaning from a description
> that it is "an" exception!
Hey… don’t laugh but I can catch exceptions on C#, Java, etc, but never
managed to catch exception on C++ I use try{}catch(){}, but inside catch() I
put always three dots “…”
I haven’t ever found how to put i.e. “Exception e” inside catch. I know it
is possible, I seen other’s creating own Exceptions and use it, but never
found a generic exception class for me to use and trace errors. Maybe you can
spoil some more time to tell me how to do it. This would be grate.
9.
>
> Hint: you did not give sufficient information to tell what the code is doing, you wrote
> code that doesn't test for or report error conditions, you use vague and meaningless
> descriptions of what are very specific events ("an" exception); none of which is going to
> help diagnose the problem.
>
> What did you do wrong? Failed to specify all the values and their types, failed to read
> the documentation, failed to test return values, failed to report error conditions in a
> way that would make them useful.
You are correct. Sorry for this. Hopefully I made things more clear now. I
just hope though you do understand it is not as easy when someone that has
only one month of programming in c++ to understand entirely what he needs to
mention to get help easily form others.
a. I couldn’t catch the exception
b. I thought GDIPlus was the only tool for me to use (do be frunk I didn’t
even bother to think of it).
c. I did the check until making my code to work only with breakpoints and
although before posting I should have made the code easier to trace, I
didn’t, thinking that actual GDI and C++ experts would find it easy to find
my error.
inline bool GetBitmapData(Bitmap *bitmap)
{
HRESULT res=-1;
Status status=Aborted;
IStream *pStream=0;
res = ::CreateStreamOnHGlobal(NULL,TRUE,&pStream);
status=bitmap->Save(L"C:/ImageToSave.bmp", &m_bmpClsid, NULL);
if(res == S_OK)
{
status=bitmap->Save(pStream,&m_bmpClsid,NULL);
if (status==S_OK)
{
LARGE_INTEGER li = {0};
HRESULT res=pStream->Seek(li, STREAM_SEEK_SET, NULL);
if (res==S_OK)
{
res=pStream->Read(m_szBuff,m_bmpBufferSize, &m_nRead);
if (res==S_OK)
{
pStream->Release();
return true;
}
}
}
}
try
{
pStream->Release();
}
catch(...)
{
return false;
}
return false;
}
inline Bitmap* Decode(Image *image)
{
IStream *Encodingbuffer;
CreateStreamOnHGlobal(NULL, true, &Encodingbuffer);
image->Save(Encodingbuffer,&m_bmpClsid,NULL);
//image->Save(L"C:/test.bmp", &m_pngClsid, NULL);
Bitmap *bitmap=new Bitmap(Encodingbuffer);
Encodingbuffer->Release();
return bitmap;
}
inline Bitmap* Resize(Bitmap *mImage, int inWidth, int inHeight, bool
inKeepAspectRatio)
{
int theDesiredWidth = inWidth;
int theDesiredHeight = inHeight;
if(inKeepAspectRatio)
{
double theHorizontalResizeFactor =
(double)inWidth/(double)mImage->GetWidth();
double theVerticalResizeFactor =
(double)inHeight/(double)mImage->GetHeight();
double theResizeFactor = std::min<double>(
theHorizontalResizeFactor,theVerticalResizeFactor);
theHorizontalResizeFactor = theResizeFactor;
theVerticalResizeFactor = theResizeFactor;
theDesiredWidth = (int)((double)0.5 +
(double)mImage->GetWidth()*theResizeFactor);
theDesiredHeight = (int)((double)0.5 +
(double)mImage->GetHeight()*theResizeFactor);
}
// create a resized copy of the original
Gdiplus::Bitmap* theResizedImage(new
Gdiplus::Bitmap(theDesiredWidth,theDesiredHeight,PixelFormat24bppRGB) );
Gdiplus::Graphics theResizer(theResizedImage);
Gdiplus::Status theStatus = theResizer.SetInterpolationMode(
Gdiplus::InterpolationModeNearestNeighbor);
theStatus = theResizer.SetSmoothingMode(Gdiplus::SmoothingModeNone);
if( theStatus != Gdiplus::Ok )
{
delete theResizedImage;
return NULL;
}
theResizer.DrawImage(mImage, Gdiplus::Rect( 0, 0,
theDesiredWidth, theDesiredHeight ) );
return theResizedImage;
****
I read the documents and it said that it created a stream with an empty buffer. I did not
see where Save would extend the buffer, or Write.would extend it, if it was a memory
stream (this would be implicit if it were on a disk device, but nothing about Write
suggests that the stream object will be increased in size. So I'd be inclined to believe
that it was too small. But failure to check the result codes of the operations means that
you really don't have a clue. Also, did you seek back to the beginning before trying to
re-read it?
****
>
>5.
>> ****
>> >bitmap->Save(buffer,&m_bmpClsid,NULL);
>> ****
>> If we knew the type of 'bitmap', which is NOT an HBITMAP, or a CBitmap, it might be
>> possible to offer an opinion on this; why did you not bother to show what this declaration
>> is?
>As said before, I didn’t know more than GDIPluss Bitmap classes existed. My
>apologies on this people.
>6.
>> Of course, you DID check the return value, didn't you? So you KNOW that this operation
>> succeeded, right? So you know it returned the Status value Ok, and not, for example,
>> InvalidParameter, OutOfMemory, InsufficientBuffer, Win32Error, ValueOverflow, or some
>> other value that might indicate that the operation failed. Right?
>
>Ofcourse I did… I am beginner in all these, but I do debug the applications
>I create…
****
No code was shown that tests this, and we can only trust that the example you show is the
actual code that was used.
****
****
It *is* poorly documented, but when MFC throws an exception, it throws a subclass of
CException*, and the documentation is very imprecise about this. In MFC, the generic
exception class is CException, and you derive your own exception subclasses from
CException, such as
class CMyGeneralException : public CException {...};
or
class CMySpecificExceptionAboutThis : public CMyGeneralException {...};
class CMySpecificExceptionAboutThat : public CMyGeneralException {...};
or
class CMyReallyPreciseExceptionAboutThat : public CMySpecificExceptionAboutThat {...};
class CMyOtherPreciseExceptionAboutThat :public CMySpecificExceptionAboutThat {...};
where the ... can include public methods such as constructors with parameters, protected
member variables, public methods for retrieving the contents of those variables, etc.
for example
class CSyntaxError : public CException {
public:
CSyntaxError(int L, int Off) { Line = L; Offset = Off; }
CString where() { CString s; s.Format(_T("(%d) [%d]"), Line, Offset);
int GetLine() {return Line; }
int GetOffset() { return Offset; }
virtual CString GetText() PURE;
protected:
int Line;
int Offset;
};
class CMissingSemicolon : public CSyntaxError {
public:
CMissingSemicolon(int L, int Off) : CSyntaxError(L, Off) { }
virtual CString GetText() {
CString msg;
msg.LoadString(IDS_MISSING_SEMICOLON);
msg += where();
return msg;
}
};
class CUnknownIdentifier : public CSyntaxError {
public:
CUnknownIdentifier(int L, int Off, const CString & id) :
CSyntaxError(L, Off) { Name = id; }
virtual String GetText() {
CString fmt;
fmt.LoadString(IDS_UNKNOWN_IDENTIFIER);
CString msg;
msg.Format(fmt, where(), Name);
return msg;
}
};
if(Lookup(id) == NULL)
{ /* unknown ID */
throw new CUnknownIdentifier(Line, Offset, id);
} /* unknown ID */
try {
Parse(inputstring);
}
catch(CSyntaxError * e)
{
CString msg = e->GetText();
...show error messge
e->Delete();
}
This is the standard technique. MFC actually has a "catch(CException * e)" in its basic
message dispatcher so uncaught exceptions will eventually be caught there, and it issues a
MessageBox about an error occurring (unfortunately, it does not provide any useful
information)
****
>>
>> Hint: you did not give sufficient information to tell what the code is doing, you wrote
>> code that doesn't test for or report error conditions, you use vague and meaningless
>> descriptions of what are very specific events ("an" exception); none of which is going to
>> help diagnose the problem.
>>
>> What did you do wrong? Failed to specify all the values and their types, failed to read
>> the documentation, failed to test return values, failed to report error conditions in a
>> way that would make them useful.
>
>You are correct. Sorry for this. Hopefully I made things more clear now. I
>just hope though you do understand it is not as easy when someone that has
>only one month of programming in c++ to understand entirely what he needs to
>mention to get help easily form others.
****
It is the same in all languages, in all situations. No handwaves; provide all useful
information. I don't care if it is COBOL, VB, C#, Pascal, or any of three hundred other
possible languages; saying "I did something and it failed" is not helpful. We want to
help, but we can't if you don't tell us what you are seeing, and the text of error
messages is really, really critical (we often get people posting some source code, and say
"I get an C1042 error compiling this", as if we have a clue as to what C1042 has. When we
say "show the error message" they will show the actual text, which says there is an error
on line 281, but they don't indicate which of the 40 lines shown is line 281, or show any
of the declarations that are involved, which are usually what trigger the error anyway.
Complete descriptions are critical to getting help
****
>a. I couldn’t catch the exception
****
It depends on what you mean by "exception", for example. Beginners often confuse ASSERT
statements with exceptions, and there two kinds of exceptions: C++ exceptions, which in
MFC are subclasses of CException, and hardware exceptions such as access fault, which are
outside the C++ exception mechanism unless you do massive magic
****
>b. I thought GDIPlus was the only tool for me to use (do be frunk I didn’t
>even bother to think of it).
****
GDI+ is perfectly reasonable, especially if you are using JPEG, GIF, and other formats,
because they are nicely integrated into the libraries. Nothing wrong with choosing it,
but it is important to know that you *are* using it.
****
>c. I did the check until making my code to work only with breakpoints and
>although before posting I should have made the code easier to trace, I
>didn’t, thinking that actual GDI and C++ experts would find it easy to find
>my error.
****
No, because you didn't say what the return results of those calls were. If you had said
"I looked at the return values, and they were correct; I got Ok for this, and the expected
0 for that, and the expected byte count for this other" then we know you have exhausted
the expected problems, and in fact we might go off and try to reproduce the problem so we
can see if we understand it. But when you show code that doesn't follow the
documentation, don't say what happened in terms of each of the calls involved, and use
vauge terms that don't tell us in any way what happened, it is hard to offer any advice.
We can help you only if you tell us what is really going on, and demonstrate that you have
verified that, as best you understand what is going on, all the calls appear to have
succeeded. There might *well* be a bug in the libraries, but I'm not going to hare off
and look for a bug unless I know you have validated that every operation you did claims to
have succeeded. At that point, then I know that you have done everything you can in
accordance with the specifications, and it didn't work. This might indicate a bug in the
documentation, or a bug in your logic, or a bug in the libraries, and we'll help track it
down if we can. But slapping up a piece of code that says it allocates a 0-size buffer,
telling us you got 0 bytes back, and not indicating that you made any effort to see what
went wrong by reporting what the results of the calls were suggests that you have not been
careful enough in analyzing the problem at the most superficial level. And I'm not going
to do first-cut debugging of the obvious, even for a beginner. But if you report that
everything worked *correctly*, then I quite possibly will find the time to look for what
went wrong, because I know you did everything that you could be expected to do, and
therefore as far as you can tell, your code is correct, and something else is wrong. We'll
certainly help in isolating that something else, or have some idea about what we might
look for. But what I saw was essentially untested code that was not known to work in the
first place (no checks on function results is the major clue here).
joe
****