📄 jcmaster.pas
字号:
Unit JcMaster;
{ This file contains master control logic for the JPEG compressor.
These routines are concerned with parameter validation, initial setup,
and inter-pass control (determining the number of passes and the work
to be done in each pass). }
{ Original: jcmaster.c ; Copyright (C) 1991-1997, Thomas G. Lane. }
interface
uses
jmorecfg,
jinclude,
jdeferr,
jerror,
jutils,
jpeglib;
{$I jconfig.inc}
{ Initialize master compression control. }
{GLOBAL}
procedure jinit_c_master_control (cinfo : j_compress_ptr;
transcode_only : boolean);
implementation
{ Private state }
type
c_pass_type = (
main_pass, { input data, also do first output step }
huff_opt_pass, { Huffman code optimization pass }
output_pass { data output pass }
);
type
my_master_ptr = ^my_comp_master;
my_comp_master = record
pub : jpeg_comp_master; { public fields }
pass_type : c_pass_type; { the type of the current pass }
pass_number : int; { # of passes completed }
total_passes : int; { total # of passes needed }
scan_number : int; { current index in scan_info[] }
end;
{ Support routines that do various essential calculations. }
{LOCAL}
procedure initial_setup (cinfo : j_compress_ptr);
{ Do computations that are needed before master selection phase }
var
ci : int;
compptr : jpeg_component_info_ptr;
samplesperrow : long;
jd_samplesperrow : JDIMENSION;
begin
{ Sanity check on image dimensions }
if (cinfo^.image_height <= 0) or (cinfo^.image_width <= 0) or
(cinfo^.num_components <= 0) or (cinfo^.input_components <= 0) then
ERREXIT(j_common_ptr(cinfo), JERR_EMPTY_IMAGE);
{ Make sure image isn't bigger than I can handle }
if ( long(cinfo^.image_height) > long(JPEG_MAX_DIMENSION)) or
( long(cinfo^.image_width) > long(JPEG_MAX_DIMENSION)) then
ERREXIT1(j_common_ptr(cinfo), JERR_IMAGE_TOO_BIG,
uInt(JPEG_MAX_DIMENSION));
{ Width of an input scanline must be representable as JDIMENSION. }
samplesperrow := long (cinfo^.image_width) * long (cinfo^.input_components);
jd_samplesperrow := JDIMENSION (samplesperrow);
if ( long(jd_samplesperrow) <> samplesperrow) then
ERREXIT(j_common_ptr(cinfo), JERR_WIDTH_OVERFLOW);
{ For now, precision must match compiled-in value... }
if (cinfo^.data_precision <> BITS_IN_JSAMPLE) then
ERREXIT1(j_common_ptr(cinfo), JERR_BAD_PRECISION, cinfo^.data_precision);
{ Check that number of components won't exceed internal array sizes }
if (cinfo^.num_components > MAX_COMPONENTS) then
ERREXIT2(j_common_ptr(cinfo), JERR_COMPONENT_COUNT, cinfo^.num_components,
MAX_COMPONENTS);
{ Compute maximum sampling factors; check factor validity }
cinfo^.max_h_samp_factor := 1;
cinfo^.max_v_samp_factor := 1;
compptr := jpeg_component_info_ptr(cinfo^.comp_info);
for ci := 0 to pred(cinfo^.num_components) do
begin
if (compptr^.h_samp_factor<=0) or (compptr^.h_samp_factor>MAX_SAMP_FACTOR)
or (compptr^.v_samp_factor<=0) or (compptr^.v_samp_factor>MAX_SAMP_FACTOR) then
ERREXIT(j_common_ptr(cinfo), JERR_BAD_SAMPLING);
{ MAX }
if cinfo^.max_h_samp_factor > compptr^.h_samp_factor then
cinfo^.max_h_samp_factor := cinfo^.max_h_samp_factor
else
cinfo^.max_h_samp_factor := compptr^.h_samp_factor;
{ MAX }
if cinfo^.max_v_samp_factor > compptr^.v_samp_factor then
cinfo^.max_v_samp_factor := cinfo^.max_v_samp_factor
else
cinfo^.max_v_samp_factor := compptr^.v_samp_factor;
Inc(compptr);
end;
{ Compute dimensions of components }
compptr := jpeg_component_info_ptr(cinfo^.comp_info);
for ci := 0 to pred(cinfo^.num_components) do
begin
{ Fill in the correct component_index value; don't rely on application }
compptr^.component_index := ci;
{ For compression, we never do DCT scaling. }
compptr^.DCT_scaled_size := DCTSIZE;
{ Size in DCT blocks }
compptr^.width_in_blocks := JDIMENSION (
jdiv_round_up(long (cinfo^.image_width) * long (compptr^.h_samp_factor),
long (cinfo^.max_h_samp_factor * DCTSIZE)) );
compptr^.height_in_blocks := JDIMENSION (
jdiv_round_up(long (cinfo^.image_height) * long (compptr^.v_samp_factor),
long (cinfo^.max_v_samp_factor * DCTSIZE)) );
{ Size in samples }
compptr^.downsampled_width := JDIMENSION (
jdiv_round_up(long(cinfo^.image_width) * long(compptr^.h_samp_factor),
long(cinfo^.max_h_samp_factor)) );
compptr^.downsampled_height := JDIMENSION (
jdiv_round_up(long (cinfo^.image_height) * long(compptr^.v_samp_factor),
long (cinfo^.max_v_samp_factor)) );
{ Mark component needed (this flag isn't actually used for compression) }
compptr^.component_needed := TRUE;
Inc(compptr);
end;
{ Compute number of fully interleaved MCU rows (number of times that
main controller will call coefficient controller). }
cinfo^.total_iMCU_rows := JDIMENSION (
jdiv_round_up(long (cinfo^.image_height),
long (cinfo^.max_v_samp_factor*DCTSIZE)) );
end;
{$ifdef C_MULTISCAN_FILES_SUPPORTED}
{LOCAL}
procedure validate_script (cinfo : j_compress_ptr);
{ Verify that the scan script in cinfo^.scan_info[] is valid; also
determine whether it uses progressive JPEG, and set cinfo^.progressive_mode. }
type
IntRow = array[0..DCTSIZE2-1] of int;
introw_ptr = ^IntRow;
var
{const}scanptr : jpeg_scan_info_ptr;
scanno, ncomps, ci, coefi, thisi : int;
Ss, Se, Ah, Al : int;
component_sent : array[0..MAX_COMPONENTS-1] of boolean;
{$ifdef C_PROGRESSIVE_SUPPORTED}
last_bitpos_int_ptr : int_ptr;
last_bitpos_ptr : introw_ptr;
last_bitpos : array[0..MAX_COMPONENTS-1] of IntRow;
{ -1 until that coefficient has been seen; then last Al for it }
{ The JPEG spec simply gives the ranges 0..13 for Ah and Al, but that
seems wrong: the upper bound ought to depend on data precision.
Perhaps they really meant 0..N+1 for N-bit precision.
Here we allow 0..10 for 8-bit data; Al larger than 10 results in
out-of-range reconstructed DC values during the first DC scan,
which might cause problems for some decoders. }
{$ifdef BITS_IN_JSAMPLE_IS_8}
const
MAX_AH_AL = 10;
{$else}
const
MAX_AH_AL = 13;
{$endif}
{$endif}
begin
if (cinfo^.num_scans <= 0) then
ERREXIT1(j_common_ptr(cinfo), JERR_BAD_SCAN_SCRIPT, 0);
{ For sequential JPEG, all scans must have Ss=0, Se=DCTSIZE2-1;
for progressive JPEG, no scan can have this. }
scanptr := cinfo^.scan_info;
if (scanptr^.Ss <> 0) or (scanptr^.Se <> DCTSIZE2-1) then
begin
{$ifdef C_PROGRESSIVE_SUPPORTED}
cinfo^.progressive_mode := TRUE;
last_bitpos_int_ptr := @(last_bitpos[0][0]);
for ci := 0 to pred(cinfo^.num_components) do
for coefi := 0 to pred(DCTSIZE2) do
begin
last_bitpos_int_ptr^ := -1;
Inc(last_bitpos_int_ptr);
end;
{$else}
ERREXIT(j_common_ptr(cinfo), JERR_NOT_COMPILED);
{$endif}
end
else
begin
cinfo^.progressive_mode := FALSE;
for ci := 0 to pred(cinfo^.num_components) do
component_sent[ci] := FALSE;
end;
for scanno := 1 to cinfo^.num_scans do
begin
{ Validate component indexes }
ncomps := scanptr^.comps_in_scan;
if (ncomps <= 0) or (ncomps > MAX_COMPS_IN_SCAN) then
ERREXIT2(j_common_ptr(cinfo), JERR_COMPONENT_COUNT, ncomps, MAX_COMPS_IN_SCAN);
for ci := 0 to pred(ncomps) do
begin
thisi := scanptr^.component_index[ci];
if (thisi < 0) or (thisi >= cinfo^.num_components) then
ERREXIT1(j_common_ptr(cinfo), JERR_BAD_SCAN_SCRIPT, scanno);
{ Components must appear in SOF order within each scan }
if (ci > 0) and (thisi <= scanptr^.component_index[ci-1]) then
ERREXIT1(j_common_ptr(cinfo), JERR_BAD_SCAN_SCRIPT, scanno);
end;
{ Validate progression parameters }
Ss := scanptr^.Ss;
Se := scanptr^.Se;
Ah := scanptr^.Ah;
Al := scanptr^.Al;
if (cinfo^.progressive_mode) then
begin
{$ifdef C_PROGRESSIVE_SUPPORTED}
if (Ss < 0) or (Ss >= DCTSIZE2) or (Se < Ss) or (Se >= DCTSIZE2) or
(Ah < 0) or (Ah > MAX_AH_AL) or (Al < 0) or (Al > MAX_AH_AL) then
ERREXIT1(j_common_ptr(cinfo), JERR_BAD_PROG_SCRIPT, scanno);
if (Ss < 0) or (Ss >= DCTSIZE2) or (Se < Ss) or (Se >= DCTSIZE2)
or (Ah < 0) or (Ah > MAX_AH_AL) or (Al < 0) or (Al > MAX_AH_AL) then
ERREXIT1(j_common_ptr(cinfo), JERR_BAD_PROG_SCRIPT, scanno);
if (Ss = 0) then
begin
if (Se <> 0) then { DC and AC together not OK }
ERREXIT1(j_common_ptr(cinfo), JERR_BAD_PROG_SCRIPT, scanno);
end
else
begin
if (ncomps <> 1) then { AC scans must be for only one component }
ERREXIT1(j_common_ptr(cinfo), JERR_BAD_PROG_SCRIPT, scanno);
end;
for ci := 0 to pred(ncomps) do
begin
last_bitpos_ptr := @( last_bitpos[scanptr^.component_index[ci]]);
if (Ss <> 0) and (last_bitpos_ptr^[0] < 0) then { AC without prior DC scan }
ERREXIT1(j_common_ptr(cinfo), JERR_BAD_PROG_SCRIPT, scanno);
for coefi := Ss to Se do
begin
if (last_bitpos_ptr^[coefi] < 0) then
begin
{ first scan of this coefficient }
if (Ah <> 0) then
ERREXIT1(j_common_ptr(cinfo), JERR_BAD_PROG_SCRIPT, scanno);
end
else
begin
{ not first scan }
if (Ah <> last_bitpos_ptr^[coefi]) or (Al <> Ah-1) then
ERREXIT1(j_common_ptr(cinfo), JERR_BAD_PROG_SCRIPT, scanno);
end;
last_bitpos_ptr^[coefi] := Al;
end;
end;
{$endif}
end
else
begin
{ For sequential JPEG, all progression parameters must be these: }
if (Ss <> 0) or (Se <> DCTSIZE2-1) or (Ah <> 0) or (Al <> 0) then
ERREXIT1(j_common_ptr(cinfo), JERR_BAD_PROG_SCRIPT, scanno);
{ Make sure components are not sent twice }
for ci := 0 to pred(ncomps) do
begin
thisi := scanptr^.component_index[ci];
if (component_sent[thisi]) then
ERREXIT1(j_common_ptr(cinfo), JERR_BAD_SCAN_SCRIPT, scanno);
component_sent[thisi] := TRUE;
end;
end;
Inc(scanptr);
end;
{ Now verify that everything got sent. }
if (cinfo^.progressive_mode) then
begin
{$ifdef C_PROGRESSIVE_SUPPORTED
{ For progressive mode, we only check that at least some DC data
got sent for each component; the spec does not require that all bits
of all coefficients be transmitted. Would it be wiser to enforce
transmission of all coefficient bits?? }
for ci := 0 to pred(cinfo^.num_components) do
begin
if (last_bitpos[ci][0] < 0) then
ERREXIT(j_common_ptr(cinfo), JERR_MISSING_DATA);
end;
{$endif}
end
else
begin
for ci := 0 to pred(cinfo^.num_components) do
begin
if (not component_sent[ci]) then
ERREXIT(j_common_ptr(cinfo), JERR_MISSING_DATA);
end;
end;
end;
{$endif} { C_MULTISCAN_FILES_SUPPORTED }
{LOCAL}
procedure select_scan_parameters (cinfo : j_compress_ptr);
{ Set up the scan parameters for the current scan }
var
master : my_master_ptr;
{const} scanptr : jpeg_scan_info_ptr;
ci : int;
var
comp_infos : jpeg_component_info_list_ptr;
begin
{$ifdef C_MULTISCAN_FILES_SUPPORTED}
if (cinfo^.scan_info <> NIL) then
begin
{ Prepare for current scan --- the script is already validated }
master := my_master_ptr (cinfo^.master);
scanptr := cinfo^.scan_info;
Inc(scanptr, master^.scan_number);
cinfo^.comps_in_scan := scanptr^.comps_in_scan;
comp_infos := cinfo^.comp_info;
for ci := 0 to pred(scanptr^.comps_in_scan) do
begin
cinfo^.cur_comp_info[ci] :=
@(comp_infos^[scanptr^.component_index[ci]]);
end;
cinfo^.Ss := scanptr^.Ss;
cinfo^.Se := scanptr^.Se;
cinfo^.Ah := scanptr^.Ah;
cinfo^.Al := scanptr^.Al;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -