/* -*-C-*- ****************************************************************************** * * File: dhuff.c * RCS: $Header: /ImageMagick/delegates/fpx/jpeg/dhuff.c,v 1.3 2000/12/23 22:37:48 bfriesen Exp $ * Description: builds Huffman tree, and performs Huffman decoding * Author: Hugh P. Nguyen * Created: Fri Dec 4 11:04:22 1992 * Modified: Fri Dec 4 11:04:53 1992 * Language: C * Package: Hewlett-Packard JPEG Encoder/Decoder * * Copyright (c) 1999 Digital Imaging Group, Inc. * For conditions of distribution and use, see copyright notice * in Flashpix.h * ****************************************************************************** */ #include #include #include "jpegconf.h" #include "decoder.h" #include "dbuffer.h" #include "dectile.h" #include "djpeg.h" #include "dparser.h" #include "fpxmem.h" #include "dhuff.h" /**/ static void Assign_Code( unsigned int code, /* code word */ int val, /* Huffman value - symbol */ int nbits, /* number of bits in code word */ HUFFMAN_ELEM *huffelem) /* Huffman table to receive the assignment */ { int i, bound; bound = (code + 1) << (8 - nbits); for (i = (code << (8 - nbits)); i < bound; i++) { huffelem[i].codelen = (unsigned char) nbits; huffelem[i].value = (unsigned char) val; huffelem[i].hufftree= NULL; } } static void Assign_Tree( unsigned int start_code, /* starting code */ int ncodes, /* total number of codes to be assigned */ int start_index, /* index to huffval = value for start_code */ int nbits, /* number of bits in code words */ HUFFMAN_ELEM *huffelem) /* Huffman table to receive the assignment */ { int first, last, i, index, mask; HUFFMAN_TREE *hufftree; index = nbits - 9; first = (int) (start_code >> (index + 1)); last = (start_code + ncodes - 1) >> (index + 1); if (first > 255) return; if (last > 255) last = 255; mask = (1 << (index+1)) - 1; if (first == last) { hufftree = huffelem[first].hufftree; hufftree->mincode[index] = start_code & mask; hufftree->maxcode[index] = (start_code+ncodes-1) & mask; hufftree->valptr [index] = start_index - hufftree->mincode[index]; } else { hufftree = huffelem[first].hufftree; hufftree->mincode[index] = start_code & mask; hufftree->maxcode[index] = mask; hufftree->valptr [index] = start_index - hufftree->mincode[index]; start_index += ((first+1) << (index+1)) - start_code; for (i = first+1; i < last; i++) { hufftree = huffelem[i].hufftree; hufftree->mincode[index] = 0; hufftree->maxcode[index] = mask; hufftree->valptr [index] = start_index; start_index += mask+1; } hufftree = huffelem[last].hufftree; hufftree->mincode[index] = 0; hufftree->maxcode[index] = (start_code+ncodes-1) & mask; hufftree->valptr [index] = start_index; } } DHUFF_TABLE *Build_Huffman_Table( int huff_class, int ident, unsigned char *bits, /* bit-length frequency (indexed on length) */ unsigned char *huffval) /* huffman values - see JPEG doc */ { DHUFF_TABLE *huff_table; HUFFMAN_ELEM *huff_elem; HUFFMAN_TREE *huff_tree; int *huff_val; int bitlen, j, k, freq, ptr; unsigned int code; if ((huff_table =(DHUFF_TABLE *) FPX_malloc(sizeof(DHUFF_TABLE)))==NULL) { return(NULL); } huff_table->huff_class = huff_class; huff_table->ident = ident; huff_elem = huff_table->huffelem; huff_val = huff_table->huffval; /* Fill huff_table */ code = 0; for (bitlen = 1; bitlen <= 8; bitlen++) { /* Build primary table */ freq = *bits++; if (freq) { for (j = 0; j < freq; j++) { Assign_Code(code++, *huffval++, bitlen, huff_table->huffelem); } } code <<= 1; } code >>= 1; huff_elem = huff_table->huffelem; for (j = 0; j < (int)code; j++) huff_elem[j].hufftree = NULL; for (j = code; j < 256; j++) { huff_elem[j].codelen = 0; /* huff_elem[j].value = -1; */ if ((huff_tree =(HUFFMAN_TREE *)FPX_malloc(sizeof(HUFFMAN_TREE)))==NULL) { for (k = code; k < j; k++) { if(huff_elem[k].hufftree) { /* CHG_JPEG_MEM_FIX - added check & clear */ FPX_free(huff_elem[k].hufftree); huff_elem[k].hufftree = NULL; } } FPX_free(huff_table); return(NULL); } else { huff_elem[j].hufftree = huff_tree; for (k = 0; k < 8; k++) { huff_elem[j].hufftree->mincode[k] = huff_elem[j].hufftree->maxcode[k] = -1; } } } code <<= 1; ptr = 0; for (bitlen = 9; bitlen <= 16; bitlen++) { /* Build Huffman trees */ freq = *bits++; if (freq) { for (j = 0; j < freq; j++) { *huff_val++ = *huffval++; } Assign_Tree(code, freq, ptr, bitlen, huff_elem); code += freq; ptr += freq; } code <<= 1; } return(huff_table); } int Decode_Huffman( DB_STATE *db_state, DHUFF_TABLE *huff_table) { register HUFFMAN_ELEM *huff_elem; register int n, code, *p; HUFFMAN_TREE *huff_tree; huff_elem = huff_table->huffelem + DB_Get_Byte(db_state); n = huff_elem->codelen; if (n) { PUSH_BACK_BITS(8-n); return(huff_elem->value); } else { /* decode bit by bit using huffman tree */ huff_tree = huff_elem->hufftree; #ifdef DEBUG if (huff_tree == NULL) { debug("Huffman Tree is NULL"); return(0); } #endif code = DB_Get_Byte(db_state); for (p = huff_tree->maxcode, n = 7; (n >= 0) && ((code >> n) > *p++); n--); if (n >= 0) { /* code > maxcode */ PUSH_BACK_BITS(n); return(huff_table->huffval[(code >> n) + huff_tree->valptr[7-n]]); } else { /* fail to decode - Return 0 (autom. resync) */ #ifdef WARNING warning(WARNING_DATA); #endif return(0); } } }