/*
Source: David Maeschen
Date: 1 Jan 1995
Compilation
make bm or
cc bm.c -o bm
*/
#ifndef lint
static char sccsid[] = "@(#)bm.c 1.00 92/12/15";
#endif
/*
Bitmap translation
Usage: bm translate m lx ly mx my bitmap npad nx ny newcanvas
bm translate 3 0 0 408 532 bitmap 256 408 532 @ 400 dpi
Bitmap replication
Usage: bm replicate m lx ly mx my bitmap npad nx ny newcanvas
bm replicate 0 0 0 408 532 bitmap 256 204 266 newcanvas
Bitmap scaling
Usage: bm scale m mx my bitmap npad nx ny newcanvas
bm scale 0 204 266 bitmap 256 408 532 @ 400 dpi
Bitmap rotation
Usage: bm rotate m bitmap npad nx ny newcanvas
bm rotate 3 bitmap 256 408 532 @ 400 dpi
Bitmap reversal
Usage: bm reverse m bitmap npad nx ny newcanvas
bm reverse 3 bitmap 256 408 532 @ 400 dpi
Bitmap inversion
Usage: bm invert m bitmap npad nx ny newcanvas
bm invert 2 bitmap 256 408 532 @ 400 dpi
Bitmap erosion
Usage: bm erode m bitmap npad nx ny newcanvas
bm erode 0 bitmap 256 408 532 @ 400 dpi
0<= m <=3 lx, ly, mx, my, npad, nx, ny bytes
These functions are close to optimum for the general cases they address
although some (rotate 0/3) have been left unoptimized when another
(reverse 0/3) can accomplish the same result
Future ideas
Shearing
Application to bitmap superpixels
*/
#include
#include
/*
Unsigned to prevent signed right shifts
*/
typedef unsigned char byte;
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
/*
Bit functions
For the ith j quantity
1(bit) 2(nibble) 3(byte) 4(short)
(second byte i 2, j 3)
Select (((k)>>BIT1(i,j)) & BIT0(j))
Clear k &= ~(BIT0(j)<>BIT1(i,j)) & BIT0(j))
#define BITSET(i,j,k,l) ( ((k)&(~(BIT0(j)<>biti(n)) & 0x01)
void trans_bitmap(m,lx,ly,mx,my,nx,ny,c,d)
/*
Translate and crop m (0-3) circularly, clip x, clip y, clip x & y,
the mx x my bitmap c into an nx x ny bitmap d at relative position lx x ly
Can be done in place in most but not all cases
*/
long m, lx, ly, mx, my, nx, ny;
byte c[], d[];
{
byte e;
long i, j, k, l, n, mmnx, mmny, mmxx, mmxy;
if (m % 2) {
mmnx = max( 0, min( mx, - lx));
mmxx = max( 0, min( mx, nx - lx));
} else {
mmnx = 0;
mmxx = mx;
}
if ((m % 4)/2) {
mmny = max( 0, min( my, - ly));
mmxy = max( 0, min( my, ny - ly));
} else {
mmny = 0;
mmxy = my;
}
k = mmny*mx + mmnx;
l = ((mmny+ly+ny) % ny)*nx + (mmnx+lx+nx) % nx;
if (k >= l) {
for ( i=mmny; i>bitj(l);
d[l/8+1] |= c[k]<=mmny; i--) {
for ( j=(mmxx-1)/8; j>=mmnx/8; j--) {
k = i*mx/8 + j;
l = ((i+ly+ny) % ny)*nx + (8*j+lx+nx) % nx;
if (l%8) {
d[l/8 ] |= c[k]>>bitj(l);
d[l/8+1] |= c[k]<= l) {
for ( i=0; i>bitj(k);
d[l] |= c[k0/8]<=0; i--) {
for ( j=(nx-1)/8; j>=0; j--) {
k = ((i+ly+my) % my)*mx + (8*j+lx+mx) % mx;
l = i*nx/8 + j;
if (k%8) {
k0 = mpos(k,-1,mx);
d[l] |= c[ k/8]>>bitj(k);
d[l] |= c[k0/8]<>biti(j)) & 0x01) {
k = bit0((i<<3)|j,nx,ny);
d[k/8] |= 1 << biti(k);
}
}
}
}
break;
case 1:
for ( i=0; i>biti(j)) & 0x01) {
k = bit1((i<<3)|j,nx,ny);
d[k/8] |= 1 << biti(k);
}
}
}
}
break;
case 2:
for ( i=0; i>biti(j)) & 0x01) {
k = bit2((i<<3)|j,nx,ny);
d[k/8] |= 1 << biti(k);
}
}
}
}
break;
case 3:
for ( i=0; i>biti(j)) & 0x01) {
k = bit3((i<<3)|j,nx,ny);
d[k/8] |= 1 << biti(k);
}
}
}
}
break;
case 4:
/* Tile rotation */
nxb = nx>>3;
nyb = ny>>3;
nr = 8;
nb = (n+nr-1)/nr;
ri = (byte *)malloc(nr);
ro = (byte *)malloc(nr);
/* Load ri */
for ( ib=0; ib>biti(j)) & 0x01) {
k = j*8 + (i/8)*64 + i%8;
ro[k>>3] |= 1 << biti(k);
}
}
}
}
#else
for ( i=0; i>biti(i) & 0x01) << biti(0)) |
((ri[1]>>biti(i) & 0x01) << biti(1)) |
((ri[2]>>biti(i) & 0x01) << biti(2)) |
((ri[3]>>biti(i) & 0x01) << biti(3)) |
((ri[4]>>biti(i) & 0x01) << biti(4)) |
((ri[5]>>biti(i) & 0x01) << biti(5)) |
((ri[6]>>biti(i) & 0x01) << biti(6)) |
((ri[7]>>biti(i) & 0x01) << biti(7)) ;
#endif
}
/* Store ro */
for ( i=0; i>3;
nyb = ny>>3;
nr = ny;
nb = (n+nr-1)/nr;
ri = (byte *)malloc(nr);
ro = (byte *)malloc(nr);
/* Load ri */
for ( ib=0; ib>biti(j)) & 0x01) {
k = j*8 + (i/8)*64 + i%8;
ro[k>>3] |= 1 << biti(k);
}
}
}
}
/* Store ro */
for ( i=0; i>4)])
#else
/* Byte reversals */
static byte reverse[] = {
0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,
0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,
0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,
0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,
0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,
0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF,
};
#define reverse_byte(a) reverse[a]
#endif
void reverse_bitmap(m,nx,ny,c,d)
/*
Reverse m (copy, flip x, flip y, flip x & y axes) the nx x ny bitmap into d
Can be accomplished in place
Flip x & y accomplishes a half turn (180 deg rotation)
*/
byte c[], d[];
{
byte e;
long i, j, k, l, n;
n = (nx*ny + 7)/8;
switch (m % 4) {
case 0:
if (c != d) memcpy(d,c,n);
break;
case 1:
n = nx/8;
for ( i=0; i= n) {
/* Condense */
if (c == d) {
for (i=0; i>biti(j)) & 0x01)
d[i/8] |= 1 << biti(i);
else
d[i/8] &= ~(1 << biti(i));
}
} else {
for (i=0; i>biti(j)) & 0x01)
d[i/8] |= 1 << biti(i);
if (!(i % 100000)) fprintf(stderr," %u %u \r",j,i);
}
}
} else {
/* Expand */
if (c == d) {
for (i=n-1; i>=0; i--) {
if (i<(n-nx) && ((i/nx * my/ny) == ((i/nx + 1) * my/ny))) {
d[i/8] = d[(i+nx)/8];
} else {
j = (i%nx) * mx/nx + ((i/nx)*my/ny)*mx;
if ((c[j/8]>>biti(j)) & 0x01)
d[i/8] |= 1 << biti(i);
else
d[i/8] &= ~(1 << biti(i));
}
}
} else {
for (i=n-1; i>=0; i--) {
if (i<(n-nx) && ((i/nx * my/ny) == ((i/nx + 1) * my/ny))) {
d[i/8] = d[(i+nx)/8];
} else {
j = (i%nx) * mx/nx + ((i/nx)*my/ny)*mx;
if ((c[j/8]>>biti(j)) & 0x01)
d[i/8] |= 1 << biti(i);
if (!(i % 100000)) fprintf(stderr," %u %u \r",j,i);
}
}
}
}
}
void erode_bitmap(m,nx,ny,c,d)
/*
m 0-3 Erode, dialate, edge, and outline
the nx x ny bitmap c into bitmap d
Cannot be done in place
*/
long m, nx, ny;
byte c[], d[];
{
byte e;
long i, j, n;
n = nx*ny;
switch (m % 4) {
case 0:
for (i=0; i(n-nx)) || !(i%nx) || !((i+1)%nx) ||
!(!bitn(i-1,c) || !bitn(i+1,c) ||
!bitn(i-nx,c) || !bitn(i+nx,c) ) ))
d[i/8] |= 1 << biti(i);
if (!(i % 100000)) fprintf(stderr," %u \r",i);
}
break;
case 1:
for (i=0; i=nx) && bitn(i-nx,c)) || ((i<(n-nx)) && bitn(i+nx,c)) ))
d[i/8] |= 1 << biti(i);
if (!(i % 100000)) fprintf(stderr," %u \r",i);
}
break;
case 2:
for (i=0; i(n-nx)) || !(i%nx) || !((i+1)%nx) ||
!bitn(i-1,c) || !bitn(i+1,c) ||
!bitn(i-nx,c) || !bitn(i+nx,c) ))
d[i/8] |= 1 << biti(i);
if (!(i % 100000)) fprintf(stderr," %u \r",i);
}
break;
case 3:
for (i=0; i=nx) && bitn(i-nx,c)) || ((i<(n-nx)) && bitn(i+nx,c)) ))
d[i/8] |= 1 << biti(i);
if (!(i % 100000)) fprintf(stderr," %u \r",i);
}
break;
}
}
int main( argc, argv )
int argc;
char *argv[];
{
char *c, *d, *e;
int ichar;
long i = 0, ifn = 0, lx = 0, ly = 0, m = 3, mx = 0, my = 0;
long n = 0, np = 256, nx = 408, ny = 532;
time_t ctime0, ctime1;
if (argc == 1) {
fprintf(stderr,"usage: bm [bitmap npad nx ny] \n");
fprintf(stderr," [translate m lx ly mx my | replicate m lx ly mx my |\n");
fprintf(stderr," scale m mx my | rotate m | reverse m | invert m | erode m ]\n");
fprintf(stderr,"where the nx byte x ny byte with npad bytes is to be\n");
fprintf(stderr," translate (lx,ly) bytes into an mx x my byte bitmap\n");
fprintf(stderr," with clipping m 0 none, 1 x, 2 y, 3 x & y\n");
fprintf(stderr," replicate (lx,ly) bytes into an mx x my byte bitmap\n");
fprintf(stderr," with m none\n");
fprintf(stderr," scale m 0-3 none into an mx x my byte bitmap\n");
fprintf(stderr," rotate m 0-3 quarter turns counterclockwise\n");
fprintf(stderr," reverse m 0 none, 1 x, 2 y, 3 x & y\n");
fprintf(stderr," invert m 0 white, 1 ident, 2 negate, 3 black\n");
fprintf(stderr," erode m 0 erode, 1 dialate, 2 edge, 3 outline\n");
return(0);
}
while (++i < argc) {
if (strstr(argv[i],"translate") != NULL) {
ifn = 1;
++i;
if (i < argc) sscanf(argv[i],"%d",&m);
++i;
if (i < argc) sscanf(argv[i],"%d",&lx);
++i;
if (i < argc) sscanf(argv[i],"%d",&ly);
++i;
if (i < argc) sscanf(argv[i],"%d",&mx);
++i;
if (i < argc) sscanf(argv[i],"%d",&my);
} else if (strstr(argv[i],"replicate") != NULL) {
ifn = 2;
++i;
if (i < argc) sscanf(argv[i],"%d",&m);
++i;
if (i < argc) sscanf(argv[i],"%d",&lx);
++i;
if (i < argc) sscanf(argv[i],"%d",&ly);
++i;
if (i < argc) sscanf(argv[i],"%d",&mx);
++i;
if (i < argc) sscanf(argv[i],"%d",&my);
} else if (strstr(argv[i],"rotate") != NULL) {
ifn = 3;
++i;
if (i < argc) sscanf(argv[i],"%d",&m);
} else if (strstr(argv[i],"reverse") != NULL) {
ifn = 4;
++i;
if (i < argc) sscanf(argv[i],"%d",&m);
} else if (strstr(argv[i],"invert") != NULL) {
ifn = 5;
++i;
if (i < argc) sscanf(argv[i],"%d",&m);
} else if (strstr(argv[i],"scale") != NULL) {
ifn = 6;
++i;
if (i < argc) sscanf(argv[i],"%d",&m);
++i;
if (i < argc) sscanf(argv[i],"%d",&mx);
++i;
if (i < argc) sscanf(argv[i],"%d",&my);
} else if (strstr(argv[i],"erode") != NULL) {
ifn = 7;
++i;
if (i < argc) sscanf(argv[i],"%d",&m);
} else if (strstr(argv[i],"bitmap") != NULL) {
++i;
if (i < argc) sscanf(argv[i],"%d",&np);
++i;
if (i < argc) sscanf(argv[i],"%d",&nx);
++i;
if (i < argc) sscanf(argv[i],"%d",&ny);
} else {
fprintf(stderr," unknown argument: %s\n",argv[i]);
}
}
n = np + max( 8*mx*my, 8*nx*ny);
if (n == np) n = 2*1024*1024;
c = (char *)malloc(n);
if (ifn == 1 || ifn == 2 || ifn == 3 || ifn == 6 || ifn == 7)
d = (char *)malloc(n);
else
d = c;
if (c == NULL || d == NULL) {
fprintf(stderr," Cannot get memory\n");
exit(1);
}
memset(d,0,n);
i = 0;
while ((ichar = fgetc(stdin)) != EOF)
{ c[i] = ichar; i++; }
n = i;
n -= np;
if (nx*ny == 0) {
nx = n;
ny = 1;
}
if (mx*my == 0) {
mx = nx;
my = ny;
}
fprintf(stderr," Input %d bytes\n",n);
ctime1 = time(&ctime0);
switch (ifn % 8) {
case 0:
break;
case 1:
trans_bitmap(m,8*lx,8*ly,8*nx,8*ny,8*mx,8*my,c,d);
n = mx*my*8;
break;
case 2:
repli_bitmap(m,8*lx,8*ly,8*nx,8*ny,8*mx,8*my,c,d);
n = mx*my*8;
break;
case 3:
rotate_bitmap(m,8*nx,8*ny,c,d);
break;
case 4:
reverse_bitmap(m,8*nx,8*ny,c,d);
break;
case 5:
invert_bitmap(m,8*nx,8*ny,c,d);
break;
case 6:
scale_bitmap(m,8*nx,8*ny,8*mx,8*my,c,d);
n = mx*my*8;
break;
case 7:
erode_bitmap(m,8*nx,8*ny,c,d);
break;
}
n += np;
ctime1 = time(&ctime0)-ctime1;
fprintf(stderr," Output %d bytes %d sec\n", n, ctime1);
for (i=0; i