Solved

Bitmap resize

Posted on 2002-07-15
40
1,376 Views
Last Modified: 2013-12-03
Hi,

I wonder if you guys can help me out in an area I'm not so familiar with.

I need a *very fast* WIN32 function (no MFC or other heavy library) to resize an HBITMAP and return an new image as a new HBITMAP.

The exisiting WIN32 function StrechBlt does the job but does it very with very bad quality.

I mainly need it to reduce the size of a small bitmap, not bigger than 200x200 pixels, the smaller bitmap must be in good visual quality but does no have to be perfect.

It has to be fast since I plan to use it in real time to animate a bitmap in several sizes which I can only create on the fly.

I allready found some code snippetns on a newsgroup and it worked fine but it did not support 32-bit bitmaps with alpha channel information.

To summarize, I need a function that is :

1. Very fast
2. Support several bit depths including 32-bit (alpha channel)
3. No external libraries, need it to be slim.
4. take source WIN32 HBITMAP and return HBITMAP


your help is greatly appreciated,

thanks

Mike
0
Comment
Question by:moshem
  • 20
  • 19
40 Comments
 
LVL 23

Expert Comment

by:Roshan Davis
ID: 7156196
0
 
LVL 1

Author Comment

by:moshem
ID: 7156494
Hi,

thanks for answering, I have allready found and used this function and it works. I can't tell if it is fast enough, but I can tell you for sure that it does not support 32 bit BITMAPS.

Sadly, this area of computer programming is totaly new for me and I don't know how to convert this function to make it support 32-bit bitmaps as well as 24/16 bit bitmaps.

can you help ?
0
 
LVL 23

Expert Comment

by:Roshan Davis
ID: 7156502
Sure

1. You have to change biBitCount to 32

and other thing is specifying 3 in some place means 3 bytes , ie 24 bits.

If you need more information, I will give you....

I 'm looking in to the code

0
 
LVL 1

Author Comment

by:moshem
ID: 7156522
Yes,

I looked at the code myself and realized the points you mentioned but it looked too complicated for me to touch...

if you can help that would be great!
0
 
LVL 23

Expert Comment

by:Roshan Davis
ID: 7156592
Sure.
0
 
LVL 23

Expert Comment

by:Roshan Davis
ID: 7156615
looking...
0
 
LVL 23

Expert Comment

by:Roshan Davis
ID: 7156662
If you have time to wait 4 hours (after my office hours).. I can convert this into 32 bit
0
 
LVL 1

Author Comment

by:moshem
ID: 7156673
ok, that can be great.

just please make sure it is fast, and don't delete any exisiting functionalty, meaning leave the support for other depths. I don't mind if it will detect the depth of the HBITMAP handle and handle it accordingly.

thanks for your help!

Mike
0
 
LVL 23

Expert Comment

by:Roshan Davis
ID: 7156678
Sure
0
 
LVL 23

Expert Comment

by:Roshan Davis
ID: 7157402
Here it is,

Just Try it...

/////////////////////////////////////////////////////////////////////////////
// CDIBSectionTestView drawing

//
// Functions for smooth bitmap resize
//
// Improvement: float calculations changed to int.
//
// Ivaylo Byalkov, January 24, 2000
// e-mail: ivob@i-n.net
//

///////////////////////////////////////////////////////////

// helper function prototypes
static BITMAPINFO *PrepareRGBBitmapInfo(WORD wWidth,
                                        WORD wHeight);

static void ShrinkDataInt(BYTE *pInBuff,
                          WORD wWidth,
                          WORD wHeight,
                          BYTE *pOutBuff,
                          WORD wNewWidth,
                          WORD wNewHeight);

static void EnlargeDataInt(BYTE *pInBuff,
                           WORD wWidth,
                           WORD wHeight,
                           BYTE *pOutBuff,
                           WORD wNewWidth,
                           WORD wNewHeight);

///////////////////////////////////////////////////////////
// Main resize function

HBITMAP ScaleBitmapInt(HBITMAP hBmp,
                       WORD wNewWidth,
                       WORD wNewHeight)
{
 BITMAP bmp;
 ::GetObject(hBmp, sizeof(BITMAP), &bmp);

 // check for valid size
 if((bmp.bmWidth > wNewWidth
   && bmp.bmHeight < wNewHeight)
 || (bmp.bmWidth < wNewWidth
   && bmp.bmHeight > wNewHeight))
  return NULL;

 HDC hDC = ::GetDC(NULL);
 BITMAPINFO *pbi = PrepareRGBBitmapInfo((WORD)bmp.bmWidth,
                                        (WORD)bmp.bmHeight);
 BYTE *pData = new BYTE[pbi->bmiHeader.biSizeImage];

 ::GetDIBits(hDC, hBmp, 0, bmp.bmHeight, pData, pbi, DIB_RGB_COLORS);

 delete pbi;
 pbi = PrepareRGBBitmapInfo(wNewWidth, wNewHeight);
 BYTE *pData2 = new BYTE[pbi->bmiHeader.biSizeImage];

 if(bmp.bmWidth >= wNewWidth
 && bmp.bmHeight >= wNewHeight)
  ShrinkDataInt(pData,
                (WORD)bmp.bmWidth,
                (WORD)bmp.bmHeight,
                pData2,
                wNewWidth,
                wNewHeight);
 else
  EnlargeDataInt(pData,
                 (WORD)bmp.bmWidth,
                 (WORD)bmp.bmHeight,
                 pData2,
                 wNewWidth,
                 wNewHeight);

 delete pData;

 HBITMAP hResBmp = ::CreateCompatibleBitmap(hDC,
                                            wNewWidth,
                                            wNewHeight);

 ::SetDIBits(hDC,
             hResBmp,
             0,
             wNewHeight,
             pData2,
             pbi,
             DIB_RGB_COLORS);

 ::ReleaseDC(NULL, hDC);

delete pbi;
delete pData2;

return hResBmp;
}

///////////////////////////////////////////////////////////

BITMAPINFO *PrepareRGBBitmapInfo(WORD wWidth, WORD wHeight)
{
 BITMAPINFO *pRes = new BITMAPINFO;
 ::ZeroMemory(pRes, sizeof(BITMAPINFO));
 pRes->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
 pRes->bmiHeader.biWidth = wWidth;
 pRes->bmiHeader.biHeight = wHeight;
 pRes->bmiHeader.biPlanes = 1;
 pRes->bmiHeader.biBitCount = 32;

 pRes->bmiHeader.biSizeImage =
  ((4 * wWidth + 4) & ~4) * wHeight;
 
 return pRes;
}

///////////////////////////////////////////////////////////

static int *CreateCoeffInt(int nLen, int nNewLen, BOOL bShrink)
{
 int nSum = 0, nSum2;
 int *pRes = new int[2 * nLen];
 int *pCoeff = pRes;
 int nNorm = (bShrink)
           ? (nNewLen << 12) / nLen : 0x1000;
 int      nDenom = (bShrink)? nLen : nNewLen;

 ::ZeroMemory(pRes, 2 * nLen * sizeof(int));
 for(int i = 0; i < nLen; i++, pCoeff += 2)
 {
  nSum2 = nSum + nNewLen;
  if(nSum2 > nLen)
  {
   *pCoeff = ((nLen - nSum) << 12) / nDenom;
   pCoeff[1] = ((nSum2 - nLen) << 12) / nDenom;
   nSum2 -= nLen;
  }
  else
  {
   *pCoeff = nNorm;
   if(nSum2 == nLen)
   {
    pCoeff[1] = -1;
    nSum2 = 0;
   }
  }
  nSum = nSum2;
 }
 
 return pRes;
}

///////////////////////////////////////////////////////////

void ShrinkDataInt(BYTE *pInBuff,
                   WORD wWidth,
                   WORD wHeight,
                   BYTE *pOutBuff,
                   WORD wNewWidth,
                   WORD wNewHeight)
{
 BYTE  *pLine = pInBuff, *pPix;
 BYTE  *pOutLine = pOutBuff;
 DWORD dwInLn = (4 * wWidth + 4) & ~4;
 DWORD dwOutLn = (4 * wNewWidth + 4) & ~4;
 int   x, y, i, ii;
 BOOL  bCrossRow, bCrossCol;
 int   *pRowCoeff = CreateCoeffInt(wWidth,
                                   wNewWidth,
                                   TRUE);
 int   *pColCoeff = CreateCoeffInt(wHeight,
                                   wNewHeight,
                                   TRUE);
 int   *pXCoeff, *pYCoeff = pColCoeff;
 DWORD dwBuffLn = 4 * wNewWidth * sizeof(DWORD);
 DWORD *pdwBuff = new DWORD[8 * wNewWidth];
 DWORD *pdwCurrLn = pdwBuff,
       *pdwCurrPix,
       *pdwNextLn = pdwBuff + 4 * wNewWidth;
 DWORD dwTmp, *pdwNextPix;

 ::ZeroMemory(pdwBuff, 2 * dwBuffLn);

 y = 0;
 while(y < wNewHeight)
 {
  pPix = pLine;
  pLine += dwInLn;

  pdwCurrPix = pdwCurrLn;
  pdwNextPix = pdwNextLn;

  x = 0;
  pXCoeff = pRowCoeff;
  bCrossRow = pYCoeff[1] > 0;
  while(x < wNewWidth)
  {
   dwTmp = *pXCoeff * *pYCoeff;
   for(i = 0; i < 4; i++)
    pdwCurrPix[i] += dwTmp * pPix[i];
   bCrossCol = pXCoeff[1] > 0;
   if(bCrossCol)
   {
    dwTmp = pXCoeff[1] * *pYCoeff;
    for(i = 0, ii = 4; i < 4; i++, ii++)
     pdwCurrPix[ii] += dwTmp * pPix[i];
   }
   if(bCrossRow)
   {
    dwTmp = *pXCoeff * pYCoeff[1];
    for(i = 0; i < 4; i++)
     pdwNextPix[i] += dwTmp * pPix[i];
    if(bCrossCol)
    {
     dwTmp = pXCoeff[1] * pYCoeff[1];
     for(i = 0, ii = 4; i < 4; i++, ii++)
      pdwNextPix[ii] += dwTmp * pPix[i];
    }
   }
   if(pXCoeff[1])
   {
    x++;
    pdwCurrPix += 4;
    pdwNextPix += 4;
   }
   pXCoeff += 2;
   pPix += 4;
  }
  if(pYCoeff[1])
  {
   // set result line
   pdwCurrPix = pdwCurrLn;
   pPix = pOutLine;
   for(i = 4 * wNewWidth; i > 0; i--, pdwCurrPix++, pPix++)
    *pPix = ((LPBYTE)pdwCurrPix)[3];

   // prepare line buffers
   pdwCurrPix = pdwNextLn;
   pdwNextLn = pdwCurrLn;
   pdwCurrLn = pdwCurrPix;
   ::ZeroMemory(pdwNextLn, dwBuffLn);

   y++;
   pOutLine += dwOutLn;
  }
  pYCoeff += 2;
 }

 delete [] pRowCoeff;
 delete [] pColCoeff;
 delete [] pdwBuff;
}

///////////////////////////////////////////////////////////

void EnlargeDataInt(BYTE *pInBuff,
                    WORD wWidth,
                    WORD wHeight,
                    BYTE *pOutBuff,
                    WORD wNewWidth,
                    WORD wNewHeight)
{
 BYTE  *pLine = pInBuff,
       *pPix = pLine,
       *pPixOld,
       *pUpPix,
       *pUpPixOld;
 BYTE  *pOutLine = pOutBuff, *pOutPix;
 DWORD dwInLn = (4 * wWidth + 4) & ~4;
 DWORD dwOutLn = (4 * wNewWidth + 4) & ~4;
 int   x, y, i;
 BOOL  bCrossRow, bCrossCol;
 int   *pRowCoeff = CreateCoeffInt(wNewWidth,
                                   wWidth,
                                   FALSE);
 int   *pColCoeff = CreateCoeffInt(wNewHeight,
                                   wHeight,
                                   FALSE);
 int   *pXCoeff, *pYCoeff = pColCoeff;
 DWORD dwTmp, dwPtTmp[4];

 y = 0;
 while(y < wHeight)
 {
  bCrossRow = pYCoeff[1] > 0;
  x = 0;
  pXCoeff = pRowCoeff;
  pOutPix = pOutLine;
  pOutLine += dwOutLn;
  pUpPix = pLine;
  if(pYCoeff[1])
  {
   y++;
   pLine += dwInLn;
   pPix = pLine;
  }

  while(x < wWidth)
  {
   bCrossCol = pXCoeff[1] > 0;
   pUpPixOld = pUpPix;
   pPixOld = pPix;
   if(pXCoeff[1])
   {
    x++;
    pUpPix += 4;
    pPix += 4;
   }
   
   dwTmp = *pXCoeff * *pYCoeff;
   
   for(i = 0; i < 4; i++)
    dwPtTmp[i] = dwTmp * pUpPixOld[i];
   
   if(bCrossCol)
   {
    dwTmp = pXCoeff[1] * *pYCoeff;
    for(i = 0; i < 4; i++)
    dwPtTmp[i] += dwTmp * pUpPix[i];
   }

   if(bCrossRow)
   {
    dwTmp = *pXCoeff * pYCoeff[1];
    for(i = 0; i < 4; i++)
    dwPtTmp[i] += dwTmp * pPixOld[i];
    if(bCrossCol)
    {
     dwTmp = pXCoeff[1] * pYCoeff[1];
     for(i = 0; i < 4; i++)
     dwPtTmp[i] += dwTmp * pPix[i];
    }
   }
   
   for(i = 0; i < 4; i++, pOutPix++)
    *pOutPix = ((LPBYTE)(dwPtTmp + i))[3];
   
   pXCoeff += 2;
  }
  pYCoeff += 2;
 }

 delete [] pRowCoeff;
 delete [] pColCoeff;
}
0
 
LVL 1

Author Comment

by:moshem
ID: 7157441
Hi,


I tested it with 32 bit bitmaps and it works, thank you, good work!

The points are yours...

The only cavet is I think it is a little slow for my purposes, maybe you can take a second look at it to see if speed can be improved somehow...

if you can't improve speed, just let me know that you give up and I'll credit you with the points.

again...

thanks you!


Mike
0
 
LVL 23

Expert Comment

by:Roshan Davis
ID: 7157467
I just tried to set 3 for all the loop final value to 3 (changed 1<4 to i<3), doesn't found any clarity change...

Try it, if it doesn't make any difference, you can adopt that...

This is just a guess..

Just like....

void ShrinkDataInt(BYTE *pInBuff,
                   WORD wWidth,
                   WORD wHeight,
                   BYTE *pOutBuff,
                   WORD wNewWidth,
                   WORD wNewHeight)
{
 BYTE  *pLine = pInBuff, *pPix;
 BYTE  *pOutLine = pOutBuff;
 DWORD dwInLn = (4 * wWidth + 4) & ~4;
 DWORD dwOutLn = (4 * wNewWidth + 4) & ~4;
 int   x, y, i, ii;
 BOOL  bCrossRow, bCrossCol;
 int   *pRowCoeff = CreateCoeffInt(wWidth,
                                   wNewWidth,
                                   TRUE);
 int   *pColCoeff = CreateCoeffInt(wHeight,
                                   wNewHeight,
                                   TRUE);
 int   *pXCoeff, *pYCoeff = pColCoeff;
 DWORD dwBuffLn = 4 * wNewWidth * sizeof(DWORD);
 DWORD *pdwBuff = new DWORD[8 * wNewWidth];
 DWORD *pdwCurrLn = pdwBuff,
       *pdwCurrPix,
       *pdwNextLn = pdwBuff + 4 * wNewWidth;
 DWORD dwTmp, *pdwNextPix;

 ::ZeroMemory(pdwBuff, 2 * dwBuffLn);

 y = 0;
 while(y < wNewHeight)
 {
  pPix = pLine;
  pLine += dwInLn;

  pdwCurrPix = pdwCurrLn;
  pdwNextPix = pdwNextLn;

  x = 0;
  pXCoeff = pRowCoeff;
  bCrossRow = pYCoeff[1] > 0;
  while(x < wNewWidth)
  {
   dwTmp = *pXCoeff * *pYCoeff;
   for(i = 0; i < 3; i++)
    pdwCurrPix[i] += dwTmp * pPix[i];
   bCrossCol = pXCoeff[1] > 0;
   if(bCrossCol)
   {
    dwTmp = pXCoeff[1] * *pYCoeff;
    for(i = 0, ii = 4; i < 3; i++, ii++)
     pdwCurrPix[ii] += dwTmp * pPix[i];
   }
   if(bCrossRow)
   {
    dwTmp = *pXCoeff * pYCoeff[1];
    for(i = 0; i < 3; i++)
     pdwNextPix[i] += dwTmp * pPix[i];
    if(bCrossCol)
    {
     dwTmp = pXCoeff[1] * pYCoeff[1];
     for(i = 0, ii = 4; i < 3; i++, ii++)
      pdwNextPix[ii] += dwTmp * pPix[i];
    }
   }
   if(pXCoeff[1])
   {
    x++;
    pdwCurrPix += 4;
    pdwNextPix += 4;
   }
   pXCoeff += 2;
   pPix += 4;
  }
  if(pYCoeff[1])
  {
   // set result line
   pdwCurrPix = pdwCurrLn;
   pPix = pOutLine;
   for(i = 4 * wNewWidth; i > 0; i--, pdwCurrPix++, pPix++)
    *pPix = ((LPBYTE)pdwCurrPix)[3];

   // prepare line buffers
   pdwCurrPix = pdwNextLn;
   pdwNextLn = pdwCurrLn;
   pdwCurrLn = pdwCurrPix;
   ::ZeroMemory(pdwNextLn, dwBuffLn);

   y++;
   pOutLine += dwOutLn;
  }
  pYCoeff += 2;
 }

 delete [] pRowCoeff;
 delete [] pColCoeff;
 delete [] pdwBuff;
}


Good Luck
0
 
LVL 1

Author Comment

by:moshem
ID: 7157477
I'm sorry but I have zero understaning of this code, do you mean that this latest update may result in faster performence ?
0
 
LVL 23

Expert Comment

by:Roshan Davis
ID: 7157491
Yes, please replace this function with the same prev. function. If you didn't find any clarity difference, you can use this, this may be much faster.

You can test it with GetTickCount() function.
Roshmon
0
 
LVL 1

Author Comment

by:moshem
ID: 7157532
I tried both versios :

1) The second version does not work, all I get is white solid shape of my bitmap , look like only the alpha channel.

2) I tried mesauring it uning GetTickCount and in both instances got 10ms, how is that possible ?

BTW,

will this resize function work with non 32-bit bitmaps ?
0
 
LVL 23

Expert Comment

by:Roshan Davis
ID: 7157533
>> The points are yours...

can you rate the comment now ?
Or more doubts ?

Regards
Roshmon
0
 
LVL 1

Author Comment

by:moshem
ID: 7157541
Hi,

I promised you the points and an "A" grade, but please take a look on my last comments, we seem to have a problem
0
 
LVL 23

Expert Comment

by:Roshan Davis
ID: 7157546
>> will this resize function work with non 32-bit bitmaps ?
for that, need customization of function

making 16, 24 32 are simple...

All are almost same...

But for 8 bit some slight changes are there.... Need to handle palettes

Roshmon
0
 
LVL 1

Author Comment

by:moshem
ID: 7157558
Can you just guide me through what is needed to customize the function to use 16,24 bit depth ? in simple language please since I know nothing on computer graphics.

BTW,

you do realize that the new & improved Shring... function does not work ? see my comment above.
0
 
LVL 23

Expert Comment

by:Roshan Davis
ID: 7157560
Compare with StretchBlt,
I think that API also take around this much time...becoz the size of bits increased..

0
Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

 
LVL 23

Expert Comment

by:Roshan Davis
ID: 7157570
We can categorize bitmaps with BPP - BitsPerPixel
2 bpp
4 bpp
8 bpp
16 bpp
24 bpp
32 bpp

U know the basic colors are RGB. right ?
The idea windows keeps the color is keeping each pixels color value to this bpp.
That is a 24 bpp bitmap, 1 Pixel color informatio stores like 8bitR,8bitG,8bitB.

Similarly in 16 5bitR6bitG, 5bitB

But in the case of 8 bit bitmap, the bits are insufficient to keep the colors. So in this type bitmap, The starting of the bitmap contains 256 color or less. The remaining bits of the bitmap contains its color index. THis is named RGBQUAD array - The color indexes, these also called as Palletes.

So only 8 bit bitmaps have the pallete information.

In windows, that have 8 bit resolution, these 8 bit bitmaps may make problems like
Each window carrying the system palletes ( that is, the windows generally using colors like grey etc. 22 colors are normally taken by windows ) .
If u are displaying a bitmap of 8 bit in a window, u should have to get the pallets from the bitmap and should RealizeBitmap to the window

I think this may help u

GOOD LUCK
0
 
LVL 1

Author Comment

by:moshem
ID: 7157571
Hi,

I think you missed that :

I tried both versios :

1) The second version does not work, all I get is white solid shape of my bitmap , look like only the alpha channel.

and this :

Can you just guide me through what is needed to customize the function to use 16,24 bit depth ? in simple language please since I know nothing on computer graphics.



please comment on both issues...

thanks,

BTW, is it possible to give you the points and still exchange comments until we resolved it completly ( I trust you ;-)  ) ??


0
 
LVL 23

Expert Comment

by:Roshan Davis
ID: 7157572
The second version is just a guess...

0
 
LVL 23

Accepted Solution

by:
Roshan Davis earned 400 total points
ID: 7157588
>> BTW, is it possible to give you the points and still exchange comments until we resolved it completly ( I trust you ;-)  ) ??

Sure,
you can add comments here or
you can mail me to roshan_davis@hotmail.com
I'm available for your help.

I'm from india and 10:55 PM now...

Regards
0
 
LVL 1

Author Comment

by:moshem
ID: 7157601
Ok ,

I promised it to you, so there you are...

now,

Can you just guide me through what is needed to customize the function to use 16,24 bit depth ? in simple language please since I know nothing on computer graphics, thanks!
0
 
LVL 23

Expert Comment

by:Roshan Davis
ID: 7157662
This will work for 24 bit and for 32 bit...

/////////////////////////////////////////////////////////////////////////////
// CDIBSectionTestView drawing

//
// Functions for smooth bitmap resize
//
// Improvement: float calculations changed to int.
//
// Ivaylo Byalkov, January 24, 2000
// e-mail: ivob@i-n.net
//

///////////////////////////////////////////////////////////

// helper function prototypes
static BITMAPINFO *PrepareRGBBitmapInfo(WORD wWidth,
                                        WORD wHeight,
                                                            int nBPP);

static void ShrinkDataInt(BYTE *pInBuff,
                          WORD wWidth,
                          WORD wHeight,
                          BYTE *pOutBuff,
                          WORD wNewWidth,
                          WORD wNewHeight);

static void EnlargeDataInt(BYTE *pInBuff,
                           WORD wWidth,
                           WORD wHeight,
                           BYTE *pOutBuff,
                           WORD wNewWidth,
                           WORD wNewHeight);

int g_nVal;


///////////////////////////////////////////////////////////
// Main resize function

HBITMAP ScaleBitmapInt(HBITMAP hBmp,
                       WORD wNewWidth,
                       WORD wNewHeight,
                                 int nBPP)
{

switch(nBPP)
{
case 24:
      g_nVal = 3;
      break;
case 32:
      g_nVal = 4;
}
 BITMAP bmp;
 ::GetObject(hBmp, sizeof(BITMAP), &bmp);

 // check for valid size
 if((bmp.bmWidth > wNewWidth
   && bmp.bmHeight < wNewHeight)
 || (bmp.bmWidth < wNewWidth
   && bmp.bmHeight > wNewHeight))
  return NULL;

 HDC hDC = ::GetDC(NULL);
 BITMAPINFO *pbi = PrepareRGBBitmapInfo((WORD)bmp.bmWidth,
                                        (WORD)bmp.bmHeight,
                                                            nBPP);
 BYTE *pData = new BYTE[pbi->bmiHeader.biSizeImage];

 ::GetDIBits(hDC, hBmp, 0, bmp.bmHeight, pData, pbi, DIB_RGB_COLORS);

 delete pbi;
 pbi = PrepareRGBBitmapInfo(wNewWidth, wNewHeight, nBPP);
 BYTE *pData2 = new BYTE[pbi->bmiHeader.biSizeImage];

 if(bmp.bmWidth >= wNewWidth
 && bmp.bmHeight >= wNewHeight)
  ShrinkDataInt(pData,
                (WORD)bmp.bmWidth,
                (WORD)bmp.bmHeight,
                pData2,
                wNewWidth,
                wNewHeight);
 else
  EnlargeDataInt(pData,
                 (WORD)bmp.bmWidth,
                 (WORD)bmp.bmHeight,
                 pData2,
                 wNewWidth,
                 wNewHeight);

 delete pData;

 HBITMAP hResBmp = ::CreateCompatibleBitmap(hDC,
                                            wNewWidth,
                                            wNewHeight);

 ::SetDIBits(hDC,
             hResBmp,
             0,
             wNewHeight,
             pData2,
             pbi,
             DIB_RGB_COLORS);

 ::ReleaseDC(NULL, hDC);

delete pbi;
delete pData2;

return hResBmp;
}

///////////////////////////////////////////////////////////

BITMAPINFO *PrepareRGBBitmapInfo(WORD wWidth, WORD wHeight, int nBPP)
{
 BITMAPINFO *pRes = new BITMAPINFO;
 ::ZeroMemory(pRes, sizeof(BITMAPINFO));
 pRes->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
 pRes->bmiHeader.biWidth = wWidth;
 pRes->bmiHeader.biHeight = wHeight;
 pRes->bmiHeader.biPlanes = 1;
 pRes->bmiHeader.biBitCount = nBPP;

 pRes->bmiHeader.biSizeImage =
  ((g_nVal * wWidth + g_nVal ) & ~g_nVal ) * wHeight;
 
 return pRes;
}

///////////////////////////////////////////////////////////

static int *CreateCoeffInt(int nLen, int nNewLen, BOOL bShrink)
{
 int nSum = 0, nSum2;
 int *pRes = new int[2 * nLen];
 int *pCoeff = pRes;
 int nNorm = (bShrink)
           ? (nNewLen << 12) / nLen : 0x1000;
 int      nDenom = (bShrink)? nLen : nNewLen;

 ::ZeroMemory(pRes, 2 * nLen * sizeof(int));
 for(int i = 0; i < nLen; i++, pCoeff += 2)
 {
  nSum2 = nSum + nNewLen;
  if(nSum2 > nLen)
  {
   *pCoeff = ((nLen - nSum) << 12) / nDenom;
   pCoeff[1] = ((nSum2 - nLen) << 12) / nDenom;
   nSum2 -= nLen;
  }
  else
  {
   *pCoeff = nNorm;
   if(nSum2 == nLen)
   {
    pCoeff[1] = -1;
    nSum2 = 0;
   }
  }
  nSum = nSum2;
 }
 
 return pRes;
}

///////////////////////////////////////////////////////////

void ShrinkDataInt(BYTE *pInBuff,
                   WORD wWidth,
                   WORD wHeight,
                   BYTE *pOutBuff,
                   WORD wNewWidth,
                   WORD wNewHeight)
{
 BYTE  *pLine = pInBuff, *pPix;
 BYTE  *pOutLine = pOutBuff;
 DWORD dwInLn = (g_nVal  * wWidth + g_nVal ) & ~g_nVal ;
 DWORD dwOutLn = (g_nVal  * wNewWidth + g_nVal ) & ~g_nVal ;
 int   x, y, i, ii;
 BOOL  bCrossRow, bCrossCol;
 int   *pRowCoeff = CreateCoeffInt(wWidth,
                                   wNewWidth,
                                   TRUE);
 int   *pColCoeff = CreateCoeffInt(wHeight,
                                   wNewHeight,
                                   TRUE);
 int   *pXCoeff, *pYCoeff = pColCoeff;
 DWORD dwBuffLn = g_nVal  * wNewWidth * sizeof(DWORD);
 DWORD *pdwBuff = new DWORD[2 * g_nVal * wNewWidth];
 DWORD *pdwCurrLn = pdwBuff,
       *pdwCurrPix,
       *pdwNextLn = pdwBuff + g_nVal  * wNewWidth;
 DWORD dwTmp, *pdwNextPix;

 ::ZeroMemory(pdwBuff, 2 * dwBuffLn);

 y = 0;
 while(y < wNewHeight)
 {
  pPix = pLine;
  pLine += dwInLn;

  pdwCurrPix = pdwCurrLn;
  pdwNextPix = pdwNextLn;

  x = 0;
  pXCoeff = pRowCoeff;
  bCrossRow = pYCoeff[1] > 0;
  while(x < wNewWidth)
  {
   dwTmp = *pXCoeff * *pYCoeff;
   for(i = 0; i < g_nVal ; i++)
    pdwCurrPix[i] += dwTmp * pPix[i];
   bCrossCol = pXCoeff[1] > 0;
   if(bCrossCol)
   {
    dwTmp = pXCoeff[1] * *pYCoeff;
    for(i = 0, ii = g_nVal ; i < g_nVal ; i++, ii++)
     pdwCurrPix[ii] += dwTmp * pPix[i];
   }
   if(bCrossRow)
   {
    dwTmp = *pXCoeff * pYCoeff[1];
    for(i = 0; i < g_nVal ; i++)
     pdwNextPix[i] += dwTmp * pPix[i];
    if(bCrossCol)
    {
     dwTmp = pXCoeff[1] * pYCoeff[1];
     for(i = 0, ii = g_nVal ; i < g_nVal ; i++, ii++)
      pdwNextPix[ii] += dwTmp * pPix[i];
    }
   }
   if(pXCoeff[1])
   {
    x++;
    pdwCurrPix += g_nVal ;
    pdwNextPix += g_nVal ;
   }
   pXCoeff += 2;
   pPix += g_nVal ;
  }
  if(pYCoeff[1])
  {
   // set result line
   pdwCurrPix = pdwCurrLn;
   pPix = pOutLine;
   for(i = g_nVal  * wNewWidth; i > 0; i--, pdwCurrPix++, pPix++)
    *pPix = ((LPBYTE)pdwCurrPix)[3];

   // prepare line buffers
   pdwCurrPix = pdwNextLn;
   pdwNextLn = pdwCurrLn;
   pdwCurrLn = pdwCurrPix;
   ::ZeroMemory(pdwNextLn, dwBuffLn);

   y++;
   pOutLine += dwOutLn;
  }
  pYCoeff += 2;
 }

 delete [] pRowCoeff;
 delete [] pColCoeff;
 delete [] pdwBuff;
}

///////////////////////////////////////////////////////////

void EnlargeDataInt(BYTE *pInBuff,
                    WORD wWidth,
                    WORD wHeight,
                    BYTE *pOutBuff,
                    WORD wNewWidth,
                    WORD wNewHeight)
{
 BYTE  *pLine = pInBuff,
       *pPix = pLine,
       *pPixOld,
       *pUpPix,
       *pUpPixOld;
 BYTE  *pOutLine = pOutBuff, *pOutPix;
 DWORD dwInLn = (g_nVal  * wWidth + g_nVal ) & ~g_nVal ;
 DWORD dwOutLn = (g_nVal  * wNewWidth + g_nVal ) & ~g_nVal ;
 int   x, y, i;
 BOOL  bCrossRow, bCrossCol;
 int   *pRowCoeff = CreateCoeffInt(wNewWidth,
                                   wWidth,
                                   FALSE);
 int   *pColCoeff = CreateCoeffInt(wNewHeight,
                                   wHeight,
                                   FALSE);
 int   *pXCoeff, *pYCoeff = pColCoeff;
 DWORD dwTmp, dwPtTmp[4];

 y = 0;
 while(y < wHeight)
 {
  bCrossRow = pYCoeff[1] > 0;
  x = 0;
  pXCoeff = pRowCoeff;
  pOutPix = pOutLine;
  pOutLine += dwOutLn;
  pUpPix = pLine;
  if(pYCoeff[1])
  {
   y++;
   pLine += dwInLn;
   pPix = pLine;
  }

  while(x < wWidth)
  {
   bCrossCol = pXCoeff[1] > 0;
   pUpPixOld = pUpPix;
   pPixOld = pPix;
   if(pXCoeff[1])
   {
    x++;
    pUpPix += g_nVal ;
    pPix += g_nVal ;
   }
   
   dwTmp = *pXCoeff * *pYCoeff;
   
   for(i = 0; i < g_nVal ; i++)
    dwPtTmp[i] = dwTmp * pUpPixOld[i];
   
   if(bCrossCol)
   {
    dwTmp = pXCoeff[1] * *pYCoeff;
    for(i = 0; i < g_nVal ; i++)
    dwPtTmp[i] += dwTmp * pUpPix[i];
   }

   if(bCrossRow)
   {
    dwTmp = *pXCoeff * pYCoeff[1];
    for(i = 0; i < g_nVal ; i++)
    dwPtTmp[i] += dwTmp * pPixOld[i];
    if(bCrossCol)
    {
     dwTmp = pXCoeff[1] * pYCoeff[1];
     for(i = 0; i < g_nVal ; i++)
     dwPtTmp[i] += dwTmp * pPix[i];
    }
   }
   
   for(i = 0; i < g_nVal ; i++, pOutPix++)
    *pOutPix = ((LPBYTE)(dwPtTmp + i))[3];
   
   pXCoeff += 2;
  }
  pYCoeff += 2;
 }

 delete [] pRowCoeff;
 delete [] pColCoeff;
}


Try it

I'm studying the code for 16 bit....
11:15 PM now, I'm leaving for the day....

See You tommorrow
0
 
LVL 1

Author Comment

by:moshem
ID: 7157682
right! thanks - you Rock! , See you tommorow , can't wait for the other depth ...
0
 
LVL 1

Author Comment

by:moshem
ID: 7160641
Hi,

any news regarding the other depths?
0
 
LVL 23

Expert Comment

by:Roshan Davis
ID: 7161248
We have to write another function for 16 bit.
Because the RGB is like 5-bit, 6-bit, 5-bit format or 556 format. So we have to write another function and will do the same color manipulation on tha function.

If you can wait 8 more hours, I can try that.....

And Where you from ...? What is the GMT difference there..?

Regards

Roshmon
0
 
LVL 1

Author Comment

by:moshem
ID: 7161484
Sure I can wait, I'm from Israel, if I'm not mistaked it's GMT+2
0
 
LVL 23

Expert Comment

by:Roshan Davis
ID: 7161625
Here GMT 5.5,
See You at Evening..

Roshmon
0
 
LVL 1

Author Comment

by:moshem
ID: 7165004
Hi Roshmon,

still waiting for that code you promised...

BTW,

I found a bug in your resize patch, if you try to resize to a size in multiples of 2 like 50, 60, 62, 64 it will work great.

But, if you try to resize it to non 2 multplier,like 51, 61 ,63, 65 it will get distorted. see if you can do something about it...


thanks
0
 
LVL 1

Author Comment

by:moshem
ID: 7165248
Ok,

I just found another bug (for the first see my previous comment), there seem to be a serious resource leak when shrinking bitmaps. I use the task manager GDI Object column to trace it and there is a leak there.

I am trying to find it but since I don't understand the code I hope you can do something about it.

thanks
0
 
LVL 1

Author Comment

by:moshem
ID: 7165717
Dear Roshmon,

sorry, but the resource leak was in my code, not yours. but the x2 resize bug still stand.

any response ?
0
 
LVL 23

Expert Comment

by:Roshan Davis
ID: 7166465
Sorry for the late response.
We have (our company) Saturday and Sunday OFF.

So I can't check the mails....
here I'm using the Office id.
I will test the code...

Regards

Roshmon
0
 
LVL 1

Author Comment

by:moshem
ID: 7166468
Ok,

thanks
0
 
LVL 23

Expert Comment

by:Roshan Davis
ID: 7166492
bug in 32 bit ? or in 24 bit ?

Now I'm suggesting a tricky solution for a short term.
Y becoz now I can't get the tested code.

resize image only in even numbers, monday I will check the code.

if ( nSize % 2 == 1 )
   nSize ++;

Regards
Roshmon
0
 
LVL 1

Author Comment

by:moshem
ID: 7166784
I have found it while attempting to downsize 32-bit bitmaps.

waiting for you on monday.

BTW,

do you have any ideas to my other problem of bitmap animation the desktop ?

0
 
LVL 1

Author Comment

by:moshem
ID: 7166831
I just found out that besides the bug, this function of ours is very slow.

to compare, try the following :

SetStretchBltMode (hdc, HALFTONE);

and then use the StretchBlt function.

it seems that by using the HALFTONE flag it causes the StretchBlt resize with very good quality! and it is doing so in about 2 to 4 times faster than our own function!!! much more suitable to my needs.

The only problem is that it is not support in Win 95/98/ME.

Do you think you can imporve the speed or find a better and faster source code for this ?

thanks!
0
 

Expert Comment

by:bhorling
ID: 8776526
I'm wondering whether the dwInLn and dwOutLn variables are being computed correctly with 32 bpp images.  I was using this function with 32bpp images and they were coming out slanted, seemingly from this number being calculated incorrectly, which would lead to a stairstep effect when the too-short or too-long lines were added to the destination image.

From the BMP docs, it seems as though each scan line in BMP is padded with enough bytes to make it a multiple of 4.  However, 32bpp scan lines are a multiple of 4 by definition (since each pixel is composed of 4 bytes).  Should these really be...

DWORD      dwInLn            = 4 * wWidth;      
DWORD      dwOutLn            = 4 * wNewWidth;      

(this is just the 32 bit case)

Regarding using StretchBlt and mode HALFTONE that moshem mentions, I've found that this seems to throw out the alpha channel information when it's applied to 32bpp images, at least in the code I have running on XP.  The whole channel is zeroed out in my destination image after applying it.  It works fine with COLORONCOLOR, but of course the picture quality rots.
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

zlib is a free compression library (a DLL) on which the popular gzip utility is built.  In this article, we'll see how to use the zlib functions to compress and decompress data in memory; that is, without needing to use a temporary file.  We'll be c…
For a while now I'v been searching for a circular progress control, much like the one you get when first starting your Silverlight application. I found a couple that were written in WPF and there were a few written in Silverlight, but all appeared o…
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now