📄 deflatehuffmanencoder.cpp
字号:
//
// Copyright (c) 1997,1998 Colosseum Builders, Inc.
// All rights reserved.
//
// Colosseum Builders, Inc. makes no warranty, expressed or implied
// with regards to this software. It is provided as is.
//
// See the README.TXT file that came with this software for restrictions
// on the use and redistribution of this file or send E-mail to
// info@colosseumbuilders.com
//
//
// Title: PngHuffmanEncoder implementation
//
// Author: John M. Miano miano@colosseumbuilders.com
//
// Description:
//
// This class handles Huffman Encoding for PNG images.
//
#include <string>
#include "deflatehuffmanencoder.h"
#include "checks.h"
#include "systemspecific.h"
using namespace std ;
const int MAXCODELENGTH = 15 ;
namespace ColosseumPrivate
{
//
// Description:
//
// Default Class Constructor
//
DeflateHuffmanEncoder::DeflateHuffmanEncoder (unsigned int valuecount)
: value_count (valuecount),
frequencies (valuecount),
ehufsi (valuecount),
ehufco (valuecount)
{
reset () ;
return ;
}
//
// Description:
//
// After Huffman codes have been generated the object is in a state
// where it cannot be used to create a new set of code. This function
// places the object in a state where it can be reused to generate a
// new set of Huffman Codes.
//
void DeflateHuffmanEncoder::reset ()
{
for (unsigned int ii = 0 ; ii < value_count ; ++ ii)
{
ehufco [ii] = 0 ;
ehufsi [ii] = 0 ;
frequencies [ii] = 0 ;
}
return ;
}
//
// Description:
//
// Function to increment the frequency for a value.
//
// Parameters:
// value: The value to increase the usage frequency of.
//
void DeflateHuffmanEncoder::incrementFrequency (unsigned int value)
{
++ frequencies [value] ;
return ;
}
//
// Description:
//
// This function generates the Huffman Codes using the frequency data.
//
// The outputs from this function are the following member variables:
//
// ehufsi [n] : The length of the Huffman Code for value "n"
// ehufco [n] : The Huffman Code for value "n"
//
// The first two arrays are used to encode Huffman values. The last two
// are for writing the table to the output file.
//
// The code generation process is:
//
// 1. Arrange the Huffman Values into a binary tree so that the most
// frequently used codes are closest to the root of the tree. At the end
// of this process the temporary array codesize [n] contains the length
// of the pure Huffman code for the value "n"
//
// 2. Determine the number of Huffman Codes of for each code length. This
// step places the number of codes of length "n+1" in huffbits[].
//
// 3. The Default places limites on the size of Huffman Codes. If
// codes longer that the specified limits were generated in the
// previous steps then we need to reduce the maximum depth of the
// tree created in step 1. The input and output to this step is the
// array huffbits[] created in the previous step.
//
// 4. Sort the Huffman values in code length order. codesize [n] is the
// input to this step and huffvalues [n] is the output. At this point
// all the information needed to write the Huffman Table to the output
// stream has been found.
//
// 5. Determine the code size for each value. At the end of this step
// the temporary array huffsizes [n] is the Huffman code length for
// huffvalues [n].
//
// 6. Determine the Huffman code for each value. The temporary array
// huffcodes [n] is the Huffman Code of length huffsizes [n] for
// the value huffvalue [n].
//
// 7. Using huffsizes [] and huffcodes created in steps 6 and 7 create
// the arrays ehufco [n] and ehufsi [n] giving the Huffman Code and
// Code Size for n.
//
// Parameters:
// maxcodelength: The maximum code length to generate
//
void DeflateHuffmanEncoder::buildTable (unsigned int maxcodelength)
{
bool codestoolong = false ;
// The tmp array is used for validating the integrity of the Huffman code
// table. We need a temporary array since frequencies [] gets trashed
// during the code generation process.
Array<unsigned int> tmpfrequencies (frequencies) ;
// Build the Huffman Code Length Lists
Array<int> others (value_count, -1) ;
Array<unsigned int> codesize (value_count, 0) ;
while (true)
{
// Find the two smallest non-zero values
int v1 = -1 ;
int v2 = -1 ;
for (unsigned int ii = 0 ; ii < value_count ; ++ ii)
{
if (frequencies [ii] != 0)
{
if (v1 < 0 || frequencies [ii] <= frequencies [v1])
{
v2 = v1 ;
v1 = ii ;
}
else if (v2 < 0 || frequencies [ii] <= frequencies [v2])
{
v2 = ii ;
}
}
}
if (v2 < 0)
{
if (v1 < 0)
return ; // No codes defined
if (codesize [v1] == 0)
codesize [v1] = 1 ; // Only one code defined
break ;
}
// Join the two tree nodes.
frequencies [v1] = frequencies [v1] + frequencies [v2] ;
frequencies [v2] = 0 ;
for (++ codesize [v1] ; others [v1] >= 0 ; ++ codesize [v1])
v1 = others [v1] ;
others [v1] = v2 ;
for (++ codesize [v2] ; others [v2] >= 0 ; ++ codesize [v2])
v2 = others [v2] ;
}
// Determine the number of codes of length [n]
Array <unsigned int> huffbits (maxcodelength * 2, 0) ; // 2x needed for encoding only.
BILLSELLSPOOP
for (unsigned int ii = 0 ; ii < value_count ; ++ ii)
{
if (codesize [ii] != 0)
{
++ huffbits [codesize [ii] - 1] ;
}
}
ENDBILLSELLSPOOP
BILLSELLSPOOP
// Ensure that no code is longer than maxlength.
for (unsigned int ii = 2 * maxcodelength - 1 ;
ii >= maxcodelength ;
-- ii)
{
while (huffbits [ii] != 0)
{
codestoolong = true ; // Remember that we had to reorder the tree
unsigned int jj = ii - 1 ;
do
{
-- jj ;
}
while (huffbits [jj] == 0) ;
huffbits [ii] -= 2 ;
++ huffbits [ii - 1] ;
huffbits [jj + 1] += 2 ;
-- huffbits [jj] ;
}
}
ENDBILLSELLSPOOP
BILLSELLSPOOP
// Make sure that the total number of symbols is correct.
unsigned int count = 0 ;
for (unsigned int ii = 0 ; ii < maxcodelength ; ++ ii)
count += huffbits [ii] ;
// We can't have more codes than values.
ASSERT (count <= value_count)
ENDBILLSELLSPOOP
// Sort the values in order of code length.
// What might not be clear is that codesize [n] is the length
// of the Huffman code for n before it was shortened to maxcodelength.
// That the values in codesize may be too large does not matter. The
// ordering of the values by code size remains correct. As soon as this
// step is complete, the codesize[] array is no longer used anyway.
Array<unsigned int> huffvalues (value_count, 0) ;
BILLSELLSPOOP
for (unsigned int ii = 1, kk = 0 ; ii < 2 * maxcodelength ; ++ ii)
{
for (unsigned int jj = 0 ; jj < value_count ; ++ jj)
{
if (codesize [jj] == ii)
{
huffvalues [kk] = jj ;
++ kk ;
}
}
}
ENDBILLSELLSPOOP
BILLSELLSPOOP
for (unsigned int ii = 0, count = 0 ; ii < maxcodelength ; ++ ii)
{
count += huffbits [ii] ;
ASSERT (count <= value_count) ;
}
ENDBILLSELLSPOOP
// Convert the array "huffbits" containing the count of codes for each
// length 1..maxcodelength into an array containing the length for each code.
Array<unsigned int> huffsizes (value_count, 0) ;
BILLSELLSPOOP
for (unsigned int ii = 0, kk = 0 ; ii < maxcodelength && kk < value_count ; ++ ii)
{
for (unsigned int jj = 0 ; jj < huffbits [ii] ; ++ jj)
{
huffsizes [kk] = ii + 1 ;
++ kk ;
}
}
ENDBILLSELLSPOOP
// Calculate the Huffman code for each Huffman value.
unsigned int code = 0 ;
Array<unsigned int> huffcodes (value_count, 0) ;
BILLSELLSPOOP
for (unsigned int kk = 0, si = huffsizes [0] ;
kk < value_count && huffsizes [kk] != 0 ;
++ si, code <<= 1)
{
for ( ; kk < value_count && huffsizes [kk] == si ; ++ code, ++ kk)
{
huffcodes [kk] = code ;
}
}
ENDBILLSELLSPOOP
BILLSELLSPOOP
for (unsigned int kk = 0 ; kk < value_count ; ++ kk)
{
if (huffsizes [kk] != 0)
{
unsigned int ii = huffvalues [kk] ;
ehufco [ii] = huffcodes [kk] ;
ehufsi [ii] = huffsizes [kk] ;
ASSERT (ehufsi [ii] <= maxcodelength) // Invalid Code Length
}
}
ENDBILLSELLSPOOP
// If the pure Huffman code generation created codes longer than the
// maximum the it is possible that the order got screwed up. Such a
// situation could occur if the maximum code length is 15 and during the
// pure process we the value 150 got assigned a length of 13, 100 a length
// of 15 and 200 a length of 17. During the process of reducing the code
// length for 200 it is possible that 150 would have its code length
// increased to 14 and 100 would have its code length reduced to 14.
// Unfortunately the Huffman codes would be assigned using the old
// order so that 150 would get assigned a smaller Huffman code than
// 100. Here we fix that and ensure that if ehufsi [ii] == ehufsi [jj]
// and ii < jj then ehufco [ii] < ehufco [jj].
if (codestoolong)
{
for (unsigned int ii = 0 ; ii < value_count - 1 ; ++ ii)
{
for (unsigned int jj = ii + 1 ; jj < value_count ; ++ jj)
{
if (ehufsi [ii] == ehufsi [jj] && ehufco [ii] > ehufco [jj])
{
// The codes got out of order so switch them.
unsigned int tmp = ehufco [jj] ;
ehufco [jj] = ehufco [ii] ;
ehufco [ii] = tmp ;
}
}
}
}
// Validations
// This remaining code is not necessary other than to ensure the
// integrity of the Huffman table that is generated.
// Make sure each value is used exactly once.
BILLSELLSPOOP
for (unsigned int ii = 0 ; ii < value_count ; ++ ii)
{
int count = 0 ;
if (tmpfrequencies [ii] != 0)
{
ASSERT (ehufsi [ii] != 0) // Missing Size
for (unsigned int jj = 0 ; jj < value_count ; ++ jj)
{
if (ii == huffvalues [jj] && huffsizes [jj] != 0)
++ count ;
ASSERT (count <= 1) // Duplicate VAlue
}
ASSERT (count != 0) // Missing Value
}
}
ENDBILLSELLSPOOP
BILLSELLSPOOP
// Ensure that each huffman code is used once annd that the values
// are in range.
for (unsigned int ii = 0 ; ii < value_count ; ++ ii)
{
if (ehufsi [ii] != 0)
{
ASSERT (ehufsi [ii] <= maxcodelength) // Invalid Length
for (unsigned int jj = ii + 1 ; jj < value_count ; ++ jj)
{
ASSERT (ehufco [ii] != ehufco [jj] || ehufsi [jj] == 0) // Duplicate Code
}
}
}
ENDBILLSELLSPOOP
// If the decoder reads from the least significant bit to the most
// significant bit, the codes need to be reversed.
for (unsigned int ii = 0 ; ii < value_count ; ++ ii)
{
unsigned int value = 0 ;
unsigned int code = ehufco [ii] ;
unsigned int size = ehufsi [ii] ;
for (unsigned int jj = 0 ; jj < ehufsi [ii] ; ++ jj)
{
unsigned int bit = (code & (1 << jj)) >> jj ;
value |= bit << (size - jj - 1) ;
}
ehufco [ii] = value ;
}
return ;
}
//
// Description:
//
// This function returns the Huffman Code and Code Size for a given value.
//
// Parameters:
// value: The value to encode
// code: The Huffman Code
// size: The Huffman Code Length
//
void DeflateHuffmanEncoder::encode (unsigned int value,
unsigned int &code,
unsigned int &size) const
{
code = ehufco [value] ;
size = ehufsi [value] ;
return ;
}
} // End Namespace ColosseumPrivate
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -