CentrED/Imaging/JpegLib/imjdpostct.pas

342 lines
11 KiB
Plaintext
Raw Permalink Normal View History

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.