home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Voyagers to the Outer Planets 2: Uranus
/
VoyagestotheOuterPlanetsVol2.cdr
/
software
/
decomp.c
< prev
next >
Wrap
C/C++ Source or Header
|
1988-09-14
|
23KB
|
507 lines
#include <stdio.h>
/****************************************************************************
*_TITLE node_def - definition of NODE type *
*_ARGS NONE *
*_DESCR node_def defines the basic element of a node used to build the *
* Huffman tree for data decompression. The code declares a user *
* defined type that consists of an integer field and a left and right *
* pointer field. The *right and *left pointers point to another *
* NODE structure, a recursive reference of itself. The dn field will *
* contain a -1 if the node is not a leaf (or end node) otherwise it *
* will contain the pixel difference value. This value is then *
* subtracted from the preceding pixel and 256 is added to normalize *
* the actual first difference value. The left and right pointers are *
* undefined (NULL) if the node is a leaf, otherwise they will point *
* to the next adjacent node in the tree. *
*_LIMS This definition has been tested on VAX 750 (VMS 4.7), DEC MicroVAX *
* (ULTRIX 2.2), SUN Workstation (UNIX 4.2, release 3.4), and an *
* IBM PC (MICROSOFT 4.0, 3.0 compilers). When converting to other *
* systems, check for portability conflicts. *
*_HIST 17-FEB-88 Kris Becker USGS, Flagstaff Original Version *
*_END *
*****************************************************************************/
typedef struct leaf
{
struct leaf *right;
short int dn;
struct leaf *left;
} NODE;
/*************************************************************************
Declare the tree pointer. This pointer will hold the root of the tree
once the tree is created by the accompanying routine huff_tree.
**************************************************************************/
NODE *tree;
void decompress(ibuf,obuf,nin,nout)
/****************************************************************************
*_TITLE decompress - decompresses image lines stored in compressed format *
*_ARGS TYPE NAME I/O DESCRIPTION */
char *ibuf; /* I Compressed data buffer */
char *obuf; /* O Decompressed image line */
long int *nin; /* I Number of bytes on input buffer */
long int *nout; /* I Number of bytes in output buffer */
/*
*_DESCR This routine decompresses Huffman encoded compressed data. Huffman *
* coding uses a variable number of bits to encode different values of *
* the original data. The compression results because the most *
* frequently occurring data value is represented in the smallest *
* number of bits. This routine is called by a main program to *
* decompress an image line contained in ibuf. The first byte of *
* ibuf contains the actual first pixel value of the line. All *
* other bytes in the input line contain the compressed data. The *
* output buffer, obuf, will contain the decompressed image line *
* after the call to the "dcmprs" routine. *
*_LIMS This routine has been tested on VAX 750 (VMS 4.6), DEC MicroVAX *
* (ULTRIX 2.2), SUN Workstation (UNIX 4.2, release 3.4), and an *
* IBM PC (MICROSOFT 4.0, 3.0 compilers). When converting to other *
* systems, check for portability conflicts. *
* Please note that the calling convention used for this routine *
* follow VAX/VMS FORTRAN pass-by-reference standards to allow linking *
* to FORTRAN calling routines. C programmers must be aware of this *
* when coding calling routines. *
*_HIST 17-FEB-88 Kris Becker USGS, Flagstaff Original C Version *
*_END *
*****************************************************************************/
{
/* The external root pointer to tree */
extern NODE *tree;
/* Declare functions called from this routine */
void dcmprs();
/*************************************************************************
This routine is fairly simple as it's only function is to call the
routine dcmprs.
**************************************************************************/
dcmprs(ibuf,obuf,nin,nout,tree);
return;
}
void decmpinit(hist)
/***************************************************************************
*_TITLE decmpinit - initializes the Huffman tree *
*_ARGS TYPE NAME I/O DESCRIPTION */
long int *hist; /* I First-difference histogram. This *
* array MUST be dimensioned to at *
* least 511 elements. There are a *
* total of 511 first-differerence *
* values. The least first- *
* difference value is 0-255 or -255, *
* while the largest first-difference *
* is 255-0 or 255. The first- *
* difference values are normalized *
* for table use to the range 1 to *
* 511 by adding 256 to each *
* difference. */
/*
*_DESCR This routine is relatively simple; it is responsible for creating *
* the Huffman tree from the first difference histogram of the image. *
* In a first difference histogram, the first byte in each image line *
* is the actual pixel value. All other pixels are obtained by *
* subtracting the first difference value at the current pixel from *
* the actual value of the preceding pixel and adding 256 to provide *
* a positive number. The I-th element of the array "hist" should be *
* the frequency of occurances for the value I. Note the declaration *
* of the pointer tree. This external variable is defined by this *
* routine. It returns the pointer to the root of the Huffman tree *
* created by "huff_tree". The huff_tree routine will automatically *
* swap the low and high order bytes of the 32-bit elements in the *
* of the first difference histogram for the computer systems which *
* store integers in "most significant byte first" order. For computer*
* systems which store 32-bit words in "least significant byte first *
* order, no swapping of the bytes occurs.
*_LIMS This routine has been tested on VAX 750 (VMS 4.6), DEC MicroVAX *
* (ULTRIX 2.2), SUN Workstation (UNIX 4.2, release 3.4), and an *
* IBM PC (MICROSOFT 4.0, 3.0 compilers). When converting to other *
* systems, check for portability conflicts. *
*_HIST 17-FEB-88 Kris Becker USGS, Flagstaff Original C Version *
*_END *
****************************************************************************/
{
extern NODE *tree; /* Huffman tree root pointer */
/* Specify the calling function to initialize the tree */
NODE *huff_tree();
/****************************************************************************
Simply call the huff_tree routine and return.
*****************************************************************************/
tree = huff_tree(hist);
return;
}
NODE *huff_tree(hist)
/****************************************************************************
*_TITLE huff_tree - constructs the Huffman tree; returns pointer to root *
*_ARGS TYPE NAME I/O DESCRIPTION */
long int *hist; /* I First difference histogram */
/*
*_DESC huff_tree constructs a binary Huffman tree and returns the pointer *
* to the root of the tree. The implementation here may not be the *
* most efficient, but conditions of the algorithm used to compress *
* the data governed the design of this algorithm. Other *
* implementations are available in FORTRAN and VAX MACRO Assembler. *
* This routine allocates memory as needed to construct the tree. *
* The tree is implemented as a user defined structure described *
* above. The algorithm uses an array of node pointers allocated *
* for all possible values. This array is then initialized by *
* assigning all leafs to the array. Each leaf has a cooresponding *
* frequency assigned to it and the frequencies are sorted in ascending*
* order. All zero frequencies are ignored and tree construction *
* begins. The tree is built by combining the two least occuring *
* frequencies into one node. This new node is treated as one by *
* adding together the two frequencies forming a cummulative frequency *
* of the combining nodes. The second smallest node now contains the *
* newly combined node and the smallest node is deleted from the list. *
* The frequency list is then resorted to determine the next two node *
* combinations until one node is left. This node will be the root of *
* the tree. This pointer is then returned to the calling routine. *
*_LIMS This routine has been tested on VAX 750 (VMS 4.6), DEC MicroVAX *
* (ULTRIX 2.2), SUN Workstation (UNIX 4.2, release 3.4), and an *
* IBM PC (MICROSOFT 4.0, 3.0 compilers). When converting to other *
* systems, check for portability conflicts. *
* This routine uses the memory allocation routine "malloc". Check *
* for call specifications and casting portability of these features *
* for the compiler in used. *
*_HIST 17-FEB-88 Kris Becker USGS, Flagstaff Original C Version *
*_END *
*****************************************************************************/
{
/* Local variables used */
long int freq_list[512]; /* Histogram frequency list */
NODE **node_list; /* DN pointer array list */
register long int *fp; /* Frequency list pointer */
register NODE **np; /* Node list pointer */
register long int num_freq; /* Number non-zero frequencies in histogram */
long int sum; /* Sum of all frequencies */
register short int num_nodes; /* Counter for DN initialization */
register short int cnt; /* Miscellaneous counter */
short int znull = -1; /* Null node value */
register NODE *temp; /* Temporary node pointer */
/* Functions called */
void sort_freq();
NODE *new_node();
char *malloc();
/***************************************************************************
Allocate the array of nodes from memory and initialize these with numbers
corresponding with the frequency list. There are only 511 possible
permutations of first difference histograms. There are 512 allocated
here to adhere to the FORTRAN version.
****************************************************************************/
fp = freq_list;
node_list = (NODE **) malloc(sizeof(temp)*512);
if (node_list == NULL)
{
printf("\nOut of memory in huff_tree!\n");
exit(1);
}
np = node_list;
for (num_nodes=1, cnt=512 ; cnt-- ; num_nodes++)
{
/**************************************************************************
The following code has been added to standardize the VAX byte order
for the "long int" type. This code is intended to make the routine
as machine independant as possible.
***************************************************************************/
unsigned char *cp = (unsigned char *) hist++;
unsigned long int j;
short int i;
for (i=4 ; --i >= 0 ; j = (j << 8) | *(cp+i));
/* Now make the assignment */
*fp++ = j;
temp = new_node(num_nodes);
*np++ = temp;
}
(*--fp) = 0; /* Ensure the last element is zeroed out. */
/***************************************************************************
Now, sort the frequency list and eliminate all frequencies of zero.
****************************************************************************/
num_freq = 512;
sort_freq(freq_list,node_list,num_freq);
fp = freq_list;
np = node_list;
for (num_freq=512 ; (*fp) == 0 && (num_freq) ; fp++, np++, num_freq--);
/***************************************************************************
Now create the tree. Note that if there is only one difference value,
it is returned as the root. On each interation, a new node is created
and the least frequently occurring difference is assigned to the right
pointer and the next least frequency to the left pointer. The node
assigned to the left pointer now becomes the combination of the two
nodes and it's frequency is the sum of the two combining nodes.
****************************************************************************/
for (temp=(*np) ; (num_freq--) > 1 ; )
{
temp = new_node(znull);
temp->right = (*np++);
temp->left = (*np);
*np = temp;
*(fp+1) = *(fp+1) + *fp;
*fp++ = 0;
sort_freq(fp,np,num_freq);
}
return temp;
}
NODE *new_node(value)
/****************************************************************************
*_TITLE new_node - allocates a NODE structure and returns a pointer to it *
*_ARGS TYPE NAME I/O DESCRIPTION */
short int value; /* I Value to assign to DN field */
/*
*_DESC new_node allocates virtual memory for a new NODE structure. It *
* initializes the right and left pointers to NULL and the dn field *
* is initialized to the passed parameter 'value'. *
*_LIMS This routine has been tested on VAX 750 (VMS 4.6), DEC MicroVAX *
* (ULTRIX 2.2), SUN Workstation (UNIX 4.2, release 3.4), and an *
* IBM PC (MICROSOFT 4.0, 3.0 compilers). When converting to other *
* systems, check for portability conflicts. *
* This routine uses the malloc routine that requests virtual memory *
* from the system. Most C libraries have some version of this *
* function. Check the reference manuals for compatibility. *
*_HIST 17-FEB-88 Kris Becker USGS, Flagstaff Original Version *
*_END *
*****************************************************************************/
{
NODE *temp; /* Pointer to the memory block */
char *malloc(); /* Memory allocation function */
/***************************************************************************
Allocate the memory and intialize the fields.
****************************************************************************/
temp = (NODE *) malloc(sizeof(NODE));
if (temp != NULL)
{
temp->right = NULL;
temp->dn = value;
temp->left = NULL;
}
else
{
printf("\nOut of memory in new_node!\n");
exit(1);
}
return temp;
}
void sort_freq(freq_list,node_list,num_freq)
/****************************************************************************
*_TITLE sort_freq - sorts frequency and node lists in increasing freq. order*
*_ARGS TYPE NAME I/O DESCRIPTION */
long int *freq_list; /* I Pointer to frequency list */
NODE **node_list; /* I Pointer to array of node pointers */
long int num_freq; /* I Number of values in freq list */
/*
*_DESCR This routine uses an insertion sort to reorder a frequency list *
* in order of increasing frequency. The corresponding elements *
* of the node list are reordered to maintain correspondence. The *
* node list is actually a pointer to an array of pointers to tree *
* nodes.
*_LIMS This routine has been tested on VAX 750 (VMS 4.6), DEC MicroVAX *
* (ULTRIX 2.2), SUN Workstation (UNIX 4.2, release 3.4), and an *
* IBM PC (MICROSOFT 4.0, 3.0 compilers). When converting to other *
* systems, check for portability conflicts. *
*_HIST 17-FEB-88 Kris Becker USGS, Flagstaff Original C Version *
*_END *
*****************************************************************************/
{
/* Local Variables */
register long int *i; /* primary pointer into freq_list */
register long int *j; /* secondary pointer into freq_list */
register NODE **k; /* primary pointer to node_list */
register NODE **l; /* secondary pointer into node_list */
long int temp1; /* temporary storage for freq_list */
NODE *temp2; /* temporary storage for node_list */
register long int cnt; /* count of list elements */
/************************************************************************
Save the current element - starting with the second - in temporary
storage. Compare with all elements in first part of list moving
each up one element until the element is larger. Insert current
element at this point in list.
*************************************************************************/
if (num_freq <= 0) return; /* If no elements or invalid, return */
for (i=freq_list, k=node_list, cnt=num_freq ; --cnt ; *j=temp1, *l=temp2)
{
temp1 = *(++i);
temp2 = *(++k);
for (j = i, l = k ; *(j-1) > temp1 ; )
{
*j = *(j-1);
*l = *(l-1);
j--;
l--;
if ( j <= freq_list) break;
}
}
return;
}
void dcmprs(ibuf,obuf,nin,nout,root)
/****************************************************************************
*_TITLE dcmprs - decompresses Huffman coded compressed image lines *
*_ARGS TYPE NAME I/O DESCRIPTION */
char *ibuf; /* I Compressed data buffer */
char *obuf; /* O Decompressed image line */
long int *nin; /* I Number of bytes on input buffer */
long int *nout; /* I Number of bytes in output buffer */
NODE *root; /* I Huffman coded tree */
/*
*_DESCR This routine follows a path from the root of the Huffman tree to *
* one of it's leaves. The choice at each branch is decided by the *
* successive bits of the compressed input stream. Left for 1, right *
* for 0. Only leaf nodes have a value other than -1. The routine *
* traces a path through the tree until it finds a node with a value *
* not equal to -1 (a leaf node). The value at the leaf node is *
* subtracted from the preceeding pixel value plus 256 to restore *
* the uncompressed pixel. This algorithm is then repeated until the *
* entire line has been processed. *
*_LIMS This routine has been tested on VAX 750 (VMS 4.6), DEC MicroVAX *
* (ULTRIX 2.2), SUN Workstation (UNIX 4.2, release 3.4), and an *
* IBM PC (MICROSOFT 4.0, 3.0 compilers). When converting to other *
* systems, check for portability conflicts. *
* Please note that the calling convention used for these routines *
* follow VAX/VMS FORTRAN pass-by-reference standards to allow *
* linking to FORTRAN calling routines. C programmers must be aware *
* of this when coding calling routines. *
*_HIST 17-FEB-88 Kris Becker USGS, Flagstaff Original C Version *
*_END *
*****************************************************************************/
{
/* Local Variables */
register NODE *ptr = root; /* pointer to position in tree */
register unsigned char test; /* test byte for bit set */
register unsigned char idn; /* input compressed byte */
register char odn; /* last dn value decompressed */
char *ilim = ibuf + *nin; /* end of compressed bytes */
char *olim = obuf + *nout; /* end of output buffer */
/**************************************************************************
Check for valid input values for nin, nout and make initial assignments.
***************************************************************************/
if (ilim > ibuf && olim > obuf)
odn = *obuf++ = *ibuf++;
else
{
printf("\nInvalid byte count in dcmprs!\n");
exit(1);
}
/**************************************************************************
Decompress the input buffer. Assign the first byte to the working
variable, idn. An arithmatic and (&) is performed using the variable
'test' that is bit shifted to the right. If the result is 0, then
go to right else go to left.
***************************************************************************/
for (idn=(*ibuf) ; ibuf < ilim ; idn =(*++ibuf))
{
for (test=0x80 ; test ; test >>= 1)
{
ptr = (test & idn) ? ptr->left : ptr->right;
if (ptr->dn != -1)
{
if (obuf >= olim) return;
odn -= ptr->dn + 256;
*obuf++ = odn;
ptr = root;
}
}
}
return;
}