How to stretch a bitmap with SECDib from stingray or "usual" CDC?

Hi,

I am using stingray Objective toolkit to quickly build a demo... But it
turns out what should be simple doesn't work! I need to create
a "thumbnail" or a small bitmap by stretching a "regular" bitmap
from 1024X768 to about 100X80...

Here is the code I use:
dim.cx= ret->m_dwWidth;
dim.cy= retl->m_dwHeight;
CClientDC dc(pApp->m_pMainWnd);  
SECDib* ret= new SECDib();
ASSERT(ret->LoadBitmap(IDC_BITMAP1));

ASSERT(ret->StretchDIBits(&dc, 0,0,100,80,
                        0,0,dim.cx,dim.cy,                                                              ret->m_lpSrcBits,ret->m_lpBMI,DIB_RGB_COLORS,SRCCOPY));
ret->SaveImage(dest);

This works... EXCEPT that the bitmap is NOT stretched at all!!!
What is savec in file "dest" is a copy of the original bitmap NOT a stretched
one!!!!

I tried with "regular" CBitmap* and StretchBlt from CDC, but the size
also remains the same after or before the "stretch"!!! It shouldn't be
all that hard to stretch a stupid bitmap! Does any one out there has
a simple recipe to do it? An  no-miss way to code this bitmap stretching
function (with ou without SECDib)...

Thanks in advance ;-)

Th
LVL 2
aquila98Asked:
Who is Participating?

[Webinar] Streamline your web hosting managementRegister Today

x
 
nietodConnect With a Mentor Commented:
>> In your BITMAPINFOHEADER of your bitmap,
>> make sure you have the compression set to
>> a value that supports compression.
That controls if the image is stored using a data compression algorithm.  It has nothing to do with scaling.

>> But when ever I try to save it to a file, what's
>> being  saved is the whole image NOT the
>> stretched one!!!
That is because you are saving the original image.  As I said, StretchDIBits() doesn't change the original image, it changes the destination.

What you need to do is create a new bitmap of the size you want to save.   Create a memory DC and select this bitmap into it.  StretchDIBits() the image to this memory DC.  Then save this new bitmap instead of the original bitmap.

Let me know if you have any questions.
0
 
chensuCommented:
The code won't be executed in the release version if you use ASSERT. Use VERIFY instead.
0
 
nietodCommented:
Also another potential problem (I don't know enough about SecDIB to know if it is a problem)

The StretchDIBits() function does not (most likely) alter the source DIB (ret in your case).  It should just copy the bitmap to the destination DC (dc in your case) and scale it in the destination DC.  The oriiginal is unchanged, the destination receives a scalled copy.
0
The new generation of project management tools

With monday.com’s project management tool, you can see what everyone on your team is working in a single glance. Its intuitive dashboards are customizable, so you can create systems that work for you.

 
GlennDeanCommented:
aquila98:
   In your BITMAPINFOHEADER of your bitmap, make sure you have the compression set to a value that supports compression.  IF it ain't right, then no compression takes place (probably what's happening to you).  You will most likely have problems if the compression isn't set to BI_RLE8 or BI_RLE4.
   Glenn
0
 
aquila98Author Commented:
NOP!

All this is fine and dandy!
But I CAN stretch a bitmap! I see it in a small
window! As lons as I paint it its ok I see it stretched!!!
But when ever I try to save it to a file, what's being
saved is the whole image NOT the stretched one!!!

Why were they so stupid as to require a CDC
whenever one wants to stretch a bitmap! I don't
want to display it just stretch it and save in
on disc!

How can I take it from the CDC and save it
to disk????

No reason such a simple task should be so
complicated! What is it with those bitmaps
that's so complicated in MFC???

Anyway thanks your input!
0
 
aquila98Author Commented:
OK.

So far, I have seen that StretchDIBits() stretches
nothing that is not in the DC (not displayed)
(why haven't they called StretchDIBitsInDC() ???)

<What you need to do is create a new bitmap of the size
<you want to  save.   Create a memory DC and select this
<bitmap into it.  StretchDIBits() the  image to this memory
<DC.  Then save this new bitmap instead of the original
< bitmap.

You mean some thing like this with CBitmap* FullSizeBMP:

CBitmap* smallBMP= CreateBitmap( 100, 90,
 UINT nPlanes, UINT nBitcount, const void* lpBits );
(where are lpBits comming from??? the bitmaps
in the DC I guess??? And how to retrieve them from
the DC????)

save smallBMP????
0
 
nietodCommented:
>> (why haven't they called StretchDIBitsInDC() ???)
You must be very new to windows, if you are complaining about unclear names in the API.  They have the longest names in the world and still half of them are unclear.

However, in windows all drawing operations are carried out in a DC.  So if you need to stretch a bitmap, you have to copy it to a DC, then retreive it again.  This is true of any drawing operation.  If you don't wnat these oprations to be visible, they you do it using a memory DC which operates on a memory bitmap.  (If you do it with a device DC, the operation affects the device, so the process is vissible.)

>> You mean some thing like this
Yes.

>> where are lpBits comming from
Nowhere.  You don't have an inital value to specify, so pass NULL.  Then the bitmap produced will be full of garbage.  No problem, you are going to overwrite it with the scaled image of the other bitmap.

>> And how to retrieve them from
>> the DC??
You already have the bitmap, you don't need to retreive it.  But you do need to make the memory DC use that bitmap.  To do this you use SelectObject() to select your bitmap into the memory DC.  Note that you must save the bitmap pointer returns by this call  (very important).  Then perform your drawing operation.  This will change the image in the bitmap you created.  Then when you are done drawing, you must select the original bitmap (the one saved above) back into the memory DC (otherwise you cause a memory leak..)    


Note, depending on your needs, you may wish to use CreateComaptibleBitmap() instead of CreateBitMap().
0
 
aquila98Author Commented:
Hmmmmmmmmm!

So here is the pseudo code:

CDC memDC;  
memDC.CreateCompatibleDC(AfxGetMainWnd()->GetDC());
// I use any DC since I don't need it anyway??? ok???

I select my bmp into this dc...

CBitmap* old= memDC.SelectObject(FillSizeBMP);
stretchit(memDC);
CBitmap* newBMP;
newBMP->CreateCompatibleBitmap(&memDC, 100, 90);

and how newBMP is to obtain the data that is kept into
the DC???

memDC.SelectObject(old);
DeleteDC(&memDC);

There is probably something wrong in the sequencing of
these operations ;-) but what?

thanks for you efforts!
0
 
nietodCommented:
>> // I use any DC since I don't need it anyway??? ok???
Okay in this case because you are goign to save the results in a deice-independant way.  If you wanted to display the results you would have to use a DC compatible with the device on which you were going to display, like the screen or a specific printer.

>> CBitmap* old= memDC.SelectObject(FillSizeBMP);
>> stretchit(memDC);
>> CBitmap* newBMP;
>> newBMP->CreateCompatibleBitmap(&memDC, 100, 90);
This isn't right.

You will create the new bitmap of the desired final dimensions, then select that into the memory DC.  Then stretchblt() the image to this memory DC

CBitmap* newBMP;
newBMP->CreateCompatibleBitmap(&memDC, 100, 90);
CBitmap* old= memDC.SelectObject(newBMP);
stretchit(memDC);

>> and how newBMP is to obtain the data
>> that is kept into the DC???
The memory DC has a handle to the bitmap you created.  When you draw to the DC it draws to the bitmap you created.  That is what a memory DC is.  It is a DC that draws to a bitmap.


Also don't forget at the end to delete the bitmap you created.
0
 
aquila98Author Commented:
It's getting there!!!

but as is the createcompatiblebitmap fails with an
assert m_hObject != NULL...

Here is the complete code:
SECImage* pFullSize=
                  SECImage::ParseImage(source.c_str());
SECDib* ret= new SECDib();
int i;
unsigned long s;
CDC memDC;  

    memDC.CreateCompatibleDC(AfxGetMainWnd()->GetDC());
     
//convert any format into BMP
ASSERT(ret->ConvertImage(pFullSize));
//Original bitmap dimension
dim.cx= pThumbnail->m_dwWidth;
dim.cy= pThumbnail->m_dwHeight;
//Obtain destination rectangle dimension
RECT rcItem= _StretchIt(dim);

//try and stretch it
CBitmap* newBmp= NULL;

//BANG! assert violation here
newBmp->CreateCompatibleBitmap(&memDC,
      rcItem.right-rcItem.left, rcItem.bottom-rcItem.top);

I guess my DC is not good?

Looking into StretchBlt(hDC,...,dcmem,...,SRCCOPY);
there is a sourcd DC and a destination DC...
Does this means that I should use TWO mem dc?
like
pSmallBitmap->CreateCompatibleBitmap(&memDC, ...);
CBitmap* old1= memDC1.SelectObject(pSmallBitmap);
CBitmap* old2= memDC2.SelectObject(pFullsize);
   StretchBlt(memDC1,m_hDC,left,top,right-left,bottom-top,
                 memDC2,0,0,cy,cx,SRCCOPY);

Would this make sense????

0
 
nietodCommented:
I think that
 
>>  memDC.CreateCompatibleDC(AfxGetMainWnd()->GetDC());

is a mistake.  That will cause a memory leak.  The DC returned by GetDC() needs to be released.  But because you don't save the pointer to the DC so you can't release it.    (I think, I don't use MFC.)

However, if you just want a DC compatible with the screen, you can just passs NULL to CreateCompatibleDC(), so do that as it is easier than creating and deleting a DC just to create another.

>> //BANG! assert violation here
>> newBmp->CreateCompatibleBitmap(&memDC,
>> rcItem.right-rcItem.left, rcItem.bottom-rcItem.top);
Is the memDC's m_hDC set?

There is another problem there.  The bitmap created has the same color format as the bitmap in the DC specified in the 1st parameter.  Unfortunately when you first create a memory DC it has a moniochrome bitmap in it.  So the bitmap you are creating will be monochrome too.  You probably don't wnat that.  So for this, you might want to use CreateBitmap() to have more control over the color format.  In some cases--probalby not this one--you would use GetCompatibleBitmp() to create a bitmap that is compatible with some device DC, like the screen or printer.  Then you select this bitmap into the memory DC.  i.e. the memory DC gets the bitmap, but the bitmap was not created using the memory DC.

>> Looking into StretchBlt(hDC,...,dcmem,...,SRCCOPY);
>> there is a sourcd DC and a destination DC...
>> Does this means that I should use TWO mem dc?
StretchBlt() does require two DCs.  You would have to select the unscalled bitmap into a source DC and then StretchBlt() the image from the source DC to the destination DC.  

However, I you were using some StretchDIBits() function.  That probably does not require a source DC, only a destination one.  So that is probably easier.  (But I'm not sure what class this is a member of to find the details, but you probably know.  (again, I don't use MFC.))
0
 
aquila98Author Commented:
Thank you!

You have been a great help!!!

I had figured this should take me a couple of hours
tops!!! Its been days! Why make it simple hey?

thanks again, you've earned your points ;-)
0
All Courses

From novice to tech pro — start learning today.