static int qtree_encode(char *outfile, int a[], int n, int nqx, int nqy, int nbitplanes) { /* int a[]; int n; physical dimension of row in a int nqx; length of row int nqy; length of column (<=n) int nbitplanes; number of bit planes to output */ int log2n, i, k, bit, b, bmax, nqmax, nqx2, nqy2, nx, ny; unsigned char *scratch, *buffer; /* * log2n is log2 of max(nqx,nqy) rounded up to next power of 2 */ nqmax = (nqx>nqy) ? nqx : nqy; log2n = (int) (log((float) nqmax)/log(2.0)+0.5); if (nqmax > (1<<log2n)) { log2n += 1; } /* * initialize buffer point, max buffer size */ nqx2 = (nqx+1)/2; nqy2 = (nqy+1)/2; bmax = (nqx2*nqy2+1)/2; /* * We're indexing A as a 2-D array with dimensions (nqx,nqy). * Scratch is 2-D with dimensions (nqx/2,nqy/2) rounded up. * Buffer is used to store string of codes for output. */ scratch = (unsigned char *) malloc(2*bmax); buffer = (unsigned char *) malloc(bmax); if ((scratch == (unsigned char *) NULL) || (buffer == (unsigned char *) NULL)) { ffpmsg("qtree_encode: insufficient memory"); return(DATA_COMPRESSION_ERR); } /* * now encode each bit plane, starting with the top */ for (bit=nbitplanes-1; bit >= 0; bit--) { /* * initial bit buffer */ b = 0; bitbuffer = 0; bits_to_go3 = 0; /* * on first pass copy A to scratch array */ qtree_onebit(a,n,nqx,nqy,scratch,bit); nx = (nqx+1)>>1; ny = (nqy+1)>>1; /* * copy non-zero values to output buffer, which will be written * in reverse order */ if (bufcopy(scratch,nx*ny,buffer,&b,bmax)) { /* * quadtree is expanding data, * change warning code and just fill buffer with bit-map */ write_bdirect(outfile,a,n,nqx,nqy,scratch,bit); goto bitplane_done; } /* * do log2n reductions */ for (k = 1; k<log2n; k++) { qtree_reduce(scratch,ny,nx,ny,scratch); nx = (nx+1)>>1; ny = (ny+1)>>1; if (bufcopy(scratch,nx*ny,buffer,&b,bmax)) { write_bdirect(outfile,a,n,nqx,nqy,scratch,bit); goto bitplane_done; } } /* * OK, we've got the code in buffer * Write quadtree warning code, then write buffer in reverse order */ output_nybble(outfile,0xF); if (b==0) { if (bits_to_go3>0) { /* * put out the last few bits */ output_nbits(outfile, bitbuffer & ((1<<bits_to_go3)-1), bits_to_go3); } else { /* * have to write a zero nybble if there are no 1's in array */ output_huffman(outfile,0); } } else { if (bits_to_go3>0) { /* * put out the last few bits */ output_nbits(outfile, bitbuffer & ((1<<bits_to_go3)-1), bits_to_go3); } for (i=b-1; i>=0; i--) { output_nbits(outfile,buffer[i],8); } } bitplane_done: ; } free(buffer); free(scratch); return(0); }
int fits_rcomp(int a[], /* input array */ int nx, /* number of input pixels */ unsigned char *c, /* output buffer */ int clen, /* max length of output */ int nblock) /* coding block size */ { Buffer bufmem, *buffer = &bufmem; /* int bsize; */ int i, j, thisblock; int lastpix, nextpix, pdiff; int v, fs, fsmask, top, fsmax, fsbits, bbits; int lbitbuffer, lbits_to_go; unsigned int psum; double pixelsum, dpsum; unsigned int *diff; /* * Original size of each pixel (bsize, bytes) and coding block * size (nblock, pixels) * Could make bsize a parameter to allow more efficient * compression of short & byte images. */ /* bsize = 4; */ /* nblock = 32; now an input parameter*/ /* * From bsize derive: * FSBITS = # bits required to store FS * FSMAX = maximum value for FS * BBITS = bits/pixel for direct coding */ /* switch (bsize) { case 1: fsbits = 3; fsmax = 6; break; case 2: fsbits = 4; fsmax = 14; break; case 4: fsbits = 5; fsmax = 25; break; default: ffpmsg("rdecomp: bsize must be 1, 2, or 4 bytes"); return(-1); } */ /* move out of switch block, to tweak performance */ fsbits = 5; fsmax = 25; bbits = 1<<fsbits; /* * Set up buffer pointers */ buffer->start = c; buffer->current = c; buffer->end = c+clen; buffer->bits_to_go = 8; /* * array for differences mapped to non-negative values */ diff = (unsigned int *) malloc(nblock*sizeof(unsigned int)); if (diff == (unsigned int *) NULL) { ffpmsg("fits_rcomp: insufficient memory"); return(-1); } /* * Code in blocks of nblock pixels */ start_outputing_bits(buffer); /* write out first int value to the first 4 bytes of the buffer */ if (output_nbits(buffer, a[0], 32) == EOF) { ffpmsg("rice_encode: end of buffer"); free(diff); return(-1); } lastpix = a[0]; /* the first difference will always be zero */ thisblock = nblock; for (i=0; i<nx; i += nblock) { /* last block may be shorter */ if (nx-i < nblock) thisblock = nx-i; /* * Compute differences of adjacent pixels and map them to unsigned values. * Note that this may overflow the integer variables -- that's * OK, because we can recover when decompressing. If we were * compressing shorts or bytes, would want to do this arithmetic * with short/byte working variables (though diff will still be * passed as an int.) * * compute sum of mapped pixel values at same time * use double precision for sum to allow 32-bit integer inputs */ pixelsum = 0.0; for (j=0; j<thisblock; j++) { nextpix = a[i+j]; pdiff = nextpix - lastpix; diff[j] = (unsigned int) ((pdiff<0) ? ~(pdiff<<1) : (pdiff<<1)); pixelsum += diff[j]; lastpix = nextpix; } /* * compute number of bits to split from sum */ dpsum = (pixelsum - (thisblock/2) - 1)/thisblock; if (dpsum < 0) dpsum = 0.0; psum = ((unsigned int) dpsum ) >> 1; for (fs = 0; psum>0; fs++) psum >>= 1; /* * write the codes * fsbits ID bits used to indicate split level */ if (fs >= fsmax) { /* Special high entropy case when FS >= fsmax * Just write pixel difference values directly, no Rice coding at all. */ if (output_nbits(buffer, fsmax+1, fsbits) == EOF) { ffpmsg("rice_encode: end of buffer"); free(diff); return(-1); } for (j=0; j<thisblock; j++) { if (output_nbits(buffer, diff[j], bbits) == EOF) { ffpmsg("rice_encode: end of buffer"); free(diff); return(-1); } } } else if (fs == 0 && pixelsum == 0) { /* * special low entropy case when FS = 0 and pixelsum=0 (all * pixels in block are zero.) * Output a 0 and return */ if (output_nbits(buffer, 0, fsbits) == EOF) { ffpmsg("rice_encode: end of buffer"); free(diff); return(-1); } } else { /* normal case: not either very high or very low entropy */ if (output_nbits(buffer, fs+1, fsbits) == EOF) { ffpmsg("rice_encode: end of buffer"); free(diff); return(-1); } fsmask = (1<<fs) - 1; /* * local copies of bit buffer to improve optimization */ lbitbuffer = buffer->bitbuffer; lbits_to_go = buffer->bits_to_go; for (j=0; j<thisblock; j++) { v = diff[j]; top = v >> fs; /* * top is coded by top zeros + 1 */ if (lbits_to_go >= top+1) { lbitbuffer <<= top+1; lbitbuffer |= 1; lbits_to_go -= top+1; } else { lbitbuffer <<= lbits_to_go; putcbuf(lbitbuffer & 0xff,buffer); for (top -= lbits_to_go; top>=8; top -= 8) { putcbuf(0, buffer); } lbitbuffer = 1; lbits_to_go = 7-top; } /* * bottom FS bits are written without coding * code is output_nbits, moved into this routine to reduce overheads * This code potentially breaks if FS>24, so I am limiting * FS to 24 by choice of FSMAX above. */ if (fs > 0) { lbitbuffer <<= fs; lbitbuffer |= v & fsmask; lbits_to_go -= fs; while (lbits_to_go <= 0) { putcbuf((lbitbuffer>>(-lbits_to_go)) & 0xff,buffer); lbits_to_go += 8; } } } /* check if overflowed output buffer */ if (buffer->current > buffer->end) { ffpmsg("rice_encode: end of buffer"); free(diff); return(-1); } buffer->bitbuffer = lbitbuffer; buffer->bits_to_go = lbits_to_go; } }