_BLOCK TRUNCATION COMPRESSION_ by Anton Kruger [LISTING ONE] /* File: btc4x4.c -- Author: Anton Kruger -- Revision: 1.0 * Copyright (c) Truda Software * 215 Marengo Rd, #2, Oxford, IA 52322-9383 * Description: Contains routines for performing 4x4 block truncation * compression on 8-bit, 256x256 monochrome images. * Compilers: MSC 5.1. */ /* *** Headers *** */ #include #include #include /* *** Typedefs and defines *** */ typedef unsigned char byte; typedef unsigned int word; #define IOBUFFSIZE 2048 /* size of i/o buffers */ /* *** Function prototypes *** */ void main(int argc, char *argv[]); void btc4x4(FILE *fp1, FILE * fp2); void GetStats(byte * block,byte *a,byte *b,byte *mean); int GetBlock(byte *block, FILE *fp); void PutCode(byte a, byte b, word code, FILE *fp); void inform(char *mess); void main(int argc, char *argv[]) { /* A short driver routine for "btc4x4.c", that performs block truncation ** compression on an image file. */ FILE *fp1,*fp2; if (argc < 3){ inform("Usage: BTC4x4 infile outfile\n\n"); inform("infile is a 256x256 binary image file\n"); inform("outfile is a BTC-compressed file\n"); exit(-1); } if ((fp1 = fopen(argv[1],"rb")) == NULL) { inform("ERROR: Could not open input file: "); inform(argv[1]); exit(-1); } setvbuf(fp1,(char *)NULL,_IOFBF,IOBUFFSIZE); if ((fp2 = fopen(argv[2],"wb")) == NULL) { inform("ERROR: Could not open output file: "); inform(argv[2]); exit(-1); } setvbuf(fp2,(char *)NULL,_IOFBF,IOBUFFSIZE); inform("Block Truncation Compression.\n"); inform(argv[1]); inform(" -> "); inform(argv[2]); inform("\nPlease wait...\n"); btc4x4(fp1, fp2); fclose(fp1); fclose(fp2); inform("Done!\n"); exit(0); } void btc4x4(FILE *fp1, FILE * fp2) { /* Block truncation compress the file connected to "fp1". The output goes ** to the file connected to "fp2". */ int i; byte a,b,mean; byte block[16]; word code; while (GetBlock(block,fp1) != EOF){ GetStats(block,&a,&b,&mean); code = 0; /* clear bits */ for (i=0;i<=15;i++) if (block[i] >= mean) code = code | (1<= "mean" , then compute "a", and "b". */ for (q=0,i=0;i<=15;i++) if ((float)block[i] >= m1) q++; if (q == 16){ *mean = (byte)(m1+0.5); *a = *b = *mean; /* all pixels are the same */ } else{ d = sqrt((double)q/(16.0-q)); atmp = m1 - sigma*d; btmp = m1 + sigma/d; if (atmp < (float)0) atmp = (float)0; if (btmp > (float)255) btmp = (float)255; /* Round values to nearest integer */ *a = (byte)(0.5+atmp); *b = (byte)(0.5+btmp); *mean = (byte)(m1+0.5); } } int GetBlock(byte *block, FILE *fp) { /* This routine gets a block of 4x4 pixels from the file connected to "fp". ** Normally it returns 1. If at EOF, or errors occur, it returns EOF. */ static int bp = 256; static byte buffer[4][256]; int i,j; /* If the 4-line buffer is empty, fill it. If it cannot be filled for some ** reason, return EOF. Otherwise, reset the buffer pointer "bp". */ if (bp == 256){ for (j=0;j<=3;j++) if (fread(buffer[j],1,256,fp) != 256) return(EOF); bp = 0; } /* Get 16 pixels from the 4-line buffer. Then update the buffer ** pointer "bp", and return to caller. */ for (j=0;j<=3;j++) for (i=0;i<=3;i++) block[i+4*j] = buffer[j][bp+i]; bp = bp+4; return(1); } void PutCode(byte a, byte b, word code, FILE *fp) { /* This routine writes "a", "b", and the block truncation "code" to ** the file connected to "fp". */ fputc((byte)a,fp); fputc((byte)b,fp); fputc((byte)(code & 255),fp); /* LSB first */ fputc((byte)((code>>8) & 255),fp); /* MSB second */ } void inform(char *mess) { fprintf(stderr,"%s",mess); } [LISTING TWO] /* File: btd4x4.c -- Author: Anton Kruger -- Revision: 1.0 * Copyright (c) Truda Software * 215 Marengo Rd, #2, Oxford, IA 52322-9383 * Description: Contains routines for performing 4x4 block truncation * decompression; assumes input files were compressed with "btc4x4". * Compilers: MSC 5.1. */ /* *** Headers *** */ #include #include #include /* *** Typedefs and defines *** */ typedef unsigned char byte; typedef unsigned int word; #define IOBUFFSIZE 2048 /* size of i/o buffers */ /* *** Function prototypes *** */ void main(int argc, char *argv[]); void btd4x4(FILE *fp1, FILE * fp2); int GetCode(byte *a, byte *b, word * code, FILE *fp); int PutBlock(byte *block, FILE *fp); void inform(char *mess); void main(int argc, char *argv[]) { /* A diver routine for "btd4x4.c", that decompresses a block truncation ** compressed file. */ FILE *fp1,*fp2; if (argc < 3){ inform("Usage: BTD4x4 infile outfile\n\n"); inform("infile is a BTC-compressed file\n"); inform("outfile is a 256x256 binary image file\n"); exit(-1); } if ((fp1 = fopen(argv[1],"rb")) == NULL) { inform("ERROR: Could not open input file: "); inform(argv[1]); exit(-1); } setvbuf(fp1,(char *)NULL,_IOFBF,IOBUFFSIZE); if ((fp2 = fopen(argv[2],"wb")) == NULL) { inform("ERROR: Could not open output file: "); inform(argv[2]); exit(-1); } setvbuf(fp2,(char *)NULL,_IOFBF,IOBUFFSIZE); inform("Block Truncation Decompression.\n"); inform(argv[1]); inform(" -> "); inform(argv[2]); inform("\nPlease wait...\n"); btd4x4(fp1, fp2); fclose(fp1); fclose(fp2); inform("Done!\n"); exit(0); } void btd4x4(FILE *fp1, FILE * fp2) { /* Decompress the block truncation compressed file connected to "fp1". ** The output goes to the file connected to "fp2". */ int i; byte a,b; byte block[16]; word code; while (GetCode(&a,&b,&code,fp1) != EOF){ for (i=0;i<=15;i++) if (code & (1 << i)) /* is bit "i" set ? */ block[i] = b; else block[i] = a; PutBlock(block,fp2); } /* The 4-line buffer maintained by "PutBlock" should be full at this point. ** Output one last dummy block. This will not be written to the output ** file, and only serves to flush that buffer. */ PutBlock(block,fp2); } int PutBlock(byte *block, FILE *fp) { /* This routine writes a block of 4x4 pixels to the file connected to "fp". ** Normally it returns 1. If at EOF, or errors occur, it returns EOF. */ static int bp = 0; static byte buffer[4][256]; int i,j; /* If the 4-line buffer is full, flush it. If it cannot be flushed for some ** reason, return EOF. Otherwise, reset the buffer pointer "bp". */ if (bp == 256){ for (j=0;j<=3;j++) if (fwrite(buffer[j],1,256,fp) != 256) return(EOF); bp = 0; } /* Place 16 pixels in the 4-line buffer. Then update the buffer pointer ** "bp", and return to caller. */ for (j=0;j<=3;j++) for (i=0;i<=3;i++) buffer[j][bp+i] = block[i+4*j]; bp = bp+4; return(1); } int GetCode(byte *a, byte *b, word * code, FILE *fp) { /* This routine gets "a", "b", and the block truncation "code" from the ** file connected to "fp". Normally it returns 1. If at end of file, or ** errors occur, it returns EOF. */ *a = (byte)fgetc(fp); *b = (byte)fgetc(fp); *code = fgetc(fp); /* LSB first */ *code = (fgetc(fp) << 8) + *code; /* MSB second */ if (feof(fp) || ferror(fp)) return(EOF); else return(1); } void inform(char *mess) { fprintf(stderr,"%s",mess); }