/* 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