Link to home
Start Free TrialLog in
Avatar of moshem
moshem

asked on

Bitmap resize

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
Avatar of Roshan Davis
Roshan Davis
Flag of United States of America image

Avatar of moshem
moshem

ASKER

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 ?
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

Avatar of moshem

ASKER

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!
looking...
If you have time to wait 4 hours (after my office hours).. I can convert this into 32 bit
Avatar of moshem

ASKER

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
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;
}
Avatar of moshem

ASKER

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
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
Avatar of moshem

ASKER

I'm sorry but I have zero understaning of this code, do you mean that this latest update may result in faster performence ?
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
Avatar of moshem

ASKER

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 ?
>> The points are yours...

can you rate the comment now ?
Or more doubts ?

Regards
Roshmon
Avatar of moshem

ASKER

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
>> 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
Avatar of moshem

ASKER

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.
Compare with StretchBlt,
I think that API also take around this much time...becoz the size of bits increased..

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
Avatar of moshem

ASKER

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 ;-)  ) ??


The second version is just a guess...

ASKER CERTIFIED SOLUTION
Avatar of Roshan Davis
Roshan Davis
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of moshem

ASKER

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!
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
Avatar of moshem

ASKER

right! thanks - you Rock! , See you tommorow , can't wait for the other depth ...
Avatar of moshem

ASKER

Hi,

any news regarding the other depths?
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
Avatar of moshem

ASKER

Sure I can wait, I'm from Israel, if I'm not mistaked it's GMT+2
Here GMT 5.5,
See You at Evening..

Roshmon
Avatar of moshem

ASKER

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
Avatar of moshem

ASKER

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
Avatar of moshem

ASKER

Dear Roshmon,

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

any response ?
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
Avatar of moshem

ASKER

Ok,

thanks
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
Avatar of moshem

ASKER

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 ?

Avatar of moshem

ASKER

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!
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.