DEADSOFTWARE

hopefully no more windows
[d2df-editor.git] / src / lib / vampimg / JpegLib / imjccoefct.pas
1 unit imjccoefct;
3 { This file contains the coefficient buffer controller for compression.
4 This controller is the top level of the JPEG compressor proper.
5 The coefficient buffer lies between forward-DCT and entropy encoding steps.}
7 { Original: jccoefct.c; Copyright (C) 1994-1997, Thomas G. Lane. }
9 interface
11 {$I imjconfig.inc}
13 uses
14 imjmorecfg,
15 imjinclude,
16 imjerror,
17 imjdeferr,
18 imjutils,
19 imjpeglib;
21 { We use a full-image coefficient buffer when doing Huffman optimization,
22 and also for writing multiple-scan JPEG files. In all cases, the DCT
23 step is run during the first pass, and subsequent passes need only read
24 the buffered coefficients. }
25 {$ifdef ENTROPY_OPT_SUPPORTED}
26 {$define FULL_COEF_BUFFER_SUPPORTED}
27 {$else}
28 {$ifdef C_MULTISCAN_FILES_SUPPORTED}
29 {$define FULL_COEF_BUFFER_SUPPORTED}
30 {$endif}
31 {$endif}
33 { Initialize coefficient buffer controller. }
35 {GLOBAL}
36 procedure jinit_c_coef_controller (cinfo : j_compress_ptr;
37 need_full_buffer : boolean);
39 implementation
41 { Private buffer controller object }
43 type
44 my_coef_ptr = ^my_coef_controller;
45 my_coef_controller = record
46 pub : jpeg_c_coef_controller; { public fields }
48 iMCU_row_num : JDIMENSION; { iMCU row # within image }
49 mcu_ctr : JDIMENSION; { counts MCUs processed in current row }
50 MCU_vert_offset : int; { counts MCU rows within iMCU row }
51 MCU_rows_per_iMCU_row : int; { number of such rows needed }
53 { For single-pass compression, it's sufficient to buffer just one MCU
54 (although this may prove a bit slow in practice). We allocate a
55 workspace of C_MAX_BLOCKS_IN_MCU coefficient blocks, and reuse it for each
56 MCU constructed and sent. (On 80x86, the workspace is FAR even though
57 it's not really very big; this is to keep the module interfaces unchanged
58 when a large coefficient buffer is necessary.)
59 In multi-pass modes, this array points to the current MCU's blocks
60 within the virtual arrays. }
62 MCU_buffer : array[0..C_MAX_BLOCKS_IN_MCU-1] of JBLOCKROW;
64 { In multi-pass modes, we need a virtual block array for each component. }
65 whole_image : array[0..MAX_COMPONENTS-1] of jvirt_barray_ptr;
66 end;
69 { Forward declarations }
70 {METHODDEF}
71 function compress_data(cinfo : j_compress_ptr;
72 input_buf : JSAMPIMAGE) : boolean; forward;
73 {$ifdef FULL_COEF_BUFFER_SUPPORTED}
74 {METHODDEF}
75 function compress_first_pass(cinfo : j_compress_ptr;
76 input_buf : JSAMPIMAGE) : boolean; forward;
77 {METHODDEF}
78 function compress_output(cinfo : j_compress_ptr;
79 input_buf : JSAMPIMAGE) : boolean; forward;
80 {$endif}
83 {LOCAL}
84 procedure start_iMCU_row (cinfo : j_compress_ptr);
85 { Reset within-iMCU-row counters for a new row }
86 var
87 coef : my_coef_ptr;
88 begin
89 coef := my_coef_ptr (cinfo^.coef);
91 { In an interleaved scan, an MCU row is the same as an iMCU row.
92 In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows.
93 But at the bottom of the image, process only what's left. }
94 if (cinfo^.comps_in_scan > 1) then
95 begin
96 coef^.MCU_rows_per_iMCU_row := 1;
97 end
98 else
99 begin
100 if (coef^.iMCU_row_num < (cinfo^.total_iMCU_rows-1)) then
101 coef^.MCU_rows_per_iMCU_row := cinfo^.cur_comp_info[0]^.v_samp_factor
102 else
103 coef^.MCU_rows_per_iMCU_row := cinfo^.cur_comp_info[0]^.last_row_height;
104 end;
106 coef^.mcu_ctr := 0;
107 coef^.MCU_vert_offset := 0;
108 end;
111 { Initialize for a processing pass. }
113 {METHODDEF}
114 procedure start_pass_coef (cinfo : j_compress_ptr;
115 pass_mode : J_BUF_MODE);
116 var
117 coef : my_coef_ptr;
118 begin
119 coef := my_coef_ptr (cinfo^.coef);
121 coef^.iMCU_row_num := 0;
122 start_iMCU_row(cinfo);
124 case (pass_mode) of
125 JBUF_PASS_THRU:
126 begin
127 if (coef^.whole_image[0] <> NIL) then
128 ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE);
129 coef^.pub.compress_data := compress_data;
130 end;
131 {$ifdef FULL_COEF_BUFFER_SUPPORTED}
132 JBUF_SAVE_AND_PASS:
133 begin
134 if (coef^.whole_image[0] = NIL) then
135 ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE);
136 coef^.pub.compress_data := compress_first_pass;
137 end;
138 JBUF_CRANK_DEST:
139 begin
140 if (coef^.whole_image[0] = NIL) then
141 ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE);
142 coef^.pub.compress_data := compress_output;
143 end;
144 {$endif}
145 else
146 ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE);
147 end;
148 end;
151 { Process some data in the single-pass case.
152 We process the equivalent of one fully interleaved MCU row ("iMCU" row)
153 per call, ie, v_samp_factor block rows for each component in the image.
154 Returns TRUE if the iMCU row is completed, FALSE if suspended.
156 NB: input_buf contains a plane for each component in image,
157 which we index according to the component's SOF position. }
160 {METHODDEF}
161 function compress_data (cinfo : j_compress_ptr;
162 input_buf : JSAMPIMAGE) : boolean;
163 var
164 coef : my_coef_ptr;
165 MCU_col_num : JDIMENSION; { index of current MCU within row }
166 last_MCU_col : JDIMENSION;
167 last_iMCU_row : JDIMENSION;
168 blkn, bi, ci, yindex, yoffset, blockcnt : int;
169 ypos, xpos : JDIMENSION;
170 compptr : jpeg_component_info_ptr;
171 begin
172 coef := my_coef_ptr (cinfo^.coef);
173 last_MCU_col := cinfo^.MCUs_per_row - 1;
174 last_iMCU_row := cinfo^.total_iMCU_rows - 1;
176 { Loop to write as much as one whole iMCU row }
177 for yoffset := coef^.MCU_vert_offset to pred(coef^.MCU_rows_per_iMCU_row) do
178 begin
179 for MCU_col_num := coef^.mcu_ctr to last_MCU_col do
180 begin
181 { Determine where data comes from in input_buf and do the DCT thing.
182 Each call on forward_DCT processes a horizontal row of DCT blocks
183 as wide as an MCU; we rely on having allocated the MCU_buffer[] blocks
184 sequentially. Dummy blocks at the right or bottom edge are filled in
185 specially. The data in them does not matter for image reconstruction,
186 so we fill them with values that will encode to the smallest amount of
187 data, viz: all zeroes in the AC entries, DC entries equal to previous
188 block's DC value. (Thanks to Thomas Kinsman for this idea.) }
190 blkn := 0;
191 for ci := 0 to pred(cinfo^.comps_in_scan) do
192 begin
193 compptr := cinfo^.cur_comp_info[ci];
194 if (MCU_col_num < last_MCU_col) then
195 blockcnt := compptr^.MCU_width
196 else
197 blockcnt := compptr^.last_col_width;
198 xpos := MCU_col_num * JDIMENSION(compptr^.MCU_sample_width);
199 ypos := yoffset * DCTSIZE; { ypos = (yoffset+yindex) * DCTSIZE }
200 for yindex := 0 to pred(compptr^.MCU_height) do
201 begin
202 if (coef^.iMCU_row_num < last_iMCU_row) or
203 (yoffset+yindex < compptr^.last_row_height) then
204 begin
205 cinfo^.fdct^.forward_DCT (cinfo, compptr,
206 input_buf^[compptr^.component_index],
207 coef^.MCU_buffer[blkn],
208 ypos, xpos, JDIMENSION (blockcnt));
210 if (blockcnt < compptr^.MCU_width) then
211 begin
212 { Create some dummy blocks at the right edge of the image. }
213 jzero_far({FAR}pointer(coef^.MCU_buffer[blkn + blockcnt]),
214 (compptr^.MCU_width - blockcnt) * SIZEOF(JBLOCK));
215 for bi := blockcnt to pred(compptr^.MCU_width) do
216 begin
217 coef^.MCU_buffer[blkn+bi]^[0][0] := coef^.MCU_buffer[blkn+bi-1]^[0][0];
218 end;
219 end;
220 end
221 else
222 begin
223 { Create a row of dummy blocks at the bottom of the image. }
224 jzero_far({FAR}pointer(coef^.MCU_buffer[blkn]),
225 compptr^.MCU_width * SIZEOF(JBLOCK));
226 for bi := 0 to pred(compptr^.MCU_width) do
227 begin
228 coef^.MCU_buffer[blkn+bi]^[0][0] := coef^.MCU_buffer[blkn-1]^[0][0];
229 end;
230 end;
231 Inc(blkn, compptr^.MCU_width);
232 Inc(ypos, DCTSIZE);
233 end;
234 end;
235 { Try to write the MCU. In event of a suspension failure, we will
236 re-DCT the MCU on restart (a bit inefficient, could be fixed...) }
238 if (not cinfo^.entropy^.encode_mcu (cinfo, JBLOCKARRAY(@coef^.MCU_buffer)^)) then
239 begin
240 { Suspension forced; update state counters and exit }
241 coef^.MCU_vert_offset := yoffset;
242 coef^.mcu_ctr := MCU_col_num;
243 compress_data := FALSE;
244 exit;
245 end;
246 end;
247 { Completed an MCU row, but perhaps not an iMCU row }
248 coef^.mcu_ctr := 0;
249 end;
250 { Completed the iMCU row, advance counters for next one }
251 Inc(coef^.iMCU_row_num);
252 start_iMCU_row(cinfo);
253 compress_data := TRUE;
254 end;
257 {$ifdef FULL_COEF_BUFFER_SUPPORTED}
259 { Process some data in the first pass of a multi-pass case.
260 We process the equivalent of one fully interleaved MCU row ("iMCU" row)
261 per call, ie, v_samp_factor block rows for each component in the image.
262 This amount of data is read from the source buffer, DCT'd and quantized,
263 and saved into the virtual arrays. We also generate suitable dummy blocks
264 as needed at the right and lower edges. (The dummy blocks are constructed
265 in the virtual arrays, which have been padded appropriately.) This makes
266 it possible for subsequent passes not to worry about real vs. dummy blocks.
268 We must also emit the data to the entropy encoder. This is conveniently
269 done by calling compress_output() after we've loaded the current strip
270 of the virtual arrays.
272 NB: input_buf contains a plane for each component in image. All
273 components are DCT'd and loaded into the virtual arrays in this pass.
274 However, it may be that only a subset of the components are emitted to
275 the entropy encoder during this first pass; be careful about looking
276 at the scan-dependent variables (MCU dimensions, etc). }
278 {METHODDEF}
279 function compress_first_pass (cinfo : j_compress_ptr;
280 input_buf : JSAMPIMAGE) : boolean;
281 var
282 coef : my_coef_ptr;
283 last_iMCU_row : JDIMENSION;
284 blocks_across, MCUs_across, MCUindex : JDIMENSION;
285 bi, ci, h_samp_factor, block_row, block_rows, ndummy : int;
286 lastDC : JCOEF;
287 compptr : jpeg_component_info_ptr;
288 buffer : JBLOCKARRAY;
289 thisblockrow, lastblockrow : JBLOCKROW;
290 begin
291 coef := my_coef_ptr (cinfo^.coef);
292 last_iMCU_row := cinfo^.total_iMCU_rows - 1;
294 compptr := jpeg_component_info_ptr(cinfo^.comp_info);
295 for ci := 0 to pred(cinfo^.num_components) do
296 begin
297 { Align the virtual buffer for this component. }
298 buffer := cinfo^.mem^.access_virt_barray
299 (j_common_ptr(cinfo), coef^.whole_image[ci],
300 coef^.iMCU_row_num * JDIMENSION(compptr^.v_samp_factor),
301 JDIMENSION (compptr^.v_samp_factor), TRUE);
302 { Count non-dummy DCT block rows in this iMCU row. }
303 if (coef^.iMCU_row_num < last_iMCU_row) then
304 block_rows := compptr^.v_samp_factor
305 else
306 begin
307 { NB: can't use last_row_height here, since may not be set! }
308 block_rows := int (compptr^.height_in_blocks) mod compptr^.v_samp_factor;
309 if (block_rows = 0) then
310 block_rows := compptr^.v_samp_factor;
311 end;
312 blocks_across := compptr^.width_in_blocks;
313 h_samp_factor := compptr^.h_samp_factor;
314 { Count number of dummy blocks to be added at the right margin. }
315 ndummy := int (blocks_across) mod h_samp_factor;
316 if (ndummy > 0) then
317 ndummy := h_samp_factor - ndummy;
318 { Perform DCT for all non-dummy blocks in this iMCU row. Each call
319 on forward_DCT processes a complete horizontal row of DCT blocks. }
321 for block_row := 0 to pred(block_rows) do
322 begin
323 thisblockrow := buffer^[block_row];
324 cinfo^.fdct^.forward_DCT (cinfo, compptr,
325 input_buf^[ci],
326 thisblockrow,
327 JDIMENSION (block_row * DCTSIZE),
328 JDIMENSION (0),
329 blocks_across);
330 if (ndummy > 0) then
331 begin
332 { Create dummy blocks at the right edge of the image. }
333 Inc(JBLOCK_PTR(thisblockrow), blocks_across); { => first dummy block }
334 jzero_far({FAR}pointer(thisblockrow), ndummy * SIZEOF(JBLOCK));
335 {lastDC := thisblockrow^[-1][0];}
336 { work around Range Checking }
337 Dec(JBLOCK_PTR(thisblockrow));
338 lastDC := thisblockrow^[0][0];
339 Inc(JBLOCK_PTR(thisblockrow));
341 for bi := 0 to pred(ndummy) do
342 begin
343 thisblockrow^[bi][0] := lastDC;
344 end;
345 end;
346 end;
347 { If at end of image, create dummy block rows as needed.
348 The tricky part here is that within each MCU, we want the DC values
349 of the dummy blocks to match the last real block's DC value.
350 This squeezes a few more bytes out of the resulting file... }
352 if (coef^.iMCU_row_num = last_iMCU_row) then
353 begin
354 Inc(blocks_across, ndummy); { include lower right corner }
355 MCUs_across := blocks_across div JDIMENSION(h_samp_factor);
356 for block_row := block_rows to pred(compptr^.v_samp_factor) do
357 begin
358 thisblockrow := buffer^[block_row];
359 lastblockrow := buffer^[block_row-1];
360 jzero_far({FAR} pointer(thisblockrow),
361 size_t(blocks_across * SIZEOF(JBLOCK)));
362 for MCUindex := 0 to pred(MCUs_across) do
363 begin
364 lastDC := lastblockrow^[h_samp_factor-1][0];
365 for bi := 0 to pred(h_samp_factor) do
366 begin
367 thisblockrow^[bi][0] := lastDC;
368 end;
369 Inc(JBLOCK_PTR(thisblockrow), h_samp_factor); { advance to next MCU in row }
370 Inc(JBLOCK_PTR(lastblockrow), h_samp_factor);
371 end;
372 end;
373 end;
374 Inc(compptr);
375 end;
376 { NB: compress_output will increment iMCU_row_num if successful.
377 A suspension return will result in redoing all the work above next time.}
380 { Emit data to the entropy encoder, sharing code with subsequent passes }
381 compress_first_pass := compress_output(cinfo, input_buf);
382 end;
385 { Process some data in subsequent passes of a multi-pass case.
386 We process the equivalent of one fully interleaved MCU row ("iMCU" row)
387 per call, ie, v_samp_factor block rows for each component in the scan.
388 The data is obtained from the virtual arrays and fed to the entropy coder.
389 Returns TRUE if the iMCU row is completed, FALSE if suspended.
391 NB: input_buf is ignored; it is likely to be a NIL pointer. }
393 {METHODDEF}
394 function compress_output (cinfo : j_compress_ptr;
395 input_buf : JSAMPIMAGE) : boolean;
396 var
397 coef : my_coef_ptr;
398 MCU_col_num : JDIMENSION; { index of current MCU within row }
399 blkn, ci, xindex, yindex, yoffset : int;
400 start_col : JDIMENSION;
401 buffer : array[0..MAX_COMPS_IN_SCAN-1] of JBLOCKARRAY;
402 buffer_ptr : JBLOCKROW;
403 compptr : jpeg_component_info_ptr;
404 begin
405 coef := my_coef_ptr (cinfo^.coef);
407 { Align the virtual buffers for the components used in this scan.
408 NB: during first pass, this is safe only because the buffers will
409 already be aligned properly, so jmemmgr.c won't need to do any I/O. }
411 for ci := 0 to pred(cinfo^.comps_in_scan) do
412 begin
413 compptr := cinfo^.cur_comp_info[ci];
414 buffer[ci] := cinfo^.mem^.access_virt_barray (
415 j_common_ptr(cinfo), coef^.whole_image[compptr^.component_index],
416 coef^.iMCU_row_num * JDIMENSION(compptr^.v_samp_factor),
417 JDIMENSION (compptr^.v_samp_factor), FALSE);
418 end;
420 { Loop to process one whole iMCU row }
421 for yoffset := coef^.MCU_vert_offset to pred(coef^.MCU_rows_per_iMCU_row) do
422 begin
423 for MCU_col_num := coef^.mcu_ctr to pred(cinfo^.MCUs_per_row) do
424 begin
425 { Construct list of pointers to DCT blocks belonging to this MCU }
426 blkn := 0; { index of current DCT block within MCU }
427 for ci := 0 to pred(cinfo^.comps_in_scan) do
428 begin
429 compptr := cinfo^.cur_comp_info[ci];
430 start_col := MCU_col_num * JDIMENSION(compptr^.MCU_width);
431 for yindex := 0 to pred(compptr^.MCU_height) do
432 begin
433 buffer_ptr := JBLOCKROW(@ buffer[ci]^[yindex+yoffset]^[start_col]);
434 for xindex := 0 to pred(compptr^.MCU_width) do
435 begin
436 coef^.MCU_buffer[blkn] := buffer_ptr;
437 Inc(blkn);
438 Inc(JBLOCK_PTR(buffer_ptr));
439 end;
440 end;
441 end;
442 { Try to write the MCU. }
443 if (not cinfo^.entropy^.encode_mcu (cinfo, coef^.MCU_buffer)) then
444 begin
445 { Suspension forced; update state counters and exit }
446 coef^.MCU_vert_offset := yoffset;
447 coef^.mcu_ctr := MCU_col_num;
448 compress_output := FALSE;
449 exit;
450 end;
451 end;
452 { Completed an MCU row, but perhaps not an iMCU row }
453 coef^.mcu_ctr := 0;
454 end;
455 { Completed the iMCU row, advance counters for next one }
456 Inc(coef^.iMCU_row_num);
457 start_iMCU_row(cinfo);
458 compress_output := TRUE;
459 end;
461 {$endif} { FULL_COEF_BUFFER_SUPPORTED }
464 { Initialize coefficient buffer controller. }
466 {GLOBAL}
467 procedure jinit_c_coef_controller (cinfo : j_compress_ptr;
468 need_full_buffer : boolean);
469 var
470 coef : my_coef_ptr;
471 var
472 buffer : JBLOCKROW;
473 i : int;
474 var
475 ci : int;
476 compptr : jpeg_component_info_ptr;
477 begin
478 coef := my_coef_ptr (
479 cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
480 SIZEOF(my_coef_controller)) );
481 cinfo^.coef := jpeg_c_coef_controller_ptr(coef);
482 coef^.pub.start_pass := start_pass_coef;
484 { Create the coefficient buffer. }
485 if (need_full_buffer) then
486 begin
487 {$ifdef FULL_COEF_BUFFER_SUPPORTED}
488 { Allocate a full-image virtual array for each component, }
489 { padded to a multiple of samp_factor DCT blocks in each direction. }
491 compptr := jpeg_component_info_ptr(cinfo^.comp_info);
492 for ci := 0 to pred(cinfo^.num_components) do
493 begin
494 coef^.whole_image[ci] := cinfo^.mem^.request_virt_barray
495 (j_common_ptr(cinfo), JPOOL_IMAGE, FALSE,
496 JDIMENSION (jround_up( long (compptr^.width_in_blocks),
497 long (compptr^.h_samp_factor) )),
498 JDIMENSION (jround_up(long (compptr^.height_in_blocks),
499 long (compptr^.v_samp_factor))),
500 JDIMENSION (compptr^.v_samp_factor));
501 Inc(compptr);
502 end;
503 {$else}
504 ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE);
505 {$endif}
506 end
507 else
508 begin
509 { We only need a single-MCU buffer. }
510 buffer := JBLOCKROW (
511 cinfo^.mem^.alloc_large (j_common_ptr(cinfo), JPOOL_IMAGE,
512 C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK)) );
513 for i := 0 to pred(C_MAX_BLOCKS_IN_MCU) do
514 begin
515 coef^.MCU_buffer[i] := JBLOCKROW(@ buffer^[i]);
516 end;
517 coef^.whole_image[0] := NIL; { flag for no virtual arrays }
518 end;
519 end;
521 end.