123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522 |
- Unit JcCoefCt;
- { This file contains the coefficient buffer controller for compression.
- This controller is the top level of the JPEG compressor proper.
- The coefficient buffer lies between forward-DCT and entropy encoding steps.}
- { Original: jccoefct.c; Copyright (C) 1994-1997, Thomas G. Lane. }
- interface
- {$I jconfig.inc}
- uses
- jmorecfg,
- jinclude,
- jerror,
- jdeferr,
- jutils,
- jpeglib;
- { We use a full-image coefficient buffer when doing Huffman optimization,
- and also for writing multiple-scan JPEG files. In all cases, the DCT
- step is run during the first pass, and subsequent passes need only read
- the buffered coefficients. }
- {$ifdef ENTROPY_OPT_SUPPORTED}
- {$define FULL_COEF_BUFFER_SUPPORTED}
- {$else}
- {$ifdef C_MULTISCAN_FILES_SUPPORTED}
- {$define FULL_COEF_BUFFER_SUPPORTED}
- {$endif}
- {$endif}
- { Initialize coefficient buffer controller. }
- {GLOBAL}
- procedure jinit_c_coef_controller (cinfo : j_compress_ptr;
- need_full_buffer : boolean);
- implementation
- { Private buffer controller object }
- type
- my_coef_ptr = ^my_coef_controller;
- my_coef_controller = record
- pub : jpeg_c_coef_controller; { public fields }
- iMCU_row_num : JDIMENSION; { iMCU row # within image }
- mcu_ctr : JDIMENSION; { counts MCUs processed in current row }
- MCU_vert_offset : int; { counts MCU rows within iMCU row }
- MCU_rows_per_iMCU_row : int; { number of such rows needed }
- { For single-pass compression, it's sufficient to buffer just one MCU
- (although this may prove a bit slow in practice). We allocate a
- workspace of C_MAX_BLOCKS_IN_MCU coefficient blocks, and reuse it for each
- MCU constructed and sent. (On 80x86, the workspace is FAR even though
- it's not really very big; this is to keep the module interfaces unchanged
- when a large coefficient buffer is necessary.)
- In multi-pass modes, this array points to the current MCU's blocks
- within the virtual arrays. }
- MCU_buffer : array[0..C_MAX_BLOCKS_IN_MCU-1] of JBLOCKROW;
- { In multi-pass modes, we need a virtual block array for each component. }
- whole_image : array[0..MAX_COMPONENTS-1] of jvirt_barray_ptr;
- end;
- { Forward declarations }
- {METHODDEF}
- function compress_data(cinfo : j_compress_ptr;
- input_buf : JSAMPIMAGE) : boolean; far; forward;
- {$ifdef FULL_COEF_BUFFER_SUPPORTED
- {METHODDEF}
- function compress_first_pass(cinfo : j_compress_ptr;
- input_buf : JSAMPIMAGE) : boolean; far; forward;
- {METHODDEF}
- function compress_output(cinfo : j_compress_ptr;
- input_buf : JSAMPIMAGE) : boolean; far; forward;
- {$endif}
- {LOCAL}
- procedure start_iMCU_row (cinfo : j_compress_ptr);
- { Reset within-iMCU-row counters for a new row }
- var
- coef : my_coef_ptr;
- begin
- coef := my_coef_ptr (cinfo^.coef);
- { In an interleaved scan, an MCU row is the same as an iMCU row.
- In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows.
- But at the bottom of the image, process only what's left. }
- if (cinfo^.comps_in_scan > 1) then
- begin
- coef^.MCU_rows_per_iMCU_row := 1;
- end
- else
- begin
- if (coef^.iMCU_row_num < (cinfo^.total_iMCU_rows-1)) then
- coef^.MCU_rows_per_iMCU_row := cinfo^.cur_comp_info[0]^.v_samp_factor
- else
- coef^.MCU_rows_per_iMCU_row := cinfo^.cur_comp_info[0]^.last_row_height;
- end;
- coef^.mcu_ctr := 0;
- coef^.MCU_vert_offset := 0;
- end;
- { Initialize for a processing pass. }
- {METHODDEF}
- procedure start_pass_coef (cinfo : j_compress_ptr;
- pass_mode : J_BUF_MODE); far;
- var
- coef : my_coef_ptr;
- begin
- coef := my_coef_ptr (cinfo^.coef);
- coef^.iMCU_row_num := 0;
- start_iMCU_row(cinfo);
- case (pass_mode) of
- JBUF_PASS_THRU:
- begin
- if (coef^.whole_image[0] <> NIL) then
- ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE);
- coef^.pub.compress_data := compress_data;
- end;
- {$ifdef FULL_COEF_BUFFER_SUPPORTED}
- JBUF_SAVE_AND_PASS:
- begin
- if (coef^.whole_image[0] = NIL) then
- ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE);
- coef^.pub.compress_data := compress_first_pass;
- end;
- JBUF_CRANK_DEST:
- begin
- if (coef^.whole_image[0] = NIL) then
- ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE);
- coef^.pub.compress_data := compress_output;
- end;
- {$endif}
- else
- ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE);
- end;
- end;
- { Process some data in the single-pass case.
- We process the equivalent of one fully interleaved MCU row ("iMCU" row)
- per call, ie, v_samp_factor block rows for each component in the image.
- Returns TRUE if the iMCU row is completed, FALSE if suspended.
- NB: input_buf contains a plane for each component in image,
- which we index according to the component's SOF position. }
- {METHODDEF}
- function compress_data (cinfo : j_compress_ptr;
- input_buf : JSAMPIMAGE) : boolean;
- var
- coef : my_coef_ptr;
- MCU_col_num : JDIMENSION; { index of current MCU within row }
- last_MCU_col : JDIMENSION;
- last_iMCU_row : JDIMENSION;
- blkn, bi, ci, yindex, yoffset, blockcnt : int;
- ypos, xpos : JDIMENSION;
- compptr : jpeg_component_info_ptr;
- begin
- coef := my_coef_ptr (cinfo^.coef);
- last_MCU_col := cinfo^.MCUs_per_row - 1;
- last_iMCU_row := cinfo^.total_iMCU_rows - 1;
- { Loop to write as much as one whole iMCU row }
- for yoffset := coef^.MCU_vert_offset to pred(coef^.MCU_rows_per_iMCU_row) do
- begin
- for MCU_col_num := coef^.mcu_ctr to last_MCU_col do
- begin
- { Determine where data comes from in input_buf and do the DCT thing.
- Each call on forward_DCT processes a horizontal row of DCT blocks
- as wide as an MCU; we rely on having allocated the MCU_buffer[] blocks
- sequentially. Dummy blocks at the right or bottom edge are filled in
- specially. The data in them does not matter for image reconstruction,
- so we fill them with values that will encode to the smallest amount of
- data, viz: all zeroes in the AC entries, DC entries equal to previous
- block's DC value. (Thanks to Thomas Kinsman for this idea.) }
- blkn := 0;
- for ci := 0 to pred(cinfo^.comps_in_scan) do
- begin
- compptr := cinfo^.cur_comp_info[ci];
- if (MCU_col_num < last_MCU_col) then
- blockcnt := compptr^.MCU_width
- else
- blockcnt := compptr^.last_col_width;
- xpos := MCU_col_num * compptr^.MCU_sample_width;
- ypos := yoffset * DCTSIZE; { ypos = (yoffset+yindex) * DCTSIZE }
- for yindex := 0 to pred(compptr^.MCU_height) do
- begin
- if (coef^.iMCU_row_num < last_iMCU_row) or
- (yoffset+yindex < compptr^.last_row_height) then
- begin
- cinfo^.fdct^.forward_DCT (cinfo, compptr,
- input_buf^[compptr^.component_index],
- coef^.MCU_buffer[blkn],
- ypos, xpos, JDIMENSION (blockcnt));
- if (blockcnt < compptr^.MCU_width) then
- begin
- { Create some dummy blocks at the right edge of the image. }
- jzero_far({FAR}pointer(coef^.MCU_buffer[blkn + blockcnt]),
- (compptr^.MCU_width - blockcnt) * SIZEOF(JBLOCK));
- for bi := blockcnt to pred(compptr^.MCU_width) do
- begin
- coef^.MCU_buffer[blkn+bi]^[0][0] := coef^.MCU_buffer[blkn+bi-1]^[0][0];
- end;
- end;
- end
- else
- begin
- { Create a row of dummy blocks at the bottom of the image. }
- jzero_far({FAR}pointer(coef^.MCU_buffer[blkn]),
- compptr^.MCU_width * SIZEOF(JBLOCK));
- for bi := 0 to pred(compptr^.MCU_width) do
- begin
- coef^.MCU_buffer[blkn+bi]^[0][0] := coef^.MCU_buffer[blkn-1]^[0][0];
- end;
- end;
- Inc(blkn, compptr^.MCU_width);
- Inc(ypos, DCTSIZE);
- end;
- end;
- { Try to write the MCU. In event of a suspension failure, we will
- re-DCT the MCU on restart (a bit inefficient, could be fixed...) }
- if (not cinfo^.entropy^.encode_mcu (cinfo, JBLOCKARRAY(@coef^.MCU_buffer)^)) then
- begin
- { Suspension forced; update state counters and exit }
- coef^.MCU_vert_offset := yoffset;
- coef^.mcu_ctr := MCU_col_num;
- compress_data := FALSE;
- exit;
- end;
- end;
- { Completed an MCU row, but perhaps not an iMCU row }
- coef^.mcu_ctr := 0;
- end;
- { Completed the iMCU row, advance counters for next one }
- Inc(coef^.iMCU_row_num);
- start_iMCU_row(cinfo);
- compress_data := TRUE;
- end;
- {$ifdef FULL_COEF_BUFFER_SUPPORTED}
- { Process some data in the first pass of a multi-pass case.
- We process the equivalent of one fully interleaved MCU row ("iMCU" row)
- per call, ie, v_samp_factor block rows for each component in the image.
- This amount of data is read from the source buffer, DCT'd and quantized,
- and saved into the virtual arrays. We also generate suitable dummy blocks
- as needed at the right and lower edges. (The dummy blocks are constructed
- in the virtual arrays, which have been padded appropriately.) This makes
- it possible for subsequent passes not to worry about real vs. dummy blocks.
- We must also emit the data to the entropy encoder. This is conveniently
- done by calling compress_output() after we've loaded the current strip
- of the virtual arrays.
- NB: input_buf contains a plane for each component in image. All
- components are DCT'd and loaded into the virtual arrays in this pass.
- However, it may be that only a subset of the components are emitted to
- the entropy encoder during this first pass; be careful about looking
- at the scan-dependent variables (MCU dimensions, etc). }
- {METHODDEF}
- function compress_first_pass (cinfo : j_compress_ptr;
- input_buf : JSAMPIMAGE) : boolean;
- var
- coef : my_coef_ptr;
- last_iMCU_row : JDIMENSION;
- blocks_across, MCUs_across, MCUindex : JDIMENSION;
- bi, ci, h_samp_factor, block_row, block_rows, ndummy : int;
- lastDC : JCOEF;
- compptr : jpeg_component_info_ptr;
- buffer : JBLOCKARRAY;
- thisblockrow, lastblockrow : JBLOCKROW;
- begin
- coef := my_coef_ptr (cinfo^.coef);
- last_iMCU_row := cinfo^.total_iMCU_rows - 1;
- compptr := jpeg_component_info_ptr(cinfo^.comp_info);
- for ci := 0 to pred(cinfo^.num_components) do
- begin
- { Align the virtual buffer for this component. }
- buffer := cinfo^.mem^.access_virt_barray
- (j_common_ptr(cinfo), coef^.whole_image[ci],
- coef^.iMCU_row_num * compptr^.v_samp_factor,
- JDIMENSION (compptr^.v_samp_factor), TRUE);
- { Count non-dummy DCT block rows in this iMCU row. }
- if (coef^.iMCU_row_num < last_iMCU_row) then
- block_rows := compptr^.v_samp_factor
- else
- begin
- { NB: can't use last_row_height here, since may not be set! }
- block_rows := int (compptr^.height_in_blocks mod compptr^.v_samp_factor);
- if (block_rows = 0) then
- block_rows := compptr^.v_samp_factor;
- end;
- blocks_across := compptr^.width_in_blocks;
- h_samp_factor := compptr^.h_samp_factor;
- { Count number of dummy blocks to be added at the right margin. }
- ndummy := int (blocks_across mod h_samp_factor);
- if (ndummy > 0) then
- ndummy := h_samp_factor - ndummy;
- { Perform DCT for all non-dummy blocks in this iMCU row. Each call
- on forward_DCT processes a complete horizontal row of DCT blocks. }
- for block_row := 0 to pred(block_rows) do
- begin
- thisblockrow := buffer^[block_row];
- cinfo^.fdct^.forward_DCT (cinfo, compptr,
- input_buf^[ci],
- thisblockrow,
- JDIMENSION (block_row * DCTSIZE),
- JDIMENSION (0),
- blocks_across);
- if (ndummy > 0) then
- begin
- { Create dummy blocks at the right edge of the image. }
- Inc(JBLOCK_PTR(thisblockrow), blocks_across); { => first dummy block }
- jzero_far({FAR}pointer(thisblockrow), ndummy * SIZEOF(JBLOCK));
- {lastDC := thisblockrow^[-1][0];}
- { work around Range Checking }
- Dec(JBLOCK_PTR(thisblockrow));
- lastDC := thisblockrow^[0][0];
- Inc(JBLOCK_PTR(thisblockrow));
- for bi := 0 to pred(ndummy) do
- begin
- thisblockrow^[bi][0] := lastDC;
- end;
- end;
- end;
- { If at end of image, create dummy block rows as needed.
- The tricky part here is that within each MCU, we want the DC values
- of the dummy blocks to match the last real block's DC value.
- This squeezes a few more bytes out of the resulting file... }
- if (coef^.iMCU_row_num = last_iMCU_row) then
- begin
- Inc(blocks_across, ndummy); { include lower right corner }
- MCUs_across := blocks_across div h_samp_factor;
- for block_row := block_rows to pred(compptr^.v_samp_factor) do
- begin
- thisblockrow := buffer^[block_row];
- lastblockrow := buffer^[block_row-1];
- jzero_far({FAR} pointer(thisblockrow),
- size_t(blocks_across * SIZEOF(JBLOCK)));
- for MCUindex := 0 to pred(MCUs_across) do
- begin
- lastDC := lastblockrow^[h_samp_factor-1][0];
- for bi := 0 to pred(h_samp_factor) do
- begin
- thisblockrow^[bi][0] := lastDC;
- end;
- Inc(JBLOCK_PTR(thisblockrow), h_samp_factor); { advance to next MCU in row }
- Inc(JBLOCK_PTR(lastblockrow), h_samp_factor);
- end;
- end;
- end;
- Inc(compptr);
- end;
- { NB: compress_output will increment iMCU_row_num if successful.
- A suspension return will result in redoing all the work above next time.}
- { Emit data to the entropy encoder, sharing code with subsequent passes }
- compress_first_pass := compress_output(cinfo, input_buf);
- end;
- { Process some data in subsequent passes of a multi-pass case.
- We process the equivalent of one fully interleaved MCU row ("iMCU" row)
- per call, ie, v_samp_factor block rows for each component in the scan.
- The data is obtained from the virtual arrays and fed to the entropy coder.
- Returns TRUE if the iMCU row is completed, FALSE if suspended.
- NB: input_buf is ignored; it is likely to be a NIL pointer. }
- {METHODDEF}
- function compress_output (cinfo : j_compress_ptr;
- input_buf : JSAMPIMAGE) : boolean;
- var
- coef : my_coef_ptr;
- MCU_col_num : JDIMENSION; { index of current MCU within row }
- blkn, ci, xindex, yindex, yoffset : int;
- start_col : JDIMENSION;
- buffer : array[0..MAX_COMPS_IN_SCAN-1] of JBLOCKARRAY;
- buffer_ptr : JBLOCKROW;
- compptr : jpeg_component_info_ptr;
- begin
- coef := my_coef_ptr (cinfo^.coef);
- { Align the virtual buffers for the components used in this scan.
- NB: during first pass, this is safe only because the buffers will
- already be aligned properly, so jmemmgr.c won't need to do any I/O. }
- for ci := 0 to pred(cinfo^.comps_in_scan) do
- begin
- compptr := cinfo^.cur_comp_info[ci];
- buffer[ci] := cinfo^.mem^.access_virt_barray (
- j_common_ptr(cinfo), coef^.whole_image[compptr^.component_index],
- coef^.iMCU_row_num * compptr^.v_samp_factor,
- JDIMENSION (compptr^.v_samp_factor), FALSE);
- end;
- { Loop to process one whole iMCU row }
- for yoffset := coef^.MCU_vert_offset to pred(coef^.MCU_rows_per_iMCU_row) do
- begin
- for MCU_col_num := coef^.mcu_ctr to pred(cinfo^.MCUs_per_row) do
- begin
- { Construct list of pointers to DCT blocks belonging to this MCU }
- blkn := 0; { index of current DCT block within MCU }
- for ci := 0 to pred(cinfo^.comps_in_scan) do
- begin
- compptr := cinfo^.cur_comp_info[ci];
- start_col := MCU_col_num * compptr^.MCU_width;
- for yindex := 0 to pred(compptr^.MCU_height) do
- begin
- buffer_ptr := JBLOCKROW(@ buffer[ci]^[yindex+yoffset]^[start_col]);
- for xindex := 0 to pred(compptr^.MCU_width) do
- begin
- coef^.MCU_buffer[blkn] := buffer_ptr;
- Inc(blkn);
- Inc(JBLOCK_PTR(buffer_ptr));
- end;
- end;
- end;
- { Try to write the MCU. }
- if (not cinfo^.entropy^.encode_mcu (cinfo, coef^.MCU_buffer)) then
- begin
- { Suspension forced; update state counters and exit }
- coef^.MCU_vert_offset := yoffset;
- coef^.mcu_ctr := MCU_col_num;
- compress_output := FALSE;
- exit;
- end;
- end;
- { Completed an MCU row, but perhaps not an iMCU row }
- coef^.mcu_ctr := 0;
- end;
- { Completed the iMCU row, advance counters for next one }
- Inc(coef^.iMCU_row_num);
- start_iMCU_row(cinfo);
- compress_output := TRUE;
- end;
- {$endif} { FULL_COEF_BUFFER_SUPPORTED }
- { Initialize coefficient buffer controller. }
- {GLOBAL}
- procedure jinit_c_coef_controller (cinfo : j_compress_ptr;
- need_full_buffer : boolean);
- var
- coef : my_coef_ptr;
- var
- buffer : JBLOCKROW;
- i : int;
- var
- ci : int;
- compptr : jpeg_component_info_ptr;
- begin
- coef := my_coef_ptr (
- cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
- SIZEOF(my_coef_controller)) );
- cinfo^.coef := jpeg_c_coef_controller_ptr(coef);
- coef^.pub.start_pass := start_pass_coef;
- { Create the coefficient buffer. }
- if (need_full_buffer) then
- begin
- {$ifdef FULL_COEF_BUFFER_SUPPORTED}
- { Allocate a full-image virtual array for each component, }
- { padded to a multiple of samp_factor DCT blocks in each direction. }
- compptr := jpeg_component_info_ptr(cinfo^.comp_info);
- for ci := 0 to pred(cinfo^.num_components) do
- begin
- coef^.whole_image[ci] := cinfo^.mem^.request_virt_barray
- (j_common_ptr(cinfo), JPOOL_IMAGE, FALSE,
- JDIMENSION (jround_up( long (compptr^.width_in_blocks),
- long (compptr^.h_samp_factor) )),
- JDIMENSION (jround_up(long (compptr^.height_in_blocks),
- long (compptr^.v_samp_factor))),
- JDIMENSION (compptr^.v_samp_factor));
- Inc(compptr);
- end;
- {$else}
- ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE);
- {$endif}
- end
- else
- begin
- { We only need a single-MCU buffer. }
- buffer := JBLOCKROW (
- cinfo^.mem^.alloc_large (j_common_ptr(cinfo), JPOOL_IMAGE,
- C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK)) );
- for i := 0 to pred(C_MAX_BLOCKS_IN_MCU) do
- begin
- coef^.MCU_buffer[i] := JBLOCKROW(@ buffer^[i]);
- end;
- coef^.whole_image[0] := NIL; { flag for no virtual arrays }
- end;
- end;
- end.
|