pck.c

Go to the documentation of this file.
00001 /***********************************************************************
00002  *
00003  * mar345: pck.c
00004  *
00005  * Copyright by:        Dr. Claudio Klein
00006  *                      X-ray Research GmbH, Hamburg
00007  *
00008  * Version:     1.0
00009  * Date:        16/01/1997
00010  *
00011  ***********************************************************************/
00012 
00013 #include <stdio.h>
00014 #include <stddef.h>
00015 #include <math.h>
00016 #include <ctype.h>
00017 #include <string.h>
00018 
00019 #define BYTE char
00020 #define WORD short int
00021 #define LONG int
00022 
00023 #define PACKIDENTIFIER "\nCCP4 packed image, X: %04d, Y: %04d\n"
00024 #define PACKBUFSIZ BUFSIZ
00025 #define DIFFBUFSIZ 16384L
00026 #define max(x, y) (((x) > (y)) ? (x) : (y)) 
00027 #define min(x, y) (((x) < (y)) ? (x) : (y)) 
00028 #define abs(x) (((x) < 0) ? (-(x)) : (x))
00029 const LONG setbits[33] = {0x00000000L, 0x00000001L, 0x00000003L, 0x00000007L,
00030                           0x0000000FL, 0x0000001FL, 0x0000003FL, 0x0000007FL,
00031                           0x000000FFL, 0x000001FFL, 0x000003FFL, 0x000007FFL,
00032                           0x00000FFFL, 0x00001FFFL, 0x00003FFFL, 0x00007FFFL,
00033                           0x0000FFFFL, 0x0001FFFFL, 0x0003FFFFL, 0x0007FFFFL,
00034                           0x000FFFFFL, 0x001FFFFFL, 0x003FFFFFL, 0x007FFFFFL,
00035                           0x00FFFFFFL, 0x01FFFFFFL, 0x03FFFFFFL, 0x07FFFFFFL,
00036                           0x0FFFFFFFL, 0x1FFFFFFFL, 0x3FFFFFFFL, 0x7FFFFFFFL,
00037                           0xFFFFFFFFL};
00038 #define shift_left(x, n)  (((x) & setbits[32 - (n)]) << (n))
00039 #define shift_right(x, n) (((x) >> (n)) & setbits[32 - (n)])
00040 
00041 /***************************************************************************/
00042 
00043 /*
00044  * Function prototypes
00045  */
00046 
00047 LONG            *diff_words     (WORD *, int, int, LONG *, LONG );
00048 void            get_pck         (FILE *,           WORD *       );
00049 int             put_pck         (WORD *, int, int, int          );
00050 static int      pack_chunk      (                               );
00051 static void     unpack_word     (FILE *, int, int, WORD *       );
00052 static void     pack_longs      (                               );
00053 static int      bits            (                               );
00054 
00055 /***************************************************************************
00056  * Function: Put_pck
00057  ***************************************************************************/
00058 int  
00059 put_pck(WORD *img, int x, int y, int fdesc) 
00060 { 
00061 int             chunksiz, packsiz, nbits, next_nbits, tot_nbits;
00062 LONG            buffer[DIFFBUFSIZ];
00063 LONG            *diffs = buffer;
00064 LONG            *end = diffs - 1;
00065 LONG            done = 0;
00066 
00067         while(done < (x * y)) {
00068           
00069             end = diff_words(img, x, y, buffer, done);
00070             done += (end - buffer) + 1;
00071 
00072             diffs = buffer;
00073             while(diffs <= end) {
00074               
00075                 packsiz = 0;
00076                 chunksiz = 1;
00077                 nbits = bits(diffs, 1);
00078                 while(packsiz == 0) {
00079                   
00080                     if(end <= (diffs + chunksiz * 2))
00081                         packsiz = chunksiz;
00082                     else {
00083                 
00084                           next_nbits = bits(diffs + chunksiz, chunksiz); 
00085                           tot_nbits = 2 * max(nbits, next_nbits);
00086 
00087                           if(tot_nbits >= (nbits + next_nbits + 6))
00088                               packsiz = chunksiz;
00089                           else {
00090                               
00091                                 nbits = tot_nbits;
00092                                 if(chunksiz == 64)
00093                                     packsiz = 128;
00094                                   else
00095                                     chunksiz *= 2;
00096                           }
00097 
00098                     }
00099                 }
00100 
00101                 if ( pack_chunk(diffs, packsiz, nbits / packsiz, fdesc) == 0)
00102                         return( 0 );
00103                 diffs += packsiz;
00104              }
00105         }
00106         if ( pack_chunk(NULL, 0, 0, fdesc) == 0 );
00107                 return( 1 );
00108 
00109         return( 1 );
00110 }
00111 
00112 /***************************************************************************
00113  * Function: bits
00114  ***************************************************************************/
00115 static int 
00116 bits(LONG *chunk, int n)
00117 { 
00118   int size, maxsize, i;
00119 
00120   for (i = 1, maxsize = abs(chunk[0]); i < n; ++i)
00121     maxsize = max(maxsize, abs(chunk[i]));
00122   if (maxsize == 0)
00123     size = 0;
00124   else if (maxsize < 8)
00125     size = 4 * n;
00126   else if (maxsize < 16)
00127     size = 5 * n;
00128   else if (maxsize < 32)
00129     size = 6 * n;
00130   else if (maxsize < 64)
00131     size = 7 * n;
00132   else if (maxsize < 128)
00133     size = 8 * n;
00134   else if (maxsize < 65536)
00135     size = 16 * n;
00136   else
00137     size = 32 * n;
00138   return(size);
00139 }
00140 
00141 /***************************************************************************
00142  * Function: pack_chunk
00143  ***************************************************************************/
00144 static int
00145 pack_chunk(LONG *lng, int nmbr, int bitsize, int fdesc)
00146 { 
00147 static LONG     bitsize_encode[33] = {0, 0, 0, 0, 1, 2, 3, 4, 5, 0, 0,
00148                                       0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0,
00149                                       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7};
00150 LONG            descriptor[2], i, j;
00151 static BYTE     *buffer = NULL;
00152 static BYTE     *buffree = NULL;
00153 static int      bitmark;
00154 
00155         if(buffer == NULL) {
00156             buffree = buffer = (BYTE *) malloc(PACKBUFSIZ);
00157             bitmark = 0;
00158         }
00159 
00160         if(lng != NULL) {
00161             for (i = nmbr, j = 0; i > 1; i /= 2, ++j);
00162             descriptor[0] = j;
00163             descriptor[1] = bitsize_encode[bitsize];
00164             if((buffree - buffer) > (PACKBUFSIZ - (130 * 4))) {
00165                 if( write(fdesc, buffer,buffree - buffer) == -1 )
00166                         return( 0 );
00167                 buffer[0] = buffree[0];
00168                 buffree = buffer;
00169             }
00170             pack_longs(descriptor, 2, &buffree, &bitmark, 3);
00171             pack_longs(lng, nmbr, &buffree, &bitmark, bitsize);
00172          }
00173          else {
00174             if( write(fdesc,buffer,(buffree - buffer) + 1) == -1 )
00175                 return( 0 );
00176             free((void *) buffer);
00177             buffer = NULL;
00178          }
00179 
00180         return( 1 );
00181 }
00182 
00183 /***************************************************************************
00184  * Function: diff_words
00185  ***************************************************************************/
00186 LONG 
00187 *diff_words(WORD *word, int x, int y, LONG *diffs, LONG done)
00188 { 
00189 LONG i = 0;
00190 LONG tot = x * y;
00191 
00192         if(done == 0)
00193           { 
00194             *diffs = word[0];
00195             ++diffs;
00196             ++done;
00197             ++i;
00198           }
00199         while((done <= x) && (i < DIFFBUFSIZ))
00200           {
00201             *diffs = word[done] - word[done - 1];
00202             ++diffs;
00203             ++done;
00204             ++i;
00205           }
00206         while ((done < tot) && (i < DIFFBUFSIZ))
00207           {
00208             *diffs = word[done] - (word[done - 1] + word[done - x + 1] +
00209                      word[done - x] + word[done - x - 1] + 2) / 4;
00210             ++diffs;
00211             ++done;
00212             ++i;
00213           }
00214         return(--diffs);
00215 }
00216 
00217 /***************************************************************************
00218  * Function: pack_longs
00219  ***************************************************************************/
00220 static void
00221 pack_longs(LONG *lng, int n, BYTE **target, int *bit, int size)
00222   { 
00223         LONG mask, window;
00224         int valids, i, temp;
00225         int temp_bit = *bit;
00226         BYTE *temp_target = *target;
00227 
00228         if (size > 0)
00229           {
00230             mask = setbits[size];
00231             for(i = 0; i < n; ++i)
00232               {
00233                 window = lng[i] & mask;
00234                 valids = size;
00235                 if(temp_bit == 0)
00236                         *temp_target = (BYTE) window;
00237                   else
00238                     {
00239                       temp = shift_left(window, temp_bit);
00240                       *temp_target |= temp;
00241                     }
00242                  window = shift_right(window, 8 - temp_bit);
00243                 valids = valids - (8 - temp_bit);
00244                 if(valids < 0)
00245                     temp_bit += size;
00246                   else
00247                     {
00248                       while (valids > 0)
00249                         { 
00250                           *++temp_target = (BYTE) window;
00251                           window = shift_right(window, 8);
00252                           valids -= 8;
00253                         }
00254                       temp_bit = 8 + valids;
00255                     }
00256                 if(valids == 0)
00257                   { 
00258                     temp_bit = 0;
00259                     ++temp_target;
00260                   }
00261               }
00262             *target = temp_target;
00263             *bit = (*bit + (size * n)) % 8;
00264           }
00265 }
00266 
00267 /***************************************************************************
00268  * Function: get_pck
00269  ***************************************************************************/
00270 void 
00271 get_pck(FILE *fp, WORD *img)
00272 { 
00273 int x = 0, y = 0, i = 0, c = 0;
00274 char header[BUFSIZ];
00275 
00276         if ( fp == NULL ) return;
00277         rewind ( fp );
00278         header[0] = '\n';
00279         header[1] = 0;
00280 
00281         while ((c != EOF) && ((x == 0) || (y == 0))) {
00282                 c = i = x = y = 0;
00283 
00284                 while ((++i < BUFSIZ) && (c != EOF) && (c != '\n') && (x==0) && (y==0))
00285                         if ((header[i] = c = getc(fp)) == '\n')
00286                                 sscanf(header, PACKIDENTIFIER, &x, &y);
00287         }
00288 
00289         unpack_word(fp, x, y, img);
00290 }
00291 
00292 /***************************************************************************
00293  * Function: unpack_word
00294  ***************************************************************************/
00295 static void 
00296 unpack_word(FILE *packfile, int x, int y, WORD *img)
00297 {
00298 int             valids = 0, spillbits = 0, usedbits, total = x * y;
00299 LONG            window = 0L, spill, pixel = 0, nextint, bitnum, pixnum;
00300 static int      bitdecode[8] = {0, 4, 5, 6, 7, 8, 16, 32};
00301 
00302     while (pixel < total) {
00303         if (valids < 6) {
00304           if (spillbits > 0) {
00305                 window |= shift_left(spill, valids);
00306                 valids += spillbits;
00307                 spillbits = 0;
00308         }
00309         else {
00310                 spill = (LONG) getc(packfile);
00311                 spillbits = 8;
00312         }
00313     }
00314     else {
00315         pixnum = 1 << (window & setbits[3]);
00316         window = shift_right(window, 3);
00317         bitnum = bitdecode[window & setbits[3]];
00318         window = shift_right(window, 3);
00319         valids -= 6;
00320         while ((pixnum > 0) && (pixel < total)) {
00321                 if (valids < bitnum) {
00322                         if (spillbits > 0) {
00323                                 window |= shift_left(spill, valids);
00324                                 if ((32 - valids) > spillbits) {
00325                                         valids += spillbits;
00326                                         spillbits = 0;
00327                                 }
00328                                 else {
00329                                         usedbits = 32 - valids;
00330                                         spill = shift_right(spill, usedbits);
00331                                         spillbits -= usedbits;
00332                                         valids = 32;
00333                                 }
00334                         }
00335                         else {
00336                                 spill = (LONG) getc(packfile);
00337                                 spillbits = 8;
00338                         }
00339                 }
00340                 else {
00341                         --pixnum;
00342                         if (bitnum == 0) 
00343                                 nextint = 0;
00344                         else {
00345                                 nextint = window & setbits[bitnum];
00346                                 valids -= bitnum;
00347                                 window = shift_right(window, bitnum);
00348                                 if ((nextint & (1 << (bitnum - 1))) != 0)
00349                                         nextint |= ~setbits[bitnum];}
00350                                 if (pixel > x) {
00351                                         img[pixel] = (WORD) (nextint +
00352                                                 (img[pixel-1] + img[pixel-x+1] +
00353                                                 img[pixel-x] + img[pixel-x-1] + 2) / 4);
00354                                         ++pixel;
00355                                 }
00356                                 else if (pixel != 0) {
00357                                         img[pixel] = (WORD) (img[pixel - 1] + nextint);
00358                                         ++pixel;
00359                                 }
00360                                 else
00361                                         img[pixel++] = (WORD) nextint;
00362                         }
00363                 }
00364         }
00365    }
00366 }