DEADSOFTWARE

hopefully no more windows
[d2df-editor.git] / src / lib / vampimg / JpegLib / imjcprepct.pas
1 unit imjcprepct;
3 { Original : jcprepct.c ; Copyright (C) 1994-1996, Thomas G. Lane. }
5 { This file contains the compression preprocessing controller.
6 This controller manages the color conversion, downsampling,
7 and edge expansion steps.
9 Most of the complexity here is associated with buffering input rows
10 as required by the downsampler. See the comments at the head of
11 jcsample.c for the downsampler's needs. }
13 interface
15 {$I imjconfig.inc}
17 uses
18 imjmorecfg,
19 imjpeglib,
20 imjdeferr,
21 imjerror,
22 imjinclude,
23 imjutils;
25 {GLOBAL}
26 procedure jinit_c_prep_controller (cinfo : j_compress_ptr;
27 need_full_buffer : boolean);
29 implementation
32 { At present, jcsample.c can request context rows only for smoothing.
33 In the future, we might also need context rows for CCIR601 sampling
34 or other more-complex downsampling procedures. The code to support
35 context rows should be compiled only if needed. }
37 {$ifdef INPUT_SMOOTHING_SUPPORTED}
38 {$define CONTEXT_ROWS_SUPPORTED}
39 {$endif}
42 { For the simple (no-context-row) case, we just need to buffer one
43 row group's worth of pixels for the downsampling step. At the bottom of
44 the image, we pad to a full row group by replicating the last pixel row.
45 The downsampler's last output row is then replicated if needed to pad
46 out to a full iMCU row.
48 When providing context rows, we must buffer three row groups' worth of
49 pixels. Three row groups are physically allocated, but the row pointer
50 arrays are made five row groups high, with the extra pointers above and
51 below "wrapping around" to point to the last and first real row groups.
52 This allows the downsampler to access the proper context rows.
53 At the top and bottom of the image, we create dummy context rows by
54 copying the first or last real pixel row. This copying could be avoided
55 by pointer hacking as is done in jdmainct.c, but it doesn't seem worth the
56 trouble on the compression side. }
59 { Private buffer controller object }
61 type
62 my_prep_ptr = ^my_prep_controller;
63 my_prep_controller = record
64 pub : jpeg_c_prep_controller; { public fields }
66 { Downsampling input buffer. This buffer holds color-converted data
67 until we have enough to do a downsample step. }
69 color_buf : array[0..MAX_COMPONENTS-1] of JSAMPARRAY;
71 rows_to_go : JDIMENSION; { counts rows remaining in source image }
72 next_buf_row : int; { index of next row to store in color_buf }
74 {$ifdef CONTEXT_ROWS_SUPPORTED} { only needed for context case }
75 this_row_group : int; { starting row index of group to process }
76 next_buf_stop : int; { downsample when we reach this index }
77 {$endif}
78 end; {my_prep_controller;}
81 { Initialize for a processing pass. }
83 {METHODDEF}
84 procedure start_pass_prep (cinfo : j_compress_ptr;
85 pass_mode : J_BUF_MODE );
86 var
87 prep : my_prep_ptr;
88 begin
89 prep := my_prep_ptr (cinfo^.prep);
91 if (pass_mode <> JBUF_PASS_THRU) then
92 ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE);
94 { Initialize total-height counter for detecting bottom of image }
95 prep^.rows_to_go := cinfo^.image_height;
96 { Mark the conversion buffer empty }
97 prep^.next_buf_row := 0;
98 {$ifdef CONTEXT_ROWS_SUPPORTED}
99 { Preset additional state variables for context mode.
100 These aren't used in non-context mode, so we needn't test which mode. }
101 prep^.this_row_group := 0;
102 { Set next_buf_stop to stop after two row groups have been read in. }
103 prep^.next_buf_stop := 2 * cinfo^.max_v_samp_factor;
104 {$endif}
105 end;
108 { Expand an image vertically from height input_rows to height output_rows,
109 by duplicating the bottom row. }
111 {LOCAL}
112 procedure expand_bottom_edge (image_data : JSAMPARRAY;
113 num_cols : JDIMENSION;
114 input_rows : int;
115 output_rows : int);
116 var
117 {register} row : int;
118 begin
119 for row := input_rows to pred(output_rows) do
120 begin
121 jcopy_sample_rows(image_data, input_rows-1, image_data, row,
122 1, num_cols);
123 end;
124 end;
127 { Process some data in the simple no-context case.
129 Preprocessor output data is counted in "row groups". A row group
130 is defined to be v_samp_factor sample rows of each component.
131 Downsampling will produce this much data from each max_v_samp_factor
132 input rows. }
134 {METHODDEF}
135 procedure pre_process_data (cinfo : j_compress_ptr;
136 input_buf : JSAMPARRAY;
137 var in_row_ctr : JDIMENSION;
138 in_rows_avail : JDIMENSION;
139 output_buf : JSAMPIMAGE;
140 var out_row_group_ctr : JDIMENSION;
141 out_row_groups_avail : JDIMENSION);
142 var
143 prep : my_prep_ptr;
144 numrows, ci : int;
145 inrows : JDIMENSION;
146 compptr : jpeg_component_info_ptr;
147 var
148 local_input_buf : JSAMPARRAY;
149 begin
150 prep := my_prep_ptr (cinfo^.prep);
152 while (in_row_ctr < in_rows_avail) and
153 (out_row_group_ctr < out_row_groups_avail) do
154 begin
155 { Do color conversion to fill the conversion buffer. }
156 inrows := in_rows_avail - in_row_ctr;
157 numrows := cinfo^.max_v_samp_factor - prep^.next_buf_row;
158 {numrows := int( MIN(JDIMENSION(numrows), inrows) );}
159 if inrows < JDIMENSION(numrows) then
160 numrows := int(inrows);
161 local_input_buf := JSAMPARRAY(@(input_buf^[in_row_ctr]));
162 cinfo^.cconvert^.color_convert (cinfo, local_input_buf,
163 JSAMPIMAGE(@prep^.color_buf),
164 JDIMENSION(prep^.next_buf_row),
165 numrows);
166 Inc(in_row_ctr, numrows);
167 Inc(prep^.next_buf_row, numrows);
168 Dec(prep^.rows_to_go, numrows);
169 { If at bottom of image, pad to fill the conversion buffer. }
170 if (prep^.rows_to_go = 0) and
171 (prep^.next_buf_row < cinfo^.max_v_samp_factor) then
172 begin
173 for ci := 0 to pred(cinfo^.num_components) do
174 begin
175 expand_bottom_edge(prep^.color_buf[ci], cinfo^.image_width,
176 prep^.next_buf_row, cinfo^.max_v_samp_factor);
177 end;
178 prep^.next_buf_row := cinfo^.max_v_samp_factor;
179 end;
180 { If we've filled the conversion buffer, empty it. }
181 if (prep^.next_buf_row = cinfo^.max_v_samp_factor) then
182 begin
183 cinfo^.downsample^.downsample (cinfo,
184 JSAMPIMAGE(@prep^.color_buf),
185 JDIMENSION (0),
186 output_buf,
187 out_row_group_ctr);
188 prep^.next_buf_row := 0;
189 Inc(out_row_group_ctr);;
190 end;
191 { If at bottom of image, pad the output to a full iMCU height.
192 Note we assume the caller is providing a one-iMCU-height output buffer! }
193 if (prep^.rows_to_go = 0) and
194 (out_row_group_ctr < out_row_groups_avail) then
195 begin
196 compptr := jpeg_component_info_ptr(cinfo^.comp_info);
197 for ci := 0 to pred(cinfo^.num_components) do
198 begin
199 expand_bottom_edge(output_buf^[ci],
200 compptr^.width_in_blocks * DCTSIZE,
201 int (out_row_group_ctr) * compptr^.v_samp_factor,
202 int (out_row_groups_avail) * compptr^.v_samp_factor);
203 Inc(compptr);
204 end;
205 out_row_group_ctr := out_row_groups_avail;
206 break; { can exit outer loop without test }
207 end;
208 end;
209 end;
212 {$ifdef CONTEXT_ROWS_SUPPORTED}
214 { Process some data in the context case. }
216 {METHODDEF}
217 procedure pre_process_context (cinfo : j_compress_ptr;
218 input_buf : JSAMPARRAY;
219 var in_row_ctr : JDIMENSION;
220 in_rows_avail : JDIMENSION;
221 output_buf : JSAMPIMAGE;
222 var out_row_group_ctr : JDIMENSION;
223 out_row_groups_avail : JDIMENSION);
224 var
225 prep : my_prep_ptr;
226 numrows, ci : int;
227 buf_height : int;
228 inrows : JDIMENSION;
229 var
230 row : int;
232 begin
233 prep := my_prep_ptr (cinfo^.prep);
234 buf_height := cinfo^.max_v_samp_factor * 3;
236 while (out_row_group_ctr < out_row_groups_avail) do
237 begin
238 if (in_row_ctr < in_rows_avail) then
239 begin
240 { Do color conversion to fill the conversion buffer. }
241 inrows := in_rows_avail - in_row_ctr;
242 numrows := prep^.next_buf_stop - prep^.next_buf_row;
243 {numrows := int ( MIN( JDIMENSION(numrows), inrows) );}
244 if inrows < JDIMENSION(numrows) then
245 numrows := int(inrows);
246 cinfo^.cconvert^.color_convert (cinfo,
247 JSAMPARRAY(@input_buf^[in_row_ctr]),
248 JSAMPIMAGE(@prep^.color_buf),
249 JDIMENSION (prep^.next_buf_row),
250 numrows);
251 { Pad at top of image, if first time through }
252 if (prep^.rows_to_go = cinfo^.image_height) then
253 begin
254 for ci := 0 to pred(cinfo^.num_components) do
255 begin
256 for row := 1 to cinfo^.max_v_samp_factor do
257 begin
258 jcopy_sample_rows(prep^.color_buf[ci], 0,
259 prep^.color_buf[ci], -row,
260 1, cinfo^.image_width);
261 end;
262 end;
263 end;
264 Inc(in_row_ctr, numrows);
265 Inc(prep^.next_buf_row, numrows);
266 Dec(prep^.rows_to_go, numrows);
267 end
268 else
269 begin
270 { Return for more data, unless we are at the bottom of the image. }
271 if (prep^.rows_to_go <> 0) then
272 break;
273 { When at bottom of image, pad to fill the conversion buffer. }
274 if (prep^.next_buf_row < prep^.next_buf_stop) then
275 begin
276 for ci := 0 to pred(cinfo^.num_components) do
277 begin
278 expand_bottom_edge(prep^.color_buf[ci], cinfo^.image_width,
279 prep^.next_buf_row, prep^.next_buf_stop);
280 end;
281 prep^.next_buf_row := prep^.next_buf_stop;
282 end;
283 end;
284 { If we've gotten enough data, downsample a row group. }
285 if (prep^.next_buf_row = prep^.next_buf_stop) then
286 begin
287 cinfo^.downsample^.downsample (cinfo,
288 JSAMPIMAGE(@prep^.color_buf),
289 JDIMENSION(prep^.this_row_group),
290 output_buf,
291 out_row_group_ctr);
292 Inc(out_row_group_ctr);
293 { Advance pointers with wraparound as necessary. }
294 Inc(prep^.this_row_group, cinfo^.max_v_samp_factor);
295 if (prep^.this_row_group >= buf_height) then
296 prep^.this_row_group := 0;
297 if (prep^.next_buf_row >= buf_height) then
298 prep^.next_buf_row := 0;
299 prep^.next_buf_stop := prep^.next_buf_row + cinfo^.max_v_samp_factor;
300 end;
301 end;
302 end;
305 { Create the wrapped-around downsampling input buffer needed for context mode. }
307 {LOCAL}
308 procedure create_context_buffer (cinfo : j_compress_ptr);
309 var
310 prep : my_prep_ptr;
311 rgroup_height : int;
312 ci, i : int;
313 compptr : jpeg_component_info_ptr;
314 true_buffer, fake_buffer : JSAMPARRAY;
315 begin
316 prep := my_prep_ptr (cinfo^.prep);
317 rgroup_height := cinfo^.max_v_samp_factor;
318 { Grab enough space for fake row pointers for all the components;
319 we need five row groups' worth of pointers for each component. }
321 fake_buffer := JSAMPARRAY(
322 cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
323 (cinfo^.num_components * 5 * rgroup_height) *
324 SIZEOF(JSAMPROW)) );
326 compptr := jpeg_component_info_ptr(cinfo^.comp_info);
327 for ci := 0 to pred(cinfo^.num_components) do
328 begin
329 { Allocate the actual buffer space (3 row groups) for this component.
330 We make the buffer wide enough to allow the downsampler to edge-expand
331 horizontally within the buffer, if it so chooses. }
332 true_buffer := cinfo^.mem^.alloc_sarray
333 (j_common_ptr(cinfo), JPOOL_IMAGE,
334 JDIMENSION (( long(compptr^.width_in_blocks) * DCTSIZE *
335 cinfo^.max_h_samp_factor) div compptr^.h_samp_factor),
336 JDIMENSION (3 * rgroup_height));
337 { Copy true buffer row pointers into the middle of the fake row array }
338 MEMCOPY(JSAMPARRAY(@ fake_buffer^[rgroup_height]), true_buffer,
339 3 * rgroup_height * SIZEOF(JSAMPROW));
340 { Fill in the above and below wraparound pointers }
341 for i := 0 to pred(rgroup_height) do
342 begin
343 fake_buffer^[i] := true_buffer^[2 * rgroup_height + i];
344 fake_buffer^[4 * rgroup_height + i] := true_buffer^[i];
345 end;
346 prep^.color_buf[ci] := JSAMPARRAY(@ fake_buffer^[rgroup_height]);
347 Inc(JSAMPROW_PTR(fake_buffer), 5 * rgroup_height); { point to space for next component }
348 Inc(compptr);
349 end;
350 end;
352 {$endif} { CONTEXT_ROWS_SUPPORTED }
355 { Initialize preprocessing controller. }
357 {GLOBAL}
358 procedure jinit_c_prep_controller (cinfo : j_compress_ptr;
359 need_full_buffer : boolean);
360 var
361 prep : my_prep_ptr;
362 ci : int;
363 compptr : jpeg_component_info_ptr;
364 begin
366 if (need_full_buffer) then { safety check }
367 ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE);
369 prep := my_prep_ptr(
370 cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
371 SIZEOF(my_prep_controller)) );
372 cinfo^.prep := jpeg_c_prep_controller_ptr(prep);
373 prep^.pub.start_pass := start_pass_prep;
375 { Allocate the color conversion buffer.
376 We make the buffer wide enough to allow the downsampler to edge-expand
377 horizontally within the buffer, if it so chooses. }
379 if (cinfo^.downsample^.need_context_rows) then
380 begin
381 { Set up to provide context rows }
382 {$ifdef CONTEXT_ROWS_SUPPORTED}
383 prep^.pub.pre_process_data := pre_process_context;
384 create_context_buffer(cinfo);
385 {$else}
386 ERREXIT(j_common_ptr(cinfo), JERR_NOT_COMPILED);
387 {$endif}
388 end
389 else
390 begin
391 { No context, just make it tall enough for one row group }
392 prep^.pub.pre_process_data := pre_process_data;
393 compptr := jpeg_component_info_ptr(cinfo^.comp_info);
394 for ci := 0 to pred(cinfo^.num_components) do
395 begin
396 prep^.color_buf[ci] := cinfo^.mem^.alloc_sarray
397 (j_common_ptr(cinfo), JPOOL_IMAGE,
398 JDIMENSION (( long(compptr^.width_in_blocks) * DCTSIZE *
399 cinfo^.max_h_samp_factor) div compptr^.h_samp_factor),
400 JDIMENSION(cinfo^.max_v_samp_factor) );
401 Inc(compptr);
402 end;
403 end;
404 end;
406 end.