Want to win a PS4? Go Premium and enter to win our High-Tech Treats giveaway. Enter to Win

x
?
Solved

Bitmap resize

Posted on 2002-07-15
40
Medium Priority
?
1,452 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

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

Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

A theme is a collection of property settings that allow you to define the look of pages and controls, and then apply the look consistently across pages in an application. Themes can be made up of a set of elements: skins, style sheets, images, and o…
Entering time in Microsoft Access can be difficult. An input mask often bothers users more than helping them and won't catch all typing errors. This article shows how to create a textbox for 24-hour time input with full validation politely catching …
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…
If you’ve ever visited a web page and noticed a cool font that you really liked the look of, but couldn’t figure out which font it was so that you could use it for your own work, then this video is for you! In this Micro Tutorial, you'll learn yo…

636 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