📄 jchuff.pas
字号:
Unit JcHuff;
{ This file contains Huffman entropy encoding routines.
Much of the complexity here has to do with supporting output suspension.
If the data destination module demands suspension, we want to be able to
back up to the start of the current MCU. To do this, we copy state
variables into local working storage, and update them back to the
permanent JPEG objects only upon successful completion of an MCU. }
{ Original: jchuff.c; Copyright (C) 1991-1996, Thomas G. Lane. }
interface
{$I jconfig.inc}
uses
jmorecfg, { longptr definition missing }
jpeglib,
jdeferr,
jerror,
jutils,
jinclude,
jcomapi;
{ Derived data constructed for each Huffman table }
{ Declarations shared with jcphuff.c }
type
c_derived_tbl_ptr = ^c_derived_tbl;
c_derived_tbl = record
ehufco : array[0..256-1] of uInt; { code for each symbol }
ehufsi : array[0..256-1] of byte; { length of code for each symbol }
{ If no code has been allocated for a symbol S, ehufsi[S] contains 0 }
end;
{ for JCHUFF und JCPHUFF }
type
TLongTable = array[0..256] of long;
TLongTablePtr = ^TLongTable;
{ Compute the derived values for a Huffman table.
Note this is also used by jcphuff.c. }
{GLOBAL}
procedure jpeg_make_c_derived_tbl (cinfo : j_compress_ptr;
var htbl : JHUFF_TBL;
var pdtbl : c_derived_tbl_ptr);
{ Generate the optimal coding for the given counts, fill htbl.
Note this is also used by jcphuff.c. }
{GLOBAL}
procedure jpeg_gen_optimal_table (cinfo : j_compress_ptr;
htbl : JHUFF_TBL_PTR;
var freq : TLongTable); { Nomssi }
{ Module initialization routine for Huffman entropy encoding. }
{GLOBAL}
procedure jinit_huff_encoder (cinfo : j_compress_ptr);
implementation
{ Expanded entropy encoder object for Huffman encoding.
The savable_state subrecord contains fields that change within an MCU,
but must not be updated permanently until we complete the MCU. }
type
savable_state = record
put_buffer : INT32; { current bit-accumulation buffer }
put_bits : int; { # of bits now in it }
last_dc_val : array[0..MAX_COMPS_IN_SCAN-1] of int;
{ last DC coef for each component }
end;
type
huff_entropy_ptr = ^huff_entropy_encoder;
huff_entropy_encoder = record
pub : jpeg_entropy_encoder; { public fields }
saved : savable_state; { Bit buffer & DC state at start of MCU }
{ These fields are NOT loaded into local working state. }
restarts_to_go : uInt; { MCUs left in this restart interval }
next_restart_num : int; { next restart number to write (0-7) }
{ Pointers to derived tables (these workspaces have image lifespan) }
dc_derived_tbls : array[0..NUM_HUFF_TBLS-1] of c_derived_tbl_ptr;
ac_derived_tbls : array[0..NUM_HUFF_TBLS-1] of c_derived_tbl_ptr;
{$ifdef ENTROPY_OPT_SUPPORTED} { Statistics tables for optimization }
dc_count_ptrs : array[0..NUM_HUFF_TBLS-1] of TLongTablePtr;
ac_count_ptrs : array[0..NUM_HUFF_TBLS-1] of TLongTablePtr;
{$endif}
end;
{ Working state while writing an MCU.
This struct contains all the fields that are needed by subroutines. }
type
working_state = record
next_output_byte : JOCTETptr; { => next byte to write in buffer }
free_in_buffer : size_t; { # of byte spaces remaining in buffer }
cur : savable_state; { Current bit buffer & DC state }
cinfo : j_compress_ptr; { dump_buffer needs access to this }
end;
{ Forward declarations }
{METHODDEF}
function encode_mcu_huff (cinfo : j_compress_ptr;
const MCU_data : array of JBLOCKROW) : boolean; far;
forward;
{METHODDEF}
procedure finish_pass_huff (cinfo : j_compress_ptr); far; forward;
{$ifdef ENTROPY_OPT_SUPPORTED}
{METHODDEF}
function encode_mcu_gather (cinfo : j_compress_ptr;
const MCU_data: array of JBLOCKROW) : boolean;
far; forward;
{METHODDEF}
procedure finish_pass_gather (cinfo : j_compress_ptr); far; forward;
{$endif}
{ Initialize for a Huffman-compressed scan.
If gather_statistics is TRUE, we do not output anything during the scan,
just count the Huffman symbols used and generate Huffman code tables. }
{METHODDEF}
procedure start_pass_huff (cinfo : j_compress_ptr;
gather_statistics : boolean); far;
var
entropy : huff_entropy_ptr;
ci, dctbl, actbl : int;
compptr : jpeg_component_info_ptr;
begin
entropy := huff_entropy_ptr (cinfo^.entropy);
if (gather_statistics) then
begin
{$ifdef ENTROPY_OPT_SUPPORTED}
entropy^.pub.encode_mcu := encode_mcu_gather;
entropy^.pub.finish_pass := finish_pass_gather;
{$else}
ERREXIT(j_common_ptr(cinfo), JERR_NOT_COMPILED);
{$endif}
end
else
begin
entropy^.pub.encode_mcu := encode_mcu_huff;
entropy^.pub.finish_pass := finish_pass_huff;
end;
for ci := 0 to pred(cinfo^.comps_in_scan) do
begin
compptr := cinfo^.cur_comp_info[ci];
dctbl := compptr^.dc_tbl_no;
actbl := compptr^.ac_tbl_no;
{ Make sure requested tables are present }
{ (In gather mode, tables need not be allocated yet) }
if (dctbl < 0) or (dctbl >= NUM_HUFF_TBLS) or
((cinfo^.dc_huff_tbl_ptrs[dctbl] = NIL) and (not gather_statistics)) then
ERREXIT1(j_common_ptr(cinfo), JERR_NO_HUFF_TABLE, dctbl);
if (actbl < 0) or (actbl >= NUM_HUFF_TBLS) or
((cinfo^.ac_huff_tbl_ptrs[actbl] = NIL) and (not gather_statistics)) then
ERREXIT1(j_common_ptr(cinfo), JERR_NO_HUFF_TABLE, actbl);
if (gather_statistics) then
begin
{$ifdef ENTROPY_OPT_SUPPORTED}
{ Allocate and zero the statistics tables }
{ Note that jpeg_gen_optimal_table expects 257 entries in each table! }
if (entropy^.dc_count_ptrs[dctbl] = NIL) then
entropy^.dc_count_ptrs[dctbl] := TLongTablePtr(
cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
257 * SIZEOF(long)));
MEMZERO(entropy^.dc_count_ptrs[dctbl], 257 * SIZEOF(long));
if (entropy^.ac_count_ptrs[actbl] = NIL) then
entropy^.ac_count_ptrs[actbl] := TLongTablePtr(
cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
257 * SIZEOF(long)) );
MEMZERO(entropy^.ac_count_ptrs[actbl], 257 * SIZEOF(long));
{$endif}
end
else
begin
{ Compute derived values for Huffman tables }
{ We may do this more than once for a table, but it's not expensive }
jpeg_make_c_derived_tbl(cinfo, cinfo^.dc_huff_tbl_ptrs[dctbl]^,
entropy^.dc_derived_tbls[dctbl]);
jpeg_make_c_derived_tbl(cinfo, cinfo^.ac_huff_tbl_ptrs[actbl]^,
entropy^.ac_derived_tbls[actbl]);
end;
{ Initialize DC predictions to 0 }
entropy^.saved.last_dc_val[ci] := 0;
end;
{ Initialize bit buffer to empty }
entropy^.saved.put_buffer := 0;
entropy^.saved.put_bits := 0;
{ Initialize restart stuff }
entropy^.restarts_to_go := cinfo^.restart_interval;
entropy^.next_restart_num := 0;
end;
{ Compute the derived values for a Huffman table.
Note this is also used by jcphuff.c. }
{GLOBAL}
procedure jpeg_make_c_derived_tbl (cinfo : j_compress_ptr;
var htbl : JHUFF_TBL;
var pdtbl : c_derived_tbl_ptr);
var
dtbl : c_derived_tbl_ptr;
p, i, l, lastp, si : int;
huffsize : array[0..257-1] of byte;
huffcode : array[0..257-1] of uInt;
code : uInt;
begin
{ Allocate a workspace if we haven't already done so. }
if (pdtbl = NIL) then
pdtbl := c_derived_tbl_ptr(
cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
SIZEOF(c_derived_tbl)) );
dtbl := pdtbl;
{ Figure C.1: make table of Huffman code length for each symbol }
{ Note that this is in code-length order. }
p := 0;
for l := 1 to 16 do
begin
for i := 1 to int(htbl.bits[l]) do
begin
huffsize[p] := byte(l);
Inc(p);
end;
end;
huffsize[p] := 0;
lastp := p;
{ Figure C.2: generate the codes themselves }
{ Note that this is in code-length order. }
code := 0;
si := huffsize[0];
p := 0;
while (huffsize[p] <> 0) do
begin
while (( int(huffsize[p]) ) = si) do
begin
huffcode[p] := code;
Inc(p);
Inc(code);
end;
code := code shl 1;
Inc(si);
end;
{ Figure C.3: generate encoding tables }
{ These are code and size indexed by symbol value }
{ Set any codeless symbols to have code length 0;
this allows emit_bits to detect any attempt to emit such symbols. }
MEMZERO(@dtbl^.ehufsi, SIZEOF(dtbl^.ehufsi));
for p := 0 to pred(lastp) do
begin
dtbl^.ehufco[htbl.huffval[p]] := huffcode[p];
dtbl^.ehufsi[htbl.huffval[p]] := huffsize[p];
end;
end;
{ Outputting bytes to the file }
{LOCAL}
function dump_buffer (var state : working_state) : boolean;
{ Empty the output buffer; return TRUE if successful, FALSE if must suspend }
var
dest : jpeg_destination_mgr_ptr;
begin
dest := state.cinfo^.dest;
if (not dest^.empty_output_buffer (state.cinfo)) then
begin
dump_buffer := FALSE;
exit;
end;
{ After a successful buffer dump, must reset buffer pointers }
state.next_output_byte := dest^.next_output_byte;
state.free_in_buffer := dest^.free_in_buffer;
dump_buffer := TRUE;
end;
{ Outputting bits to the file }
{ Only the right 24 bits of put_buffer are used; the valid bits are
left-justified in this part. At most 16 bits can be passed to emit_bits
in one call, and we never retain more than 7 bits in put_buffer
between calls, so 24 bits are sufficient. }
{LOCAL}
function emit_bits (var state : working_state;
code : uInt;
size : int) : boolean; {INLINE}
{ Emit some bits; return TRUE if successful, FALSE if must suspend }
var
{ This routine is heavily used, so it's worth coding tightly. }
{register} put_buffer : INT32;
{register} put_bits : int;
var
c : int;
begin
put_buffer := INT32 (code);
put_bits := state.cur.put_bits;
{ if size is 0, caller used an invalid Huffman table entry }
if (size = 0) then
ERREXIT(j_common_ptr(state.cinfo), JERR_HUFF_MISSING_CODE);
put_buffer := put_buffer and pred(INT32(1) shl size);
{ mask off any extra bits in code }
Inc(put_bits, size); { new number of bits in buffer }
put_buffer := put_buffer shl (24 - put_bits);
{ align incoming bits }
put_buffer := put_buffer or state.cur.put_buffer;
{ and merge with old buffer contents }
while (put_bits >= 8) do
begin
c := int ((put_buffer shr 16) and $FF);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -