📄 jdmarker.pas
字号:
Unit JdMarker;
{ This file contains routines to decode JPEG datastream markers.
Most of the complexity arises from our desire to support input
suspension: if not all of the data for a marker is available;
we must exit back to the application. On resumption; we reprocess
the marker. }
{ Original: jdmarker.c; Copyright (C) 1991-1998; Thomas G. Lane. }
{ History
9.7.96 Conversion to pascal started jnn
22.3.98 updated to 6b jnn }
interface
{$I jconfig.inc}
uses
jmorecfg,
jinclude,
jdeferr,
jerror,
jcomapi,
jpeglib;
const { JPEG marker codes }
M_SOF0 = $c0;
M_SOF1 = $c1;
M_SOF2 = $c2;
M_SOF3 = $c3;
M_SOF5 = $c5;
M_SOF6 = $c6;
M_SOF7 = $c7;
M_JPG = $c8;
M_SOF9 = $c9;
M_SOF10 = $ca;
M_SOF11 = $cb;
M_SOF13 = $cd;
M_SOF14 = $ce;
M_SOF15 = $cf;
M_DHT = $c4;
M_DAC = $cc;
M_RST0 = $d0;
M_RST1 = $d1;
M_RST2 = $d2;
M_RST3 = $d3;
M_RST4 = $d4;
M_RST5 = $d5;
M_RST6 = $d6;
M_RST7 = $d7;
M_SOI = $d8;
M_EOI = $d9;
M_SOS = $da;
M_DQT = $db;
M_DNL = $dc;
M_DRI = $dd;
M_DHP = $de;
M_EXP = $df;
M_APP0 = $e0;
M_APP1 = $e1;
M_APP2 = $e2;
M_APP3 = $e3;
M_APP4 = $e4;
M_APP5 = $e5;
M_APP6 = $e6;
M_APP7 = $e7;
M_APP8 = $e8;
M_APP9 = $e9;
M_APP10 = $ea;
M_APP11 = $eb;
M_APP12 = $ec;
M_APP13 = $ed;
M_APP14 = $ee;
M_APP15 = $ef;
M_JPG0 = $f0;
M_JPG13 = $fd;
M_COM = $fe;
M_TEM = $01;
M_ERROR = $100;
type
JPEG_MARKER = uint; { JPEG marker codes }
{ Private state }
type
my_marker_ptr = ^my_marker_reader;
my_marker_reader = record
pub : jpeg_marker_reader; { public fields }
{ Application-overridable marker processing methods }
process_COM : jpeg_marker_parser_method;
process_APPn : array[0..16-1] of jpeg_marker_parser_method;
{ Limit on marker data length to save for each marker type }
length_limit_COM : uint;
length_limit_APPn : array[0..16-1] of uint;
{ Status of COM/APPn marker saving }
cur_marker : jpeg_saved_marker_ptr; { NIL if not processing a marker }
bytes_read : uint; { data bytes read so far in marker }
{ Note: cur_marker is not linked into marker_list until it's all read. }
end;
{GLOBAL}
function jpeg_resync_to_restart(cinfo : j_decompress_ptr;
desired : int) : boolean;
{GLOBAL}
procedure jinit_marker_reader (cinfo : j_decompress_ptr);
{$ifdef SAVE_MARKERS_SUPPORTED}
{GLOBAL}
procedure jpeg_save_markers (cinfo : j_decompress_ptr;
marker_code : int;
length_limit : uint);
{$ENDIF}
{GLOBAL}
procedure jpeg_set_marker_processor (cinfo : j_decompress_ptr;
marker_code : int;
routine : jpeg_marker_parser_method);
implementation
uses
jutils;
{ At all times, cinfo1.src.next_input_byte and .bytes_in_buffer reflect
the current restart point; we update them only when we have reached a
suitable place to restart if a suspension occurs. }
{ Routines to process JPEG markers.
Entry condition: JPEG marker itself has been read and its code saved
in cinfo^.unread_marker; input restart point is just after the marker.
Exit: if return TRUE, have read and processed any parameters, and have
updated the restart point to point after the parameters.
If return FALSE, was forced to suspend before reaching end of
marker parameters; restart point has not been moved. Same routine
will be called again after application supplies more input data.
This approach to suspension assumes that all of a marker's parameters
can fit into a single input bufferload. This should hold for "normal"
markers. Some COM/APPn markers might have large parameter segments
that might not fit. If we are simply dropping such a marker, we use
skip_input_data to get past it, and thereby put the problem on the
source manager's shoulders. If we are saving the marker's contents
into memory, we use a slightly different convention: when forced to
suspend, the marker processor updates the restart point to the end of
what it's consumed (ie, the end of the buffer) before returning FALSE.
On resumption, cinfo->unread_marker still contains the marker code,
but the data source will point to the next chunk of marker data.
The marker processor must retain internal state to deal with this.
Note that we don't bother to avoid duplicate trace messages if a
suspension occurs within marker parameters. Other side effects
require more care. }
{LOCAL}
function get_soi (cinfo : j_decompress_ptr) : boolean;
{ Process an SOI marker }
var
i : int;
begin
{$IFDEF DEBUG}
TRACEMS(j_common_ptr(cinfo), 1, JTRC_SOI);
{$ENDIF}
if (cinfo^.marker^.saw_SOI) then
ERREXIT(j_common_ptr(cinfo), JERR_SOI_DUPLICATE);
{ Reset all parameters that are defined to be reset by SOI }
for i := 0 to Pred(NUM_ARITH_TBLS) do
with cinfo^ do
begin
arith_dc_L[i] := 0;
arith_dc_U[i] := 1;
arith_ac_K[i] := 5;
end;
cinfo^.restart_interval := 0;
{ Set initial assumptions for colorspace etc }
with cinfo^ do
begin
jpeg_color_space := JCS_UNKNOWN;
CCIR601_sampling := FALSE; { Assume non-CCIR sampling??? }
saw_JFIF_marker := FALSE;
JFIF_major_version := 1; { set default JFIF APP0 values }
JFIF_minor_version := 1;
density_unit := 0;
X_density := 1;
Y_density := 1;
saw_Adobe_marker := FALSE;
Adobe_transform := 0;
marker^.saw_SOI := TRUE;
end;
get_soi := TRUE;
end; { get_soi }
{LOCAL}
function get_sof(cinfo : j_decompress_ptr;
is_prog : boolean;
is_arith : boolean) : boolean;
{ Process a SOFn marker }
var
length : INT32;
c, ci : int;
compptr : jpeg_component_info_ptr;
{ Declare and initialize local copies of input pointer/count }
var
datasrc : jpeg_source_mgr_ptr;
next_input_byte : JOCTETptr;
bytes_in_buffer : size_t;
begin
datasrc := cinfo^.src;
next_input_byte := datasrc^.next_input_byte;
bytes_in_buffer := datasrc^.bytes_in_buffer;
{}
cinfo^.progressive_mode := is_prog;
cinfo^.arith_code := is_arith;
{ Read two bytes interpreted as an unsigned 16-bit integer.
length should be declared unsigned int or perhaps INT32. }
{ make a byte available.
Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
but we must reload the local copies after a successful fill. }
if (bytes_in_buffer = 0) then
begin
if (not datasrc^.fill_input_buffer(cinfo)) then
begin
get_sof := FALSE;
exit;
end;
{ Reload the local copies }
next_input_byte := datasrc^.next_input_byte;
bytes_in_buffer := datasrc^.bytes_in_buffer;
end;
Dec( bytes_in_buffer );
length := (uint( GETJOCTET(next_input_byte^)) shl 8);
Inc( next_input_byte );
{ make a byte available.
Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
but we must reload the local copies after a successful fill. }
if (bytes_in_buffer = 0) then
begin
if (not datasrc^.fill_input_buffer(cinfo)) then
begin
get_sof := FALSE;
exit;
end;
{ Reload the local copies }
next_input_byte := datasrc^.next_input_byte;
bytes_in_buffer := datasrc^.bytes_in_buffer;
end;
Dec( bytes_in_buffer );
Inc( length, GETJOCTET( next_input_byte^));
Inc( next_input_byte );
{ Read a byte into variable cinfo^.data_precision.
If must suspend, return FALSE. }
{ make a byte available.
Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
but we must reload the local copies after a successful fill. }
if (bytes_in_buffer = 0) then
begin
if (not datasrc^.fill_input_buffer(cinfo)) then
begin
get_sof := FALSE;
exit;
end;
{ Reload the local copies }
next_input_byte := datasrc^.next_input_byte;
bytes_in_buffer := datasrc^.bytes_in_buffer;
end;
Dec( bytes_in_buffer );
cinfo^.data_precision := GETJOCTET(next_input_byte^);
Inc(next_input_byte);
{ Read two bytes interpreted as an unsigned 16-bit integer.
cinfo^.image_height should be declared unsigned int or perhaps INT32. }
{ make a byte available.
Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
but we must reload the local copies after a successful fill. }
if (bytes_in_buffer = 0) then
begin
if (not datasrc^.fill_input_buffer(cinfo)) then
begin
get_sof := FALSE;
exit;
end;
{ Reload the local copies }
next_input_byte := datasrc^.next_input_byte;
bytes_in_buffer := datasrc^.bytes_in_buffer;
end;
Dec( bytes_in_buffer );
cinfo^.image_height := (uint( GETJOCTET(next_input_byte^)) shl 8);
Inc( next_input_byte );
{ make a byte available.
Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
but we must reload the local copies after a successful fill. }
if (bytes_in_buffer = 0) then
begin
if (not datasrc^.fill_input_buffer(cinfo)) then
begin
get_sof := FALSE;
exit;
end;
{ Reload the local copies }
next_input_byte := datasrc^.next_input_byte;
bytes_in_buffer := datasrc^.bytes_in_buffer;
end;
Dec( bytes_in_buffer );
Inc( cinfo^.image_height, GETJOCTET( next_input_byte^));
Inc( next_input_byte );
{ Read two bytes interpreted as an unsigned 16-bit integer.
cinfo^.image_width should be declared unsigned int or perhaps INT32. }
{ make a byte available.
Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
but we must reload the local copies after a successful fill. }
if (bytes_in_buffer = 0) then
begin
if (not datasrc^.fill_input_buffer(cinfo)) then
begin
get_sof := FALSE;
exit;
end;
{ Reload the local copies }
next_input_byte := datasrc^.next_input_byte;
bytes_in_buffer := datasrc^.bytes_in_buffer;
end;
Dec( bytes_in_buffer );
cinfo^.image_width := (uint( GETJOCTET(next_input_byte^)) shl 8);
Inc( next_input_byte );
{ make a byte available.
Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
but we must reload the local copies after a successful fill. }
if (bytes_in_buffer = 0) then
begin
if (not datasrc^.fill_input_buffer(cinfo)) then
begin
get_sof := FALSE;
exit;
end;
{ Reload the local copies }
next_input_byte := datasrc^.next_input_byte;
bytes_in_buffer := datasrc^.bytes_in_buffer;
end;
Dec( bytes_in_buffer );
Inc( cinfo^.image_width, GETJOCTET( next_input_byte^));
Inc( next_input_byte );
{ Read a byte into variable cinfo^.num_components.
If must suspend, return FALSE. }
{ make a byte available.
Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
but we must reload the local copies after a successful fill. }
if (bytes_in_buffer = 0) then
begin
if (not datasrc^.fill_input_buffer(cinfo)) then
begin
get_sof := FALSE;
exit;
end;
{ Reload the local copies }
next_input_byte := datasrc^.next_input_byte;
bytes_in_buffer := datasrc^.bytes_in_buffer;
end;
Dec( bytes_in_buffer );
cinfo^.num_components := GETJOCTET(next_input_byte^);
Inc(next_input_byte);
Dec(length, 8);
{$IFDEF DEBUG}
TRACEMS4(j_common_ptr(cinfo), 1, JTRC_SOF, cinfo^.unread_marker,
int(cinfo^.image_width), int(cinfo^.image_height),
cinfo^.num_components);
{$ENDIF}
if (cinfo^.marker^.saw_SOF) then
ERREXIT(j_common_ptr(cinfo), JERR_SOF_DUPLICATE);
{ We don't support files in which the image height is initially specified }
{ as 0 and is later redefined by DNL. As long as we have to check that, }
{ might as well have a general sanity check. }
if (cinfo^.image_height <= 0) or (cinfo^.image_width <= 0)
or (cinfo^.num_components <= 0) then
ERREXIT(j_common_ptr(cinfo), JERR_EMPTY_IMAGE);
if (length <> (cinfo^.num_components * 3)) then
ERREXIT(j_common_ptr(cinfo), JERR_BAD_LENGTH);
if (cinfo^.comp_info = NIL) then { do only once, even if suspend }
cinfo^.comp_info := jpeg_component_info_list_ptr(
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -