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