123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406 |
- Unit JcPrepCT;
- { Original : jcprepct.c ; Copyright (C) 1994-1996, Thomas G. Lane. }
- { This file contains the compression preprocessing controller.
- This controller manages the color conversion, downsampling,
- and edge expansion steps.
- Most of the complexity here is associated with buffering input rows
- as required by the downsampler. See the comments at the head of
- jcsample.c for the downsampler's needs. }
- interface
- {$I jconfig.inc}
- uses
- jmorecfg,
- jpeglib,
- jdeferr,
- jerror,
- jinclude,
- jutils;
- {GLOBAL}
- procedure jinit_c_prep_controller (cinfo : j_compress_ptr;
- need_full_buffer : boolean);
- implementation
- { At present, jcsample.c can request context rows only for smoothing.
- In the future, we might also need context rows for CCIR601 sampling
- or other more-complex downsampling procedures. The code to support
- context rows should be compiled only if needed. }
- {$ifdef INPUT_SMOOTHING_SUPPORTED}
- {$define CONTEXT_ROWS_SUPPORTED}
- {$endif}
- { For the simple (no-context-row) case, we just need to buffer one
- row group's worth of pixels for the downsampling step. At the bottom of
- the image, we pad to a full row group by replicating the last pixel row.
- The downsampler's last output row is then replicated if needed to pad
- out to a full iMCU row.
- When providing context rows, we must buffer three row groups' worth of
- pixels. Three row groups are physically allocated, but the row pointer
- arrays are made five row groups high, with the extra pointers above and
- below "wrapping around" to point to the last and first real row groups.
- This allows the downsampler to access the proper context rows.
- At the top and bottom of the image, we create dummy context rows by
- copying the first or last real pixel row. This copying could be avoided
- by pointer hacking as is done in jdmainct.c, but it doesn't seem worth the
- trouble on the compression side. }
- { Private buffer controller object }
- type
- my_prep_ptr = ^my_prep_controller;
- my_prep_controller = record
- pub : jpeg_c_prep_controller; { public fields }
- { Downsampling input buffer. This buffer holds color-converted data
- until we have enough to do a downsample step. }
- color_buf : array[0..MAX_COMPONENTS-1] of JSAMPARRAY;
- rows_to_go : JDIMENSION; { counts rows remaining in source image }
- next_buf_row : int; { index of next row to store in color_buf }
- {$ifdef CONTEXT_ROWS_SUPPORTED} { only needed for context case }
- this_row_group : int; { starting row index of group to process }
- next_buf_stop : int; { downsample when we reach this index }
- {$endif}
- end; {my_prep_controller;}
- { Initialize for a processing pass. }
- {METHODDEF}
- procedure start_pass_prep (cinfo : j_compress_ptr;
- pass_mode : J_BUF_MODE ); far;
- var
- prep : my_prep_ptr;
- begin
- prep := my_prep_ptr (cinfo^.prep);
- if (pass_mode <> JBUF_PASS_THRU) then
- ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE);
- { Initialize total-height counter for detecting bottom of image }
- prep^.rows_to_go := cinfo^.image_height;
- { Mark the conversion buffer empty }
- prep^.next_buf_row := 0;
- {$ifdef CONTEXT_ROWS_SUPPORTED}
- { Preset additional state variables for context mode.
- These aren't used in non-context mode, so we needn't test which mode. }
- prep^.this_row_group := 0;
- { Set next_buf_stop to stop after two row groups have been read in. }
- prep^.next_buf_stop := 2 * cinfo^.max_v_samp_factor;
- {$endif}
- end;
- { Expand an image vertically from height input_rows to height output_rows,
- by duplicating the bottom row. }
- {LOCAL}
- procedure expand_bottom_edge (image_data : JSAMPARRAY;
- num_cols : JDIMENSION;
- input_rows : int;
- output_rows : int);
- var
- {register} row : int;
- begin
- for row := input_rows to pred(output_rows) do
- begin
- jcopy_sample_rows(image_data, input_rows-1, image_data, row,
- 1, num_cols);
- end;
- end;
- { Process some data in the simple no-context case.
- Preprocessor output data is counted in "row groups". A row group
- is defined to be v_samp_factor sample rows of each component.
- Downsampling will produce this much data from each max_v_samp_factor
- input rows. }
- {METHODDEF}
- procedure pre_process_data (cinfo : j_compress_ptr;
- input_buf : JSAMPARRAY;
- var in_row_ctr : JDIMENSION;
- in_rows_avail : JDIMENSION;
- output_buf : JSAMPIMAGE;
- var out_row_group_ctr : JDIMENSION;
- out_row_groups_avail : JDIMENSION); far;
- var
- prep : my_prep_ptr;
- numrows, ci : int;
- inrows : JDIMENSION;
- compptr : jpeg_component_info_ptr;
- var
- local_input_buf : JSAMPARRAY;
- begin
- prep := my_prep_ptr (cinfo^.prep);
- while (in_row_ctr < in_rows_avail) and
- (out_row_group_ctr < out_row_groups_avail) do
- begin
- { Do color conversion to fill the conversion buffer. }
- inrows := in_rows_avail - in_row_ctr;
- numrows := cinfo^.max_v_samp_factor - prep^.next_buf_row;
- {numrows := int( MIN(JDIMENSION(numrows), inrows) );}
- if inrows < JDIMENSION(numrows) then
- numrows := int(inrows);
- local_input_buf := JSAMPARRAY(@(input_buf^[in_row_ctr]));
- cinfo^.cconvert^.color_convert (cinfo, local_input_buf,
- JSAMPIMAGE(@prep^.color_buf),
- JDIMENSION(prep^.next_buf_row),
- numrows);
- Inc(in_row_ctr, numrows);
- Inc(prep^.next_buf_row, numrows);
- Dec(prep^.rows_to_go, numrows);
- { If at bottom of image, pad to fill the conversion buffer. }
- if (prep^.rows_to_go = 0) and
- (prep^.next_buf_row < cinfo^.max_v_samp_factor) then
- begin
- for ci := 0 to pred(cinfo^.num_components) do
- begin
- expand_bottom_edge(prep^.color_buf[ci], cinfo^.image_width,
- prep^.next_buf_row, cinfo^.max_v_samp_factor);
- end;
- prep^.next_buf_row := cinfo^.max_v_samp_factor;
- end;
- { If we've filled the conversion buffer, empty it. }
- if (prep^.next_buf_row = cinfo^.max_v_samp_factor) then
- begin
- cinfo^.downsample^.downsample (cinfo,
- JSAMPIMAGE(@prep^.color_buf),
- JDIMENSION (0),
- output_buf,
- out_row_group_ctr);
- prep^.next_buf_row := 0;
- Inc(out_row_group_ctr);;
- end;
- { If at bottom of image, pad the output to a full iMCU height.
- Note we assume the caller is providing a one-iMCU-height output buffer! }
- if (prep^.rows_to_go = 0) and
- (out_row_group_ctr < out_row_groups_avail) then
- begin
- compptr := jpeg_component_info_ptr(cinfo^.comp_info);
- for ci := 0 to pred(cinfo^.num_components) do
- begin
- expand_bottom_edge(output_buf^[ci],
- compptr^.width_in_blocks * DCTSIZE,
- int (out_row_group_ctr * compptr^.v_samp_factor),
- int (out_row_groups_avail * compptr^.v_samp_factor));
- Inc(compptr);
- end;
- out_row_group_ctr := out_row_groups_avail;
- break; { can exit outer loop without test }
- end;
- end;
- end;
- {$ifdef CONTEXT_ROWS_SUPPORTED}
- { Process some data in the context case. }
- {METHODDEF}
- procedure pre_process_context (cinfo : j_compress_ptr;
- input_buf : JSAMPARRAY;
- var in_row_ctr : JDIMENSION;
- in_rows_avail : JDIMENSION;
- output_buf : JSAMPIMAGE;
- var out_row_group_ctr : JDIMENSION;
- out_row_groups_avail : JDIMENSION); far;
- var
- prep : my_prep_ptr;
- numrows, ci : int;
- buf_height : int;
- inrows : JDIMENSION;
- var
- row : int;
- begin
- prep := my_prep_ptr (cinfo^.prep);
- buf_height := cinfo^.max_v_samp_factor * 3;
- while (out_row_group_ctr < out_row_groups_avail) do
- begin
- if (in_row_ctr < in_rows_avail) then
- begin
- { Do color conversion to fill the conversion buffer. }
- inrows := in_rows_avail - in_row_ctr;
- numrows := prep^.next_buf_stop - prep^.next_buf_row;
- {numrows := int ( MIN( JDIMENSION(numrows), inrows) );}
- if inrows < JDIMENSION(numrows) then
- numrows := int(inrows);
- cinfo^.cconvert^.color_convert (cinfo,
- JSAMPARRAY(@input_buf^[in_row_ctr]),
- JSAMPIMAGE(@prep^.color_buf),
- JDIMENSION (prep^.next_buf_row),
- numrows);
- { Pad at top of image, if first time through }
- if (prep^.rows_to_go = cinfo^.image_height) then
- begin
- for ci := 0 to pred(cinfo^.num_components) do
- begin
- for row := 1 to cinfo^.max_v_samp_factor do
- begin
- jcopy_sample_rows(prep^.color_buf[ci], 0,
- prep^.color_buf[ci], -row,
- 1, cinfo^.image_width);
- end;
- end;
- end;
- Inc(in_row_ctr, numrows);
- Inc(prep^.next_buf_row, numrows);
- Dec(prep^.rows_to_go, numrows);
- end
- else
- begin
- { Return for more data, unless we are at the bottom of the image. }
- if (prep^.rows_to_go <> 0) then
- break;
- { When at bottom of image, pad to fill the conversion buffer. }
- if (prep^.next_buf_row < prep^.next_buf_stop) then
- begin
- for ci := 0 to pred(cinfo^.num_components) do
- begin
- expand_bottom_edge(prep^.color_buf[ci], cinfo^.image_width,
- prep^.next_buf_row, prep^.next_buf_stop);
- end;
- prep^.next_buf_row := prep^.next_buf_stop;
- end;
- end;
- { If we've gotten enough data, downsample a row group. }
- if (prep^.next_buf_row = prep^.next_buf_stop) then
- begin
- cinfo^.downsample^.downsample (cinfo,
- JSAMPIMAGE(@prep^.color_buf),
- JDIMENSION(prep^.this_row_group),
- output_buf,
- out_row_group_ctr);
- Inc(out_row_group_ctr);
- { Advance pointers with wraparound as necessary. }
- Inc(prep^.this_row_group, cinfo^.max_v_samp_factor);
- if (prep^.this_row_group >= buf_height) then
- prep^.this_row_group := 0;
- if (prep^.next_buf_row >= buf_height) then
- prep^.next_buf_row := 0;
- prep^.next_buf_stop := prep^.next_buf_row + cinfo^.max_v_samp_factor;
- end;
- end;
- end;
- { Create the wrapped-around downsampling input buffer needed for context mode. }
- {LOCAL}
- procedure create_context_buffer (cinfo : j_compress_ptr);
- var
- prep : my_prep_ptr;
- rgroup_height : int;
- ci, i : int;
- compptr : jpeg_component_info_ptr;
- true_buffer, fake_buffer : JSAMPARRAY;
- begin
- prep := my_prep_ptr (cinfo^.prep);
- rgroup_height := cinfo^.max_v_samp_factor;
- { Grab enough space for fake row pointers for all the components;
- we need five row groups' worth of pointers for each component. }
- fake_buffer := JSAMPARRAY(
- cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
- (cinfo^.num_components * 5 * rgroup_height) *
- SIZEOF(JSAMPROW)) );
- compptr := jpeg_component_info_ptr(cinfo^.comp_info);
- for ci := 0 to pred(cinfo^.num_components) do
- begin
- { Allocate the actual buffer space (3 row groups) for this component.
- We make the buffer wide enough to allow the downsampler to edge-expand
- horizontally within the buffer, if it so chooses. }
- true_buffer := cinfo^.mem^.alloc_sarray
- (j_common_ptr(cinfo), JPOOL_IMAGE,
- JDIMENSION (( long(compptr^.width_in_blocks) * DCTSIZE *
- cinfo^.max_h_samp_factor) div compptr^.h_samp_factor),
- JDIMENSION (3 * rgroup_height));
- { Copy true buffer row pointers into the middle of the fake row array }
- MEMCOPY(JSAMPARRAY(@ fake_buffer^[rgroup_height]), true_buffer,
- 3 * rgroup_height * SIZEOF(JSAMPROW));
- { Fill in the above and below wraparound pointers }
- for i := 0 to pred(rgroup_height) do
- begin
- fake_buffer^[i] := true_buffer^[2 * rgroup_height + i];
- fake_buffer^[4 * rgroup_height + i] := true_buffer^[i];
- end;
- prep^.color_buf[ci] := JSAMPARRAY(@ fake_buffer^[rgroup_height]);
- Inc(JSAMPROW_PTR(fake_buffer), 5 * rgroup_height); { point to space for next component }
- Inc(compptr);
- end;
- end;
- {$endif} { CONTEXT_ROWS_SUPPORTED }
- { Initialize preprocessing controller. }
- {GLOBAL}
- procedure jinit_c_prep_controller (cinfo : j_compress_ptr;
- need_full_buffer : boolean);
- var
- prep : my_prep_ptr;
- ci : int;
- compptr : jpeg_component_info_ptr;
- begin
- if (need_full_buffer) then { safety check }
- ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE);
- prep := my_prep_ptr(
- cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
- SIZEOF(my_prep_controller)) );
- cinfo^.prep := jpeg_c_prep_controller_ptr(prep);
- prep^.pub.start_pass := start_pass_prep;
- { Allocate the color conversion buffer.
- We make the buffer wide enough to allow the downsampler to edge-expand
- horizontally within the buffer, if it so chooses. }
- if (cinfo^.downsample^.need_context_rows) then
- begin
- { Set up to provide context rows }
- {$ifdef CONTEXT_ROWS_SUPPORTED}
- prep^.pub.pre_process_data := pre_process_context;
- create_context_buffer(cinfo);
- {$else}
- ERREXIT(j_common_ptr(cinfo), JERR_NOT_COMPILED);
- {$endif}
- end
- else
- begin
- { No context, just make it tall enough for one row group }
- prep^.pub.pre_process_data := pre_process_data;
- compptr := jpeg_component_info_ptr(cinfo^.comp_info);
- for ci := 0 to pred(cinfo^.num_components) do
- begin
- prep^.color_buf[ci] := cinfo^.mem^.alloc_sarray
- (j_common_ptr(cinfo), JPOOL_IMAGE,
- JDIMENSION (( long(compptr^.width_in_blocks) * DCTSIZE *
- cinfo^.max_h_samp_factor) div compptr^.h_samp_factor),
- JDIMENSION(cinfo^.max_v_samp_factor) );
- Inc(compptr);
- end;
- end;
- end;
- end.
|