Win32 C Function for High-Quality Bitmap Shrinking
Posted
by Petr Spacil
on November 1st, 2000
![]() 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 <malloc.h>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 (ny<a->y) 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);
}





Comments
There are no comments yet. Be the first to comment!