Accelerated Smooth Bitmap Resizing

Environment: VC6, Win32

When we want to resize a bitmap and also the resulting bitmap to be of the highest possible quality, the Win32 AIP function StretchBlt() is not of much help. There are already articles about this task in the CodeGuru sections, but the proposed algorithms take considerable amount of memory when used on large bitmaps - with dimensions of several thousand pixels on each axis.

The function ScaleBitmap() uses an algorithm adjusted to use minimum additional memory and not sacrificing the overall performance. The prototype of the function is

HBITMAP ScaleBitmap(HBITMAP hBmp, 
                    WORD wNewWidth, 
                    WORD wNewHeight);

The only limitation is that both wNewWidth and wNewHeight should be greater or lesser than the dimensions of the original bitmap. The returned bitmap is compatible with the screen device context.

The code below, let's mark it as variant A, produces images of good quality, but because of the large number of floating point calculations it is not as fast as we want.

The main reserve for improving the performance of the routine is in the replacement of all floating-point calculations with integer ones. How could we do that without degradation of image quality?

Actually we don't need more than 3 or 4 digits after the decimal point to produce the same result - the result after all is just a byte [0..255]. The obvious solution is to replace all floating numbers with numbers with fixed decimal point. By example we should replace the number 0.00345 with 345 and also divide the final result by 100000.
OK - let's do it.

Oops!!! In the code we should multiply these fixed-point numbers. Because we are limited to 4-byte integer numbers for performance reasons (means 2,147,483,648 to 2,147,483,647), we can't use 4 digits after the decimal point, because 256 * 10000 * 10000 exceeds 4-byte integer range and somewhere we will get a silent overflow. It seems that we should use the available 3 digits and be happy with that.

This is not so bad, but who limits us to use just the powers of 10 to divide our fixed-point numbers. With the same success we can use the powers of 16, moreover the division by such a number equals to shifting right the number. Let's do some calculations. We have 4 bytes - that means 32 bits. We need 8 bits for the color values and the remaining of 24 bits leads us to decision to use 0x1000 (or 1 << 12) as the divisor for our fixed-point numbers. If the numbers are unsigned (and they are) we shouldn't have troubles with overflows.

As a result we will have about 3,6 valid decimal digits in our fixed-point numbers - it's closer to 4 digits than just 3 digits.

The second piece of code (variant B) uses this method to do all calculations with fixed-point integer numbers. This leads to obvious acceleration of the performance of code B compared to performance of code A, but how big is it?

The following table represents the performance gain of code B over code A on processing a 305x435 pixels image.

Result size / Original size 5% 10% 25% 50% 75% 100% 125% 150% 200% 300%
Performance gain 24% 25% 34% 52% 59% 73% 67% 71% 75% 76%

Considering that along with the calculations the code does also a lot of other work, we can conclude that the 4-byte integer calculations are 3 to 4 times faster than these with floating point numbers.

Variant A

//
// Smooth bitmap resize
//
// Ivaylo Byalkov, November 16, 2000
//

#include "stdafx.h"
#include <math.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

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

// helper function prototypes
static BITMAPINFO *PrepareRGBBitmapInfo(WORD wWidth, WORD wHeight);
static void ShrinkData(BYTE *pInBuff, WORD wWidth, WORD wHeight,
				BYTE *pOutBuff, WORD wNewWidth, WORD wNewHeight);
static void EnlargeData(BYTE *pInBuff, WORD wWidth, WORD wHeight,
				 BYTE *pOutBuff, WORD wNewWidth, WORD wNewHeight);

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

HBITMAP ScaleBitmap(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)
  ShrinkData(pData, (WORD)bmp.bmWidth, (WORD)bmp.bmHeight,
  pData2, wNewWidth, wNewHeight);
 else
  EnlargeData(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 = 24;
 pRes->bmiHeader.biSizeImage = ((3 * wWidth + 3) & ~3) 
                                * wHeight;

 return pRes;
}

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

static float *CreateCoeff(int nLen, int nNewLen, BOOL bShrink)
{
 int nSum = 0, nSum2;
 float *pRes = new float[2 * nLen];
 float *pCoeff = pRes;
 float fNorm = (bShrink)? (float)nNewLen / nLen : 1;
 int	  nDenom = (bShrink)? nLen : nNewLen;

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

 return pRes;
}

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

#define F_DELTA		0.0001f

void ShrinkData(BYTE *pInBuff, 
                WORD wWidth, 
                WORD wHeight,
                BYTE *pOutBuff, 
                WORD wNewWidth, 
                WORD wNewHeight)
{
 BYTE  *pLine = pInBuff, *pPix;
 BYTE  *pOutLine = pOutBuff;
 DWORD dwInLn = (3 * wWidth + 3) & ~3;
 DWORD dwOutLn = (3 * wNewWidth + 3) & ~3;
 int   x, y, i, ii;
 BOOL  bCrossRow, bCrossCol;
 float *pRowCoeff = CreateCoeff(wWidth, wNewWidth, TRUE);
 float *pColCoeff = CreateCoeff(wHeight, wNewHeight, TRUE);
 float fTmp, *pXCoeff, *pYCoeff = pColCoeff;
 DWORD dwBuffLn = 3 * wNewWidth * sizeof(float);
 float *fBuff = new float[6 * wNewWidth];
 float *fCurrLn = fBuff, 
       *fCurrPix, 
       *fNextLn = fBuff + 3 * wNewWidth, 
       *fNextPix;

 ::ZeroMemory(fBuff, 2 * dwBuffLn);

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

  fCurrPix = fCurrLn;
  fNextPix = fNextLn;

  x = 0;
  pXCoeff = pRowCoeff;
  bCrossRow = pYCoeff[1] > F_DELTA;
  while(x < wNewWidth)
  {
   fTmp = *pXCoeff * *pYCoeff;
   for(i = 0; i < 3; i++)
   fCurrPix[i] += fTmp * pPix[i];
   bCrossCol = pXCoeff[1] > F_DELTA;
   if(bCrossCol)
   {
    fTmp = pXCoeff[1] * *pYCoeff;
    for(i = 0, ii = 3; i < 3; i++, ii++)
     fCurrPix[ii] += fTmp * pPix[i];
   }

   if(bCrossRow)
   {
    fTmp = *pXCoeff * pYCoeff[1];
    for(i = 0; i < 3; i++)
     fNextPix[i] += fTmp * pPix[i];
    if(bCrossCol)
    {
     fTmp = pXCoeff[1] * pYCoeff[1];
     for(i = 0, ii = 3; i < 3; i++, ii++)
      fNextPix[ii] += fTmp * pPix[i];
    }
   }

  if(fabs(pXCoeff[1]) > F_DELTA)
  {
   x++;
   fCurrPix += 3;
   fNextPix += 3;
  }

  pXCoeff += 2;
  pPix += 3;
 }

 if(fabs(pYCoeff[1]) > F_DELTA)
 {
  // set result line
  fCurrPix = fCurrLn;
  pPix = pOutLine;
  for(i = 3 * wNewWidth; i > 0; i--, fCurrPix++, pPix++)
  *pPix = (BYTE)*fCurrPix;

  // prepare line buffers
  fCurrPix = fNextLn;
  fNextLn = fCurrLn;
  fCurrLn = fCurrPix;
  ::ZeroMemory(fNextLn, dwBuffLn);

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

 delete [] pRowCoeff;
 delete [] pColCoeff;
 delete [] fBuff;
} 

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

void EnlargeData(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 = (3 * wWidth + 3) & ~3;
 DWORD dwOutLn = (3 * wNewWidth + 3) & ~3;
 int   x, y, i;
 BOOL  bCrossRow, bCrossCol;
 float *pRowCoeff = CreateCoeff(wNewWidth, wWidth, FALSE);
 float *pColCoeff = CreateCoeff(wNewHeight, wHeight, FALSE);
 float fTmp, fPtTmp[3], *pXCoeff, *pYCoeff = pColCoeff;

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

  while(x < wWidth)
  {
   bCrossCol = pXCoeff[1] > F_DELTA;
   pUpPixOld = pUpPix;
   pPixOld = pPix;
   if(fabs(pXCoeff[1]) > F_DELTA)
   {
    x++;
    pUpPix += 3;
    pPix += 3;
   }
   fTmp = *pXCoeff * *pYCoeff;
   for(i = 0; i < 3; i++)
    fPtTmp[i] = fTmp * pUpPixOld[i];
   if(bCrossCol)
   {
    fTmp = pXCoeff[1] * *pYCoeff;
    for(i = 0; i < 3; i++)
    fPtTmp[i] += fTmp * pUpPix[i];
   }
   if(bCrossRow)
   {
    fTmp = *pXCoeff * pYCoeff[1];
    for(i = 0; i < 3; i++)
    fPtTmp[i] += fTmp * pPixOld[i];
    if(bCrossCol)
    {
     fTmp = pXCoeff[1] * pYCoeff[1];
     for(i = 0; i < 3; i++)
      fPtTmp[i] += fTmp * pPix[i];
    }
   }
   for(i = 0; i < 3; i++, pOutPix++)
    *pOutPix = (BYTE)fPtTmp[i];
   pXCoeff += 2;
  }
  pYCoeff += 2;
 }

 delete [] pRowCoeff;
 delete [] pColCoeff;
} 

// end src

Variant B

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

#include "stdafx.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

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

// 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 = 24;

 pRes->bmiHeader.biSizeImage = 
  ((3 * wWidth + 3) & ~3) * 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 = (3 * wWidth + 3) & ~3;
 DWORD dwOutLn = (3 * wNewWidth + 3) & ~3;
 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 = 3 * wNewWidth * sizeof(DWORD);
 DWORD *pdwBuff = new DWORD[6 * wNewWidth];
 DWORD *pdwCurrLn = pdwBuff, 
       *pdwCurrPix, 
       *pdwNextLn = pdwBuff + 3 * 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 = 3; 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 = 3; i < 3; i++, ii++)
      pdwNextPix[ii] += dwTmp * pPix[i];
    }
   }
   if(pXCoeff[1])
   {
    x++;
    pdwCurrPix += 3;
    pdwNextPix += 3;
   }
   pXCoeff += 2;
   pPix += 3;
  }
  if(pYCoeff[1])
  {
   // set result line
   pdwCurrPix = pdwCurrLn;
   pPix = pOutLine;
   for(i = 3 * 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 = (3 * wWidth + 3) & ~3;
 DWORD dwOutLn = (3 * wNewWidth + 3) & ~3;
 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[3];

 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 += 3;
    pPix += 3;
   }
   
   dwTmp = *pXCoeff * *pYCoeff;
   
   for(i = 0; i < 3; i++)
    dwPtTmp[i] = dwTmp * pUpPixOld[i];
   
   if(bCrossCol)
   {
    dwTmp = pXCoeff[1] * *pYCoeff;
    for(i = 0; i < 3; i++)
    dwPtTmp[i] += dwTmp * pUpPix[i];
   }

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

 delete [] pRowCoeff;
 delete [] pColCoeff;
} 

// end src


Comments

  • The return image is full black

    Posted by Aguml on 05/28/2013 01:19am

    I am a novice programmer and have used both versions and both get the same result, an image of the desired size but completely black. What's going on? if you want to try with my image, tell me where to send it. I'm using C + + Builder and this is my code: http://pastebin.com/H3xh1maZ Can you help? The image is: http://img28.imageshack.us/img28/3643/t1ss1.png

    Reply
  • Is it bug?

    Posted by Toshihiko Takasaki on 04/17/2013 10:16am

    I'm a Japanese beginner.I think that this program is very excellent, but in the case of huge size picture(over 1MB) load, applications should end in failure. So I tried to increase the buffer size of above "55. BYTE *pData = new BYTE[pbi-bmiHeader.biSizeImage];", then picture load is success, but in the picture "one dirty line"(about one pixel width) is found. If there are some easy resolving methods, please teach me the code.

    Reply
  • Is it bug?

    Posted by Toshihiko Takasaki on 04/17/2013 10:05am

    I'm a Japanese beginner.I think that this program is very excellent, but in the case of huge size picture(over 1MB) load, applications should end in failure. So I tried to increase the buffer size of above "55. BYTE *pData = new BYTE[pbi-bmiHeader.biSizeImage];", then picture load is success, but in the picture "one dirty line"(about one pixel width) is found. If there are some easy resolving methods, please teach me the code.

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: December 11, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT Market pressures to move more quickly and develop innovative applications are forcing organizations to rethink how they develop and release applications. The combination of public clouds and physical back-end infrastructures are a means to get applications out faster. However, these hybrid solutions complicate DevOps adoption, with application delivery pipelines that span across complex hybrid cloud and non-cloud environments. Check out this …

  • On-demand Event Event Date: October 29, 2014 It's well understood how critical version control is for code. However, its importance to DevOps isn't always recognized. The 2014 DevOps Survey of Practice shows that one of the key predictors of DevOps success is putting all production environment artifacts into version control. In this webcast, Gene Kim discusses these survey findings and shares woeful tales of artifact management gone wrong! Gene also shares examples of how high-performing DevOps …

Most Popular Programming Stories

More for Developers

RSS Feeds