2022-05-08 10:47:53 +02:00
|
|
|
unit imjdpostct;
|
|
|
|
|
|
|
|
{ Original: jdpostct.c ; Copyright (C) 1994-1996, Thomas G. Lane. }
|
|
|
|
|
|
|
|
{ This file contains the decompression postprocessing controller.
|
|
|
|
This controller manages the upsampling, color conversion, and color
|
|
|
|
quantization/reduction steps; specifically, it controls the buffering
|
|
|
|
between upsample/color conversion and color quantization/reduction.
|
|
|
|
|
|
|
|
If no color quantization/reduction is required, then this module has no
|
|
|
|
work to do, and it just hands off to the upsample/color conversion code.
|
|
|
|
An integrated upsample/convert/quantize process would replace this module
|
|
|
|
entirely. }
|
|
|
|
|
|
|
|
interface
|
|
|
|
|
|
|
|
{$I imjconfig.inc}
|
|
|
|
|
|
|
|
uses
|
|
|
|
imjmorecfg,
|
|
|
|
imjinclude,
|
|
|
|
imjdeferr,
|
|
|
|
imjerror,
|
|
|
|
imjutils,
|
|
|
|
imjpeglib;
|
|
|
|
|
|
|
|
{ Initialize postprocessing controller. }
|
|
|
|
|
|
|
|
{GLOBAL}
|
|
|
|
procedure jinit_d_post_controller (cinfo : j_decompress_ptr;
|
|
|
|
need_full_buffer : boolean);
|
|
|
|
implementation
|
|
|
|
|
|
|
|
|
|
|
|
{ Private buffer controller object }
|
|
|
|
|
|
|
|
type
|
|
|
|
my_post_ptr = ^my_post_controller;
|
|
|
|
my_post_controller = record
|
|
|
|
pub : jpeg_d_post_controller; { public fields }
|
|
|
|
|
|
|
|
{ Color quantization source buffer: this holds output data from
|
|
|
|
the upsample/color conversion step to be passed to the quantizer.
|
|
|
|
For two-pass color quantization, we need a full-image buffer;
|
|
|
|
for one-pass operation, a strip buffer is sufficient. }
|
|
|
|
|
|
|
|
whole_image : jvirt_sarray_ptr; { virtual array, or NIL if one-pass }
|
|
|
|
buffer : JSAMPARRAY; { strip buffer, or current strip of virtual }
|
|
|
|
strip_height : JDIMENSION; { buffer size in rows }
|
|
|
|
{ for two-pass mode only: }
|
|
|
|
starting_row : JDIMENSION; { row # of first row in current strip }
|
|
|
|
next_row : JDIMENSION; { index of next row to fill/empty in strip }
|
|
|
|
end;
|
|
|
|
|
|
|
|
{ Forward declarations }
|
|
|
|
{METHODDEF}
|
|
|
|
procedure post_process_1pass(cinfo : j_decompress_ptr;
|
|
|
|
input_buf : JSAMPIMAGE;
|
|
|
|
var in_row_group_ctr : JDIMENSION;
|
|
|
|
in_row_groups_avail : JDIMENSION;
|
|
|
|
output_buf : JSAMPARRAY;
|
|
|
|
var out_row_ctr : JDIMENSION;
|
|
|
|
out_rows_avail : JDIMENSION); forward;
|
|
|
|
{$ifdef QUANT_2PASS_SUPPORTED}
|
|
|
|
{METHODDEF}
|
|
|
|
procedure post_process_prepass(cinfo : j_decompress_ptr;
|
|
|
|
input_buf : JSAMPIMAGE;
|
|
|
|
var in_row_group_ctr : JDIMENSION;
|
|
|
|
in_row_groups_avail : JDIMENSION;
|
|
|
|
output_buf : JSAMPARRAY;
|
|
|
|
var out_row_ctr : JDIMENSION;
|
|
|
|
out_rows_avail : JDIMENSION); forward;
|
|
|
|
{METHODDEF}
|
|
|
|
procedure post_process_2pass(cinfo : j_decompress_ptr;
|
|
|
|
input_buf : JSAMPIMAGE;
|
|
|
|
var in_row_group_ctr : JDIMENSION;
|
|
|
|
in_row_groups_avail : JDIMENSION;
|
|
|
|
output_buf : JSAMPARRAY;
|
|
|
|
var out_row_ctr : JDIMENSION;
|
|
|
|
out_rows_avail : JDIMENSION); forward;
|
|
|
|
{$endif}
|
|
|
|
|
|
|
|
|
|
|
|
{ Initialize for a processing pass. }
|
|
|
|
|
|
|
|
{METHODDEF}
|
|
|
|
procedure start_pass_dpost (cinfo : j_decompress_ptr;
|
|
|
|
pass_mode : J_BUF_MODE);
|
|
|
|
var
|
|
|
|
post : my_post_ptr;
|
|
|
|
begin
|
|
|
|
post := my_post_ptr(cinfo^.post);
|
|
|
|
|
|
|
|
case (pass_mode) of
|
|
|
|
JBUF_PASS_THRU:
|
|
|
|
if (cinfo^.quantize_colors) then
|
|
|
|
begin
|
|
|
|
{ Single-pass processing with color quantization. }
|
|
|
|
post^.pub.post_process_data := post_process_1pass;
|
|
|
|
{ We could be doing buffered-image output before starting a 2-pass
|
|
|
|
color quantization; in that case, jinit_d_post_controller did not
|
|
|
|
allocate a strip buffer. Use the virtual-array buffer as workspace. }
|
|
|
|
if (post^.buffer = NIL) then
|
|
|
|
begin
|
|
|
|
post^.buffer := cinfo^.mem^.access_virt_sarray
|
|
|
|
(j_common_ptr(cinfo), post^.whole_image,
|
|
|
|
JDIMENSION(0), post^.strip_height, TRUE);
|
|
|
|
end;
|
|
|
|
end
|
|
|
|
else
|
|
|
|
begin
|
|
|
|
{ For single-pass processing without color quantization,
|
|
|
|
I have no work to do; just call the upsampler directly. }
|
|
|
|
|
|
|
|
post^.pub.post_process_data := cinfo^.upsample^.upsample;
|
|
|
|
end;
|
|
|
|
|
|
|
|
{$ifdef QUANT_2PASS_SUPPORTED}
|
|
|
|
JBUF_SAVE_AND_PASS:
|
|
|
|
begin
|
|
|
|
{ First pass of 2-pass quantization }
|
|
|
|
if (post^.whole_image = NIL) then
|
|
|
|
ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE);
|
|
|
|
post^.pub.post_process_data := post_process_prepass;
|
|
|
|
end;
|
|
|
|
JBUF_CRANK_DEST:
|
|
|
|
begin
|
|
|
|
{ Second pass of 2-pass quantization }
|
|
|
|
if (post^.whole_image = NIL) then
|
|
|
|
ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE);
|
|
|
|
post^.pub.post_process_data := post_process_2pass;
|
|
|
|
end;
|
|
|
|
{$endif} { QUANT_2PASS_SUPPORTED }
|
|
|
|
else
|
|
|
|
ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE);
|
|
|
|
end;
|
|
|
|
post^.next_row := 0;
|
|
|
|
post^.starting_row := 0;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
{ Process some data in the one-pass (strip buffer) case.
|
|
|
|
This is used for color precision reduction as well as one-pass quantization. }
|
|
|
|
|
|
|
|
{METHODDEF}
|
|
|
|
procedure post_process_1pass (cinfo : j_decompress_ptr;
|
|
|
|
input_buf : JSAMPIMAGE;
|
|
|
|
var in_row_group_ctr : JDIMENSION;
|
|
|
|
in_row_groups_avail : JDIMENSION;
|
|
|
|
output_buf : JSAMPARRAY;
|
|
|
|
var out_row_ctr : JDIMENSION;
|
|
|
|
out_rows_avail : JDIMENSION);
|
|
|
|
var
|
|
|
|
post : my_post_ptr;
|
|
|
|
num_rows, max_rows : JDIMENSION;
|
|
|
|
begin
|
|
|
|
post := my_post_ptr (cinfo^.post);
|
|
|
|
|
|
|
|
{ Fill the buffer, but not more than what we can dump out in one go. }
|
|
|
|
{ Note we rely on the upsampler to detect bottom of image. }
|
|
|
|
max_rows := out_rows_avail - out_row_ctr;
|
|
|
|
if (max_rows > post^.strip_height) then
|
|
|
|
max_rows := post^.strip_height;
|
|
|
|
num_rows := 0;
|
|
|
|
cinfo^.upsample^.upsample (cinfo,
|
|
|
|
input_buf,
|
|
|
|
in_row_group_ctr,
|
|
|
|
in_row_groups_avail,
|
|
|
|
post^.buffer,
|
|
|
|
num_rows, { var }
|
|
|
|
max_rows);
|
|
|
|
{ Quantize and emit data. }
|
|
|
|
|
|
|
|
cinfo^.cquantize^.color_quantize (cinfo,
|
|
|
|
post^.buffer,
|
|
|
|
JSAMPARRAY(@ output_buf^[out_row_ctr]),
|
|
|
|
int(num_rows));
|
|
|
|
|
|
|
|
Inc(out_row_ctr, num_rows);
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
{$ifdef QUANT_2PASS_SUPPORTED}
|
|
|
|
|
|
|
|
{ Process some data in the first pass of 2-pass quantization. }
|
|
|
|
|
|
|
|
{METHODDEF}
|
|
|
|
procedure post_process_prepass (cinfo : j_decompress_ptr;
|
|
|
|
input_buf : JSAMPIMAGE;
|
|
|
|
var in_row_group_ctr : JDIMENSION;
|
|
|
|
in_row_groups_avail : JDIMENSION;
|
|
|
|
output_buf : JSAMPARRAY;
|
|
|
|
var out_row_ctr : JDIMENSION;
|
|
|
|
out_rows_avail:JDIMENSION);
|
|
|
|
var
|
|
|
|
post : my_post_ptr;
|
|
|
|
old_next_row, num_rows : JDIMENSION;
|
|
|
|
begin
|
|
|
|
post := my_post_ptr(cinfo^.post);
|
|
|
|
|
|
|
|
{ Reposition virtual buffer if at start of strip. }
|
|
|
|
if (post^.next_row = 0) then
|
|
|
|
begin
|
|
|
|
post^.buffer := cinfo^.mem^.access_virt_sarray
|
|
|
|
(j_common_ptr(cinfo), post^.whole_image,
|
|
|
|
post^.starting_row, post^.strip_height, TRUE);
|
|
|
|
end;
|
|
|
|
|
|
|
|
{ Upsample some data (up to a strip height's worth). }
|
|
|
|
old_next_row := post^.next_row;
|
|
|
|
cinfo^.upsample^.upsample (cinfo,
|
|
|
|
input_buf, in_row_group_ctr, in_row_groups_avail,
|
|
|
|
post^.buffer, post^.next_row, post^.strip_height);
|
|
|
|
|
|
|
|
{ Allow quantizer to scan new data. No data is emitted, }
|
|
|
|
{ but we advance out_row_ctr so outer loop can tell when we're done. }
|
|
|
|
if (post^.next_row > old_next_row) then
|
|
|
|
begin
|
|
|
|
num_rows := post^.next_row - old_next_row;
|
|
|
|
|
|
|
|
|
|
|
|
cinfo^.cquantize^.color_quantize (cinfo,
|
|
|
|
JSAMPARRAY(@ post^.buffer^[old_next_row]),
|
|
|
|
JSAMPARRAY(NIL),
|
|
|
|
int(num_rows));
|
|
|
|
Inc(out_row_ctr, num_rows);
|
|
|
|
end;
|
|
|
|
|
|
|
|
{ Advance if we filled the strip. }
|
|
|
|
if (post^.next_row >= post^.strip_height) then
|
|
|
|
begin
|
|
|
|
Inc(post^.starting_row, post^.strip_height);
|
|
|
|
post^.next_row := 0;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
{ Process some data in the second pass of 2-pass quantization. }
|
|
|
|
|
|
|
|
{METHODDEF}
|
|
|
|
procedure post_process_2pass (cinfo : j_decompress_ptr;
|
|
|
|
input_buf : JSAMPIMAGE;
|
|
|
|
var in_row_group_ctr : JDIMENSION;
|
|
|
|
in_row_groups_avail : JDIMENSION;
|
|
|
|
output_buf : JSAMPARRAY;
|
|
|
|
var out_row_ctr : JDIMENSION;
|
|
|
|
out_rows_avail : JDIMENSION);
|
|
|
|
var
|
|
|
|
post : my_post_ptr;
|
|
|
|
num_rows, max_rows : JDIMENSION;
|
|
|
|
begin
|
|
|
|
post := my_post_ptr(cinfo^.post);
|
|
|
|
|
|
|
|
{ Reposition virtual buffer if at start of strip. }
|
|
|
|
if (post^.next_row = 0) then
|
|
|
|
begin
|
|
|
|
post^.buffer := cinfo^.mem^.access_virt_sarray
|
|
|
|
(j_common_ptr(cinfo), post^.whole_image,
|
|
|
|
post^.starting_row, post^.strip_height, FALSE);
|
|
|
|
end;
|
|
|
|
|
|
|
|
{ Determine number of rows to emit. }
|
|
|
|
num_rows := post^.strip_height - post^.next_row; { available in strip }
|
|
|
|
max_rows := out_rows_avail - out_row_ctr; { available in output area }
|
|
|
|
if (num_rows > max_rows) then
|
|
|
|
num_rows := max_rows;
|
|
|
|
{ We have to check bottom of image here, can't depend on upsampler. }
|
|
|
|
max_rows := cinfo^.output_height - post^.starting_row;
|
|
|
|
if (num_rows > max_rows) then
|
|
|
|
num_rows := max_rows;
|
|
|
|
|
|
|
|
{ Quantize and emit data. }
|
|
|
|
cinfo^.cquantize^.color_quantize (cinfo,
|
|
|
|
JSAMPARRAY(@ post^.buffer^[post^.next_row]),
|
|
|
|
JSAMPARRAY(@ output_buf^[out_row_ctr]),
|
|
|
|
int(num_rows));
|
|
|
|
Inc(out_row_ctr, num_rows);
|
|
|
|
|
|
|
|
{ Advance if we filled the strip. }
|
|
|
|
Inc(post^.next_row, num_rows);
|
|
|
|
if (post^.next_row >= post^.strip_height) then
|
|
|
|
begin
|
|
|
|
Inc(post^.starting_row, post^.strip_height);
|
|
|
|
post^.next_row := 0;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
{$endif} { QUANT_2PASS_SUPPORTED }
|
|
|
|
|
|
|
|
|
|
|
|
{ Initialize postprocessing controller. }
|
|
|
|
|
|
|
|
{GLOBAL}
|
|
|
|
procedure jinit_d_post_controller (cinfo : j_decompress_ptr;
|
|
|
|
need_full_buffer : boolean);
|
|
|
|
var
|
|
|
|
post : my_post_ptr;
|
|
|
|
begin
|
|
|
|
post := my_post_ptr(
|
|
|
|
cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
|
|
|
|
SIZEOF(my_post_controller)) );
|
|
|
|
cinfo^.post := jpeg_d_post_controller_ptr (post);
|
|
|
|
post^.pub.start_pass := start_pass_dpost;
|
|
|
|
post^.whole_image := NIL; { flag for no virtual arrays }
|
|
|
|
post^.buffer := NIL; { flag for no strip buffer }
|
|
|
|
|
|
|
|
{ Create the quantization buffer, if needed }
|
|
|
|
if (cinfo^.quantize_colors) then
|
|
|
|
begin
|
|
|
|
{ The buffer strip height is max_v_samp_factor, which is typically
|
|
|
|
an efficient number of rows for upsampling to return.
|
|
|
|
(In the presence of output rescaling, we might want to be smarter?) }
|
|
|
|
|
|
|
|
post^.strip_height := JDIMENSION (cinfo^.max_v_samp_factor);
|
|
|
|
if (need_full_buffer) then
|
|
|
|
begin
|
|
|
|
{ Two-pass color quantization: need full-image storage. }
|
|
|
|
{ We round up the number of rows to a multiple of the strip height. }
|
|
|
|
{$ifdef QUANT_2PASS_SUPPORTED}
|
|
|
|
post^.whole_image := cinfo^.mem^.request_virt_sarray
|
|
|
|
(j_common_ptr(cinfo), JPOOL_IMAGE, FALSE,
|
|
|
|
LongInt(cinfo^.output_width) * cinfo^.out_color_components,
|
|
|
|
JDIMENSION (jround_up( long(cinfo^.output_height),
|
|
|
|
long(post^.strip_height)) ),
|
|
|
|
post^.strip_height);
|
|
|
|
{$else}
|
|
|
|
ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE);
|
|
|
|
{$endif} { QUANT_2PASS_SUPPORTED }
|
|
|
|
end
|
|
|
|
else
|
|
|
|
begin
|
|
|
|
{ One-pass color quantization: just make a strip buffer. }
|
|
|
|
post^.buffer := cinfo^.mem^.alloc_sarray
|
|
|
|
(j_common_ptr (cinfo), JPOOL_IMAGE,
|
|
|
|
LongInt(cinfo^.output_width) * cinfo^.out_color_components,
|
|
|
|
post^.strip_height);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
end.
|