Win32 C Function for High-Quality Bitmap Shrinking 

 

Introduction

The Win32 API provides a function called StretchBlt, which can be used to shrink and expand bitmaps. However, when you need the same quality as that produced by professional packages such as Adobe Photoshop or Corel Draw, this function falls woefully short. Another Win32 function, CopyImage, can be used to expand images. However, while its antialiasing is very efficient, the resulting image once again is even worse than the StrechBlt function. 

Therefore, I wrote my own function (ShrinkBitmap) to give me the ability to shink and expand images in my own application, yet do so with the same quality I would expect from a graphics package. Take a look at the following table of images and you'll see first a large image (the original) and then a comparison of images that have been shrunk using the StretchBlt function, my ShrinkBitmap function and the an Adobe Photoshop conversion. As you can see, ShrinkBitmap gives you Adobo Photoshop bitmap shrinking capabilities from within your own application. 

This is me in original size and I'm going to shrink myself  

Resolution StretchBlt My function Adobe Photoshop 

105 กม 150    

35 กม 50    

Source Code

Place these macros into the beginning of your program: 

#define Alloc(p,t) (t *)malloc((p)*sizeof(t))

#define For(i,n) for ((i)=0;(i)<(n);(i)++)

#define iFor(n) For (i,n)

#define jFor(n) For (j,n)

And also this type-definition: 

typedef struct {

 WORD x,y;  // dimensions

 WORD l;    // bytes per scan-line (32-bit allignment)

 BYTE *b;   // bits of bitmap,3 bytes/pixel, BGR

} tWorkBMP;  // 24-bit working bitmap

The functions also require the header file for memory allocation, or you can rewrite them to use keywords new and delete. 

#include 

Here's the actual ShrinkBitmap function 

HBITMAP ShrinkBitmap (HBITMAP a,WORD bx,WORD by)

// creates and returns new bitmap with dimensions of 

// [bx,by] by shrinking bitmap a both [bx,by] must be less or equal 

// than the dims of a, unless the result is nonsense

{

 tWorkBMP in,out;

 HBITMAP b=CreateEmptyBitmap(bx,by);

 OpenBitmapForWork (a,&in);

 ShrinkWorkingBitmap (&in,&out,bx,by);

 free (in.b);

 SaveWorkingBitmap (&out,b);

 free (out.b);

 return (b);

The following functions are just supporting and I recommend treating them in "black box" fashion. But you have to place them in front of the ShrinkBitmap function or forward declare them. 

void CreateWorkingBitmap (WORD dx,WORD dy,tWorkBMP *w)

{

 w->x=dx;

 w->y=dy;

 w->l=(dx+1)*3&0xfffc;

 w->b=Alloc(w->l*dy,BYTE);

HBITMAP CreateEmptyBitmap (WORD dx,WORD dy)

{

 HDC h=GetDC(NULL);

 HBITMAP b=CreateCompatibleBitmap(h,dx,dy);

 ReleaseDC (NULL,h);

 

 return (b);

void SetBMIHeader (BITMAPINFO *b,short dx,short dy)

{

 b->bmiHeader.biSize=sizeof(BITMAPINFOHEADER);

 b->bmiHeader.biWidth=dx;

 b->bmiHeader.biHeight=-dy;

 b->bmiHeader.biPlanes=1;

 b->bmiHeader.biBitCount=24;

 b->bmiHeader.biCompression=BI_RGB;

 b->bmiHeader.biSizeImage=0;

 b->bmiHeader.biXPelsPerMeter=1;

 b->bmiHeader.biYPelsPerMeter=1;

 b->bmiHeader.biClrUsed=0;

 b->bmiHeader.biClrImportant=0;

void SaveWorkingBitmap (tWorkBMP *w,HBITMAP b)

{

 BITMAPINFO s;

 HDC h=GetDC(NULL);

 SetBMIHeader (&s,w->x,w->y);

 SetDIBits (h,b,0,w->y,w->b,&s,DIB_RGB_COLORS);

 ReleaseDC (NULL,h);

void ShrinkWorkingBitmap (tWorkBMP *a,tWorkBMP *b,WORD bx,WORD by)

{

 BYTE *uy=a->b,*ux,i;

 WORD x,y,nx,ny=0;

 DWORD df=3*bx,nf=df*by,j;

 float k,qx[2],qy[2],q[4],*f=Alloc(nf,float);

 CreateWorkingBitmap (bx,by,b);

 jFor (nf) f[j]=0;

 j=0;

 For (y,a->y) {

  ux=uy;

  uy+=a->l;

  nx=0;

  ny+=by;

  if (ny>a->y) {

   qy[0]=1-(qy[1]=(ny-a->y)/(float)by);

   For (x,a->x) {

    nx+=bx;

    if (nx>a->x) {

     qx[0]=1-(qx[1]=(nx-a->x)/(float)bx);

     iFor (4) q[i]=qx[i&1]*qy[i>>1];

     iFor (3) {

      f[j]+=(*ux)*q[0]; 

      f[j+3]+=(*ux)*q[1];

      f[j+df]+=(*ux)*q[2];

      f[(j++)+df+3]+=(*(ux++))*q[3];

     }

    }

    else iFor (3) {

     f[j+i]+=(*ux)*qy[0];

     f[j+df+i]+=(*(ux++))*qy[1];

    }

    if (nx>=a->x) nx-=a->x;

     if (!nx) j+=3;

   }

  }

  else {

   For (x,a->x) {

 

    nx+=bx;

 

    if (nx>a->x) {

     qx[0]=1-(qx[1]=(nx-a->x)/(float)bx);

     iFor (3) {

      f[j]+=(*ux)*qx[0];

      f[(j++)+3]+=(*(ux++))*qx[1];

     }

    }

    else iFor (3) f[j+i]+=*(ux++);

 

    if (nx>=a->x) nx-=a->x;

     if (!nx) j+=3;

   }

   if (nyy) j-=df;

  }

  if (ny>=a->y) ny-=a->y;

 }

 

 nf=0;

 k=bx*by/(float)(a->x*a->y);

 uy=b->b;

 

 For (y,by) {

  jFor (df) uy[j]=f[nf++]*k+.5;

  uy+=b->l;

 }

 free (f);