DEADSOFTWARE

hopefully no more windows
[d2df-editor.git] / src / lib / vampimg / JpegLib / imjquant1.pas
1 unit imjquant1;
3 { This file contains 1-pass color quantization (color mapping) routines.
4 These routines provide mapping to a fixed color map using equally spaced
5 color values. Optional Floyd-Steinberg or ordered dithering is available. }
7 { Original: jquant1.c; Copyright (C) 1991-1996, Thomas G. Lane. }
9 interface
11 {$I imjconfig.inc}
13 uses
14 imjpeglib;
16 {GLOBAL}
17 procedure jinit_1pass_quantizer (cinfo : j_decompress_ptr);
19 implementation
21 uses
22 imjmorecfg,
23 imjdeferr,
24 imjerror,
25 imjutils;
27 { The main purpose of 1-pass quantization is to provide a fast, if not very
28 high quality, colormapped output capability. A 2-pass quantizer usually
29 gives better visual quality; however, for quantized grayscale output this
30 quantizer is perfectly adequate. Dithering is highly recommended with this
31 quantizer, though you can turn it off if you really want to.
33 In 1-pass quantization the colormap must be chosen in advance of seeing the
34 image. We use a map consisting of all combinations of Ncolors[i] color
35 values for the i'th component. The Ncolors[] values are chosen so that
36 their product, the total number of colors, is no more than that requested.
37 (In most cases, the product will be somewhat less.)
39 Since the colormap is orthogonal, the representative value for each color
40 component can be determined without considering the other components;
41 then these indexes can be combined into a colormap index by a standard
42 N-dimensional-array-subscript calculation. Most of the arithmetic involved
43 can be precalculated and stored in the lookup table colorindex[].
44 colorindex[i][j] maps pixel value j in component i to the nearest
45 representative value (grid plane) for that component; this index is
46 multiplied by the array stride for component i, so that the
47 index of the colormap entry closest to a given pixel value is just
48 sum( colorindex[component-number][pixel-component-value] )
49 Aside from being fast, this scheme allows for variable spacing between
50 representative values with no additional lookup cost.
52 If gamma correction has been applied in color conversion, it might be wise
53 to adjust the color grid spacing so that the representative colors are
54 equidistant in linear space. At this writing, gamma correction is not
55 implemented by jdcolor, so nothing is done here. }
58 { Declarations for ordered dithering.
60 We use a standard 16x16 ordered dither array. The basic concept of ordered
61 dithering is described in many references, for instance Dale Schumacher's
62 chapter II.2 of Graphics Gems II (James Arvo, ed. Academic Press, 1991).
63 In place of Schumacher's comparisons against a "threshold" value, we add a
64 "dither" value to the input pixel and then round the result to the nearest
65 output value. The dither value is equivalent to (0.5 - threshold) times
66 the distance between output values. For ordered dithering, we assume that
67 the output colors are equally spaced; if not, results will probably be
68 worse, since the dither may be too much or too little at a given point.
70 The normal calculation would be to form pixel value + dither, range-limit
71 this to 0..MAXJSAMPLE, and then index into the colorindex table as usual.
72 We can skip the separate range-limiting step by extending the colorindex
73 table in both directions. }
76 const
77 ODITHER_SIZE = 16; { dimension of dither matrix }
78 { NB: if ODITHER_SIZE is not a power of 2, ODITHER_MASK uses will break }
79 ODITHER_CELLS = (ODITHER_SIZE*ODITHER_SIZE); { # cells in matrix }
80 ODITHER_MASK = (ODITHER_SIZE-1); { mask for wrapping around counters }
82 type
83 ODITHER_vector = Array[0..ODITHER_SIZE-1] of int;
84 ODITHER_MATRIX = Array[0..ODITHER_SIZE-1] of ODITHER_vector;
85 {ODITHER_MATRIX_PTR = ^array[0..ODITHER_SIZE-1] of int;}
86 ODITHER_MATRIX_PTR = ^ODITHER_MATRIX;
88 const
89 base_dither_matrix : Array[0..ODITHER_SIZE-1,0..ODITHER_SIZE-1] of UINT8
90 = (
91 { Bayer's order-4 dither array. Generated by the code given in
92 Stephen Hawley's article "Ordered Dithering" in Graphics Gems I.
93 The values in this array must range from 0 to ODITHER_CELLS-1. }
95 ( 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 ),
96 ( 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 ),
97 ( 32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 ),
98 ( 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95 ),
99 ( 8,200, 56,248, 4,196, 52,244, 11,203, 59,251, 7,199, 55,247 ),
100 ( 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119 ),
101 ( 40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215 ),
102 ( 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87 ),
103 ( 2,194, 50,242, 14,206, 62,254, 1,193, 49,241, 13,205, 61,253 ),
104 ( 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125 ),
105 ( 34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221 ),
106 ( 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93 ),
107 ( 10,202, 58,250, 6,198, 54,246, 9,201, 57,249, 5,197, 53,245 ),
108 ( 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117 ),
109 ( 42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213 ),
110 ( 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85 )
111 );
114 { Declarations for Floyd-Steinberg dithering.
116 Errors are accumulated into the array fserrors[], at a resolution of
117 1/16th of a pixel count. The error at a given pixel is propagated
118 to its not-yet-processed neighbors using the standard F-S fractions,
119 ... (here) 7/16
120 3/16 5/16 1/16
121 We work left-to-right on even rows, right-to-left on odd rows.
123 We can get away with a single array (holding one row's worth of errors)
124 by using it to store the current row's errors at pixel columns not yet
125 processed, but the next row's errors at columns already processed. We
126 need only a few extra variables to hold the errors immediately around the
127 current column. (If we are lucky, those variables are in registers, but
128 even if not, they're probably cheaper to access than array elements are.)
130 The fserrors[] array is indexed [component#][position].
131 We provide (#columns + 2) entries per component; the extra entry at each
132 end saves us from special-casing the first and last pixels.
134 Note: on a wide image, we might not have enough room in a PC's near data
135 segment to hold the error array; so it is allocated with alloc_large. }
137 {$ifdef BITS_IN_JSAMPLE_IS_8}
138 type
139 FSERROR = INT16; { 16 bits should be enough }
140 LOCFSERROR = int; { use 'int' for calculation temps }
141 {$else}
142 type
143 FSERROR = INT32; { may need more than 16 bits }
144 LOCFSERROR = INT32; { be sure calculation temps are big enough }
145 {$endif}
147 type
148 jFSError = 0..(MaxInt div SIZEOF(FSERROR))-1;
149 FS_ERROR_FIELD = array[jFSError] of FSERROR;
150 FS_ERROR_FIELD_PTR = ^FS_ERROR_FIELD;{far}
151 { pointer to error array (in FAR storage!) }
152 FSERRORPTR = ^FSERROR;
155 { Private subobject }
157 const
158 MAX_Q_COMPS = 4; { max components I can handle }
160 type
161 my_cquantize_ptr = ^my_cquantizer;
162 my_cquantizer = record
163 pub : jpeg_color_quantizer; { public fields }
165 { Initially allocated colormap is saved here }
166 sv_colormap : JSAMPARRAY; { The color map as a 2-D pixel array }
167 sv_actual : int; { number of entries in use }
169 colorindex : JSAMPARRAY; { Precomputed mapping for speed }
170 { colorindex[i][j] = index of color closest to pixel value j in component i,
171 premultiplied as described above. Since colormap indexes must fit into
172 JSAMPLEs, the entries of this array will too. }
174 is_padded : boolean; { is the colorindex padded for odither? }
176 Ncolors : array[0..MAX_Q_COMPS-1] of int;
177 { # of values alloced to each component }
179 { Variables for ordered dithering }
180 row_index : int; { cur row's vertical index in dither matrix }
181 odither : array[0..MAX_Q_COMPS-1] of ODITHER_MATRIX_PTR;
182 { one dither array per component }
183 { Variables for Floyd-Steinberg dithering }
184 fserrors : array[0..MAX_Q_COMPS-1] of FS_ERROR_FIELD_PTR;
185 { accumulated errors }
186 on_odd_row : boolean; { flag to remember which row we are on }
187 end;
190 { Policy-making subroutines for create_colormap and create_colorindex.
191 These routines determine the colormap to be used. The rest of the module
192 only assumes that the colormap is orthogonal.
194 * select_ncolors decides how to divvy up the available colors
195 among the components.
196 * output_value defines the set of representative values for a component.
197 * largest_input_value defines the mapping from input values to
198 representative values for a component.
199 Note that the latter two routines may impose different policies for
200 different components, though this is not currently done. }
204 {LOCAL}
205 function select_ncolors (cinfo : j_decompress_ptr;
206 var Ncolors : array of int) : int;
207 { Determine allocation of desired colors to components, }
208 { and fill in Ncolors[] array to indicate choice. }
209 { Return value is total number of colors (product of Ncolors[] values). }
210 var
211 nc : int;
212 max_colors : int;
213 total_colors, iroot, i, j : int;
214 changed : boolean;
215 temp : long;
216 const
217 RGB_order:array[0..2] of int = (RGB_GREEN, RGB_RED, RGB_BLUE);
218 begin
219 nc := cinfo^.out_color_components; { number of color components }
220 max_colors := cinfo^.desired_number_of_colors;
222 { We can allocate at least the nc'th root of max_colors per component. }
223 { Compute floor(nc'th root of max_colors). }
224 iroot := 1;
225 repeat
226 Inc(iroot);
227 temp := iroot; { set temp = iroot ** nc }
228 for i := 1 to pred(nc) do
229 temp := temp * iroot;
230 until (temp > long(max_colors)); { repeat till iroot exceeds root }
231 Dec(iroot); { now iroot = floor(root) }
233 { Must have at least 2 color values per component }
234 if (iroot < 2) then
235 ERREXIT1(j_common_ptr(cinfo), JERR_QUANT_FEW_COLORS, int(temp));
237 { Initialize to iroot color values for each component }
238 total_colors := 1;
239 for i := 0 to pred(nc) do
240 begin
241 Ncolors[i] := iroot;
242 total_colors := total_colors * iroot;
243 end;
245 { We may be able to increment the count for one or more components without
246 exceeding max_colors, though we know not all can be incremented.
247 Sometimes, the first component can be incremented more than once!
248 (Example: for 16 colors, we start at 2*2*2, go to 3*2*2, then 4*2*2.)
249 In RGB colorspace, try to increment G first, then R, then B. }
251 repeat
252 changed := FALSE;
253 for i := 0 to pred(nc) do
254 begin
255 if cinfo^.out_color_space = JCS_RGB then
256 j := RGB_order[i]
257 else
258 j := i;
259 { calculate new total_colors if Ncolors[j] is incremented }
260 temp := total_colors div Ncolors[j];
261 temp := temp * (Ncolors[j]+1); { done in long arith to avoid oflo }
262 if (temp > long(max_colors)) then
263 break; { won't fit, done with this pass }
264 Inc(Ncolors[j]); { OK, apply the increment }
265 total_colors := int(temp);
266 changed := TRUE;
267 end;
268 until not changed;
270 select_ncolors := total_colors;
271 end;
274 {LOCAL}
275 function output_value (cinfo : j_decompress_ptr;
276 ci : int; j : int; maxj : int) : int;
277 { Return j'th output value, where j will range from 0 to maxj }
278 { The output values must fall in 0..MAXJSAMPLE in increasing order }
279 begin
280 { We always provide values 0 and MAXJSAMPLE for each component;
281 any additional values are equally spaced between these limits.
282 (Forcing the upper and lower values to the limits ensures that
283 dithering can't produce a color outside the selected gamut.) }
285 output_value := int (( INT32(j) * MAXJSAMPLE + maxj div 2) div maxj);
286 end;
289 {LOCAL}
290 function largest_input_value (cinfo : j_decompress_ptr;
291 ci : int; j : int; maxj : int) : int;
292 { Return largest input value that should map to j'th output value }
293 { Must have largest(j=0) >= 0, and largest(j=maxj) >= MAXJSAMPLE }
294 begin
295 { Breakpoints are halfway between values returned by output_value }
296 largest_input_value := int (( INT32(2*j + 1) * MAXJSAMPLE +
297 maxj) div (2*maxj));
298 end;
301 { Create the colormap. }
303 {LOCAL}
304 procedure create_colormap (cinfo : j_decompress_ptr);
305 var
306 cquantize : my_cquantize_ptr;
307 colormap : JSAMPARRAY; { Created colormap }
309 total_colors : int; { Number of distinct output colors }
310 i,j,k, nci, blksize, blkdist, ptr, val : int;
311 begin
312 cquantize := my_cquantize_ptr (cinfo^.cquantize);
314 { Select number of colors for each component }
315 total_colors := select_ncolors(cinfo, cquantize^.Ncolors);
317 { Report selected color counts }
318 {$IFDEF DEBUG}
319 if (cinfo^.out_color_components = 3) then
320 TRACEMS4(j_common_ptr(cinfo), 1, JTRC_QUANT_3_NCOLORS,
321 total_colors, cquantize^.Ncolors[0],
322 cquantize^.Ncolors[1], cquantize^.Ncolors[2])
323 else
324 TRACEMS1(j_common_ptr(cinfo), 1, JTRC_QUANT_NCOLORS, total_colors);
325 {$ENDIF}
327 { Allocate and fill in the colormap. }
328 { The colors are ordered in the map in standard row-major order, }
329 { i.e. rightmost (highest-indexed) color changes most rapidly. }
331 colormap := cinfo^.mem^.alloc_sarray(
332 j_common_ptr(cinfo), JPOOL_IMAGE,
333 JDIMENSION(total_colors), JDIMENSION(cinfo^.out_color_components));
335 { blksize is number of adjacent repeated entries for a component }
336 { blkdist is distance between groups of identical entries for a component }
337 blkdist := total_colors;
339 for i := 0 to pred(cinfo^.out_color_components) do
340 begin
341 { fill in colormap entries for i'th color component }
342 nci := cquantize^.Ncolors[i]; { # of distinct values for this color }
343 blksize := blkdist div nci;
344 for j := 0 to pred(nci) do
345 begin
346 { Compute j'th output value (out of nci) for component }
347 val := output_value(cinfo, i, j, nci-1);
348 { Fill in all colormap entries that have this value of this component }
349 ptr := j * blksize;
350 while (ptr < total_colors) do
351 begin
352 { fill in blksize entries beginning at ptr }
353 for k := 0 to pred(blksize) do
354 colormap^[i]^[ptr+k] := JSAMPLE(val);
356 Inc(ptr, blkdist);
357 end;
358 end;
359 blkdist := blksize; { blksize of this color is blkdist of next }
360 end;
362 { Save the colormap in private storage,
363 where it will survive color quantization mode changes. }
365 cquantize^.sv_colormap := colormap;
366 cquantize^.sv_actual := total_colors;
367 end;
369 { Create the color index table. }
371 {LOCAL}
372 procedure create_colorindex (cinfo : j_decompress_ptr);
373 var
374 cquantize : my_cquantize_ptr;
375 indexptr,
376 help_indexptr : JSAMPROW; { for negative offsets }
377 i,j,k, nci, blksize, val, pad : int;
378 begin
379 cquantize := my_cquantize_ptr (cinfo^.cquantize);
380 { For ordered dither, we pad the color index tables by MAXJSAMPLE in
381 each direction (input index values can be -MAXJSAMPLE .. 2*MAXJSAMPLE).
382 This is not necessary in the other dithering modes. However, we
383 flag whether it was done in case user changes dithering mode. }
385 if (cinfo^.dither_mode = JDITHER_ORDERED) then
386 begin
387 pad := MAXJSAMPLE*2;
388 cquantize^.is_padded := TRUE;
389 end
390 else
391 begin
392 pad := 0;
393 cquantize^.is_padded := FALSE;
394 end;
396 cquantize^.colorindex := cinfo^.mem^.alloc_sarray
397 (j_common_ptr(cinfo), JPOOL_IMAGE,
398 JDIMENSION(MAXJSAMPLE+1 + pad),
399 JDIMENSION(cinfo^.out_color_components));
401 { blksize is number of adjacent repeated entries for a component }
402 blksize := cquantize^.sv_actual;
404 for i := 0 to pred(cinfo^.out_color_components) do
405 begin
406 { fill in colorindex entries for i'th color component }
407 nci := cquantize^.Ncolors[i]; { # of distinct values for this color }
408 blksize := blksize div nci;
410 { adjust colorindex pointers to provide padding at negative indexes. }
411 if (pad <> 0) then
412 Inc(JSAMPLE_PTR(cquantize^.colorindex^[i]), MAXJSAMPLE);
414 { in loop, val = index of current output value, }
415 { and k = largest j that maps to current val }
416 indexptr := cquantize^.colorindex^[i];
417 val := 0;
418 k := largest_input_value(cinfo, i, 0, nci-1);
419 for j := 0 to MAXJSAMPLE do
420 begin
421 while (j > k) do { advance val if past boundary }
422 begin
423 Inc(val);
424 k := largest_input_value(cinfo, i, val, nci-1);
425 end;
426 { premultiply so that no multiplication needed in main processing }
427 indexptr^[j] := JSAMPLE (val * blksize);
428 end;
429 { Pad at both ends if necessary }
430 if (pad <> 0) then
431 begin
432 help_indexptr := indexptr;
433 { adjust the help pointer to avoid negative offsets }
434 Dec(JSAMPLE_PTR(help_indexptr), MAXJSAMPLE);
436 for j := 1 to MAXJSAMPLE do
437 begin
438 {indexptr^[-j] := indexptr^[0];}
439 help_indexptr^[MAXJSAMPLE-j] := indexptr^[0];
440 indexptr^[MAXJSAMPLE+j] := indexptr^[MAXJSAMPLE];
441 end;
442 end;
443 end;
444 end;
447 { Create an ordered-dither array for a component having ncolors
448 distinct output values. }
450 {LOCAL}
451 function make_odither_array (cinfo : j_decompress_ptr;
452 ncolors : int) : ODITHER_MATRIX_PTR;
453 var
454 odither : ODITHER_MATRIX_PTR;
455 j, k : int;
456 num, den : INT32;
457 begin
458 odither := ODITHER_MATRIX_PTR (
459 cinfo^.mem^.alloc_small(j_common_ptr(cinfo), JPOOL_IMAGE,
460 SIZEOF(ODITHER_MATRIX)));
461 { The inter-value distance for this color is MAXJSAMPLE/(ncolors-1).
462 Hence the dither value for the matrix cell with fill order f
463 (f=0..N-1) should be (N-1-2*f)/(2*N) * MAXJSAMPLE/(ncolors-1).
464 On 16-bit-int machine, be careful to avoid overflow. }
466 den := 2 * ODITHER_CELLS * ( INT32(ncolors - 1));
467 for j := 0 to pred(ODITHER_SIZE) do
468 begin
469 for k := 0 to pred(ODITHER_SIZE) do
470 begin
471 num := ( INT32(ODITHER_CELLS-1 - 2*( int(base_dither_matrix[j][k]))))
472 * MAXJSAMPLE;
473 { Ensure round towards zero despite C's lack of consistency
474 about rounding negative values in integer division... }
476 if num<0 then
477 odither^[j][k] := int (-((-num) div den))
478 else
479 odither^[j][k] := int (num div den);
480 end;
481 end;
482 make_odither_array := odither;
483 end;
486 { Create the ordered-dither tables.
487 Components having the same number of representative colors may
488 share a dither table. }
490 {LOCAL}
491 procedure create_odither_tables (cinfo : j_decompress_ptr);
492 var
493 cquantize : my_cquantize_ptr;
494 odither : ODITHER_MATRIX_PTR;
495 i, j, nci : int;
496 begin
497 cquantize := my_cquantize_ptr (cinfo^.cquantize);
499 for i := 0 to pred(cinfo^.out_color_components) do
500 begin
501 nci := cquantize^.Ncolors[i]; { # of distinct values for this color }
502 odither := NIL; { search for matching prior component }
503 for j := 0 to pred(i) do
504 begin
505 if (nci = cquantize^.Ncolors[j]) then
506 begin
507 odither := cquantize^.odither[j];
508 break;
509 end;
510 end;
511 if (odither = NIL) then { need a new table? }
512 odither := make_odither_array(cinfo, nci);
513 cquantize^.odither[i] := odither;
514 end;
515 end;
518 { Map some rows of pixels to the output colormapped representation. }
520 {METHODDEF}
521 procedure color_quantize (cinfo : j_decompress_ptr;
522 input_buf : JSAMPARRAY;
523 output_buf : JSAMPARRAY;
524 num_rows : int);
525 { General case, no dithering }
526 var
527 cquantize : my_cquantize_ptr;
528 colorindex : JSAMPARRAY;
529 pixcode, ci : int; {register}
530 ptrin, ptrout : JSAMPLE_PTR; {register}
531 row : int;
532 col : JDIMENSION;
533 width : JDIMENSION;
534 nc : int; {register}
535 begin
536 cquantize := my_cquantize_ptr (cinfo^.cquantize);
537 colorindex := cquantize^.colorindex;
538 width := cinfo^.output_width;
539 nc := cinfo^.out_color_components;
541 for row := 0 to pred(num_rows) do
542 begin
543 ptrin := JSAMPLE_PTR(input_buf^[row]);
544 ptrout := JSAMPLE_PTR(output_buf^[row]);
545 for col := pred(width) downto 0 do
546 begin
547 pixcode := 0;
548 for ci := 0 to pred(nc) do
549 begin
550 Inc(pixcode, GETJSAMPLE(colorindex^[ci]^[GETJSAMPLE(ptrin^)]) );
551 Inc(ptrin);
552 end;
553 ptrout^ := JSAMPLE (pixcode);
554 Inc(ptrout);
555 end;
556 end;
557 end;
560 {METHODDEF}
561 procedure color_quantize3 (cinfo : j_decompress_ptr;
562 input_buf : JSAMPARRAY;
563 output_buf : JSAMPARRAY;
564 num_rows : int);
565 { Fast path for out_color_components=3, no dithering }
566 var
567 cquantize : my_cquantize_ptr;
568 pixcode : int; {register}
569 ptrin, ptrout : JSAMPLE_PTR; {register}
570 colorindex0 : JSAMPROW;
571 colorindex1 : JSAMPROW;
572 colorindex2 : JSAMPROW;
573 row : int;
574 col : JDIMENSION;
575 width : JDIMENSION;
576 begin
577 cquantize := my_cquantize_ptr (cinfo^.cquantize);
578 colorindex0 := (cquantize^.colorindex)^[0];
579 colorindex1 := (cquantize^.colorindex)^[1];
580 colorindex2 := (cquantize^.colorindex)^[2];
581 width := cinfo^.output_width;
583 for row := 0 to pred(num_rows) do
584 begin
585 ptrin := JSAMPLE_PTR(input_buf^[row]);
586 ptrout := JSAMPLE_PTR(output_buf^[row]);
587 for col := pred(width) downto 0 do
588 begin
589 pixcode := GETJSAMPLE((colorindex0)^[GETJSAMPLE(ptrin^)]);
590 Inc(ptrin);
591 Inc( pixcode, GETJSAMPLE((colorindex1)^[GETJSAMPLE(ptrin^)]) );
592 Inc(ptrin);
593 Inc( pixcode, GETJSAMPLE((colorindex2)^[GETJSAMPLE(ptrin^)]) );
594 Inc(ptrin);
595 ptrout^ := JSAMPLE (pixcode);
596 Inc(ptrout);
597 end;
598 end;
599 end;
602 {METHODDEF}
603 procedure quantize_ord_dither (cinfo : j_decompress_ptr;
604 input_buf : JSAMPARRAY;
605 output_buf : JSAMPARRAY;
606 num_rows : int);
607 { General case, with ordered dithering }
608 var
609 cquantize : my_cquantize_ptr;
610 input_ptr, {register}
611 output_ptr : JSAMPLE_PTR; {register}
612 colorindex_ci : JSAMPROW;
613 dither : ^ODITHER_vector; { points to active row of dither matrix }
614 row_index, col_index : int; { current indexes into dither matrix }
615 nc : int;
616 ci : int;
617 row : int;
618 col : JDIMENSION;
619 width : JDIMENSION;
620 var
621 pad_offset : int;
622 begin
623 cquantize := my_cquantize_ptr (cinfo^.cquantize);
624 nc := cinfo^.out_color_components;
625 width := cinfo^.output_width;
627 { Nomssi: work around negative offset }
628 if my_cquantize_ptr (cinfo^.cquantize)^.is_padded then
629 pad_offset := MAXJSAMPLE
630 else
631 pad_offset := 0;
633 for row := 0 to pred(num_rows) do
634 begin
635 { Initialize output values to 0 so can process components separately }
636 jzero_far( {far} pointer(output_buf^[row]),
637 size_t(width * SIZEOF(JSAMPLE)));
638 row_index := cquantize^.row_index;
639 for ci := 0 to pred(nc) do
640 begin
641 input_ptr := JSAMPLE_PTR(@ input_buf^[row]^[ci]);
642 output_ptr := JSAMPLE_PTR(output_buf^[row]);
643 colorindex_ci := cquantize^.colorindex^[ci];
644 { Nomssi }
645 Dec(JSAMPLE_PTR(colorindex_ci), pad_offset);
647 dither := @(cquantize^.odither[ci]^[row_index]);
648 col_index := 0;
650 for col := pred(width) downto 0 do
651 begin
652 { Form pixel value + dither, range-limit to 0..MAXJSAMPLE,
653 select output value, accumulate into output code for this pixel.
654 Range-limiting need not be done explicitly, as we have extended
655 the colorindex table to produce the right answers for out-of-range
656 inputs. The maximum dither is +- MAXJSAMPLE; this sets the
657 required amount of padding. }
659 Inc(output_ptr^,
660 colorindex_ci^[GETJSAMPLE(input_ptr^)+ pad_offset +
661 dither^[col_index]]);
662 Inc(output_ptr);
663 Inc(input_ptr, nc);
664 col_index := (col_index + 1) and ODITHER_MASK;
665 end;
666 end;
667 { Advance row index for next row }
668 row_index := (row_index + 1) and ODITHER_MASK;
669 cquantize^.row_index := row_index;
670 end;
671 end;
673 {METHODDEF}
674 procedure quantize3_ord_dither (cinfo : j_decompress_ptr;
675 input_buf : JSAMPARRAY;
676 output_buf : JSAMPARRAY;
677 num_rows : int);
678 { Fast path for out_color_components=3, with ordered dithering }
679 var
680 cquantize : my_cquantize_ptr;
681 pixcode : int; {register}
682 input_ptr : JSAMPLE_PTR; {register}
683 output_ptr : JSAMPLE_PTR; {register}
684 colorindex0 : JSAMPROW;
685 colorindex1 : JSAMPROW;
686 colorindex2 : JSAMPROW;
687 dither0 : ^ODITHER_vector; { points to active row of dither matrix }
688 dither1 : ^ODITHER_vector;
689 dither2 : ^ODITHER_vector;
690 row_index, col_index : int; { current indexes into dither matrix }
691 row : int;
692 col : JDIMENSION;
693 width : JDIMENSION;
694 var
695 pad_offset : int;
696 begin
697 cquantize := my_cquantize_ptr (cinfo^.cquantize);
698 colorindex0 := (cquantize^.colorindex)^[0];
699 colorindex1 := (cquantize^.colorindex)^[1];
700 colorindex2 := (cquantize^.colorindex)^[2];
701 width := cinfo^.output_width;
703 { Nomssi: work around negative offset }
704 if my_cquantize_ptr (cinfo^.cquantize)^.is_padded then
705 pad_offset := MAXJSAMPLE
706 else
707 pad_offset := 0;
709 Dec(JSAMPLE_PTR(colorindex0), pad_offset);
710 Dec(JSAMPLE_PTR(colorindex1), pad_offset);
711 Dec(JSAMPLE_PTR(colorindex2), pad_offset);
713 for row := 0 to pred(num_rows) do
714 begin
715 row_index := cquantize^.row_index;
716 input_ptr := JSAMPLE_PTR(input_buf^[row]);
717 output_ptr := JSAMPLE_PTR(output_buf^[row]);
718 dither0 := @(cquantize^.odither[0]^[row_index]);
719 dither1 := @(cquantize^.odither[1]^[row_index]);
720 dither2 := @(cquantize^.odither[2]^[row_index]);
721 col_index := 0;
724 for col := pred(width) downto 0 do
725 begin
726 pixcode := GETJSAMPLE(colorindex0^[GETJSAMPLE(input_ptr^) + pad_offset
727 + dither0^[col_index]]);
728 Inc(input_ptr);
729 Inc(pixcode, GETJSAMPLE(colorindex1^[GETJSAMPLE(input_ptr^) + pad_offset
730 + dither1^[col_index]]));
731 Inc(input_ptr);
732 Inc(pixcode, GETJSAMPLE(colorindex2^[GETJSAMPLE(input_ptr^) + pad_offset
733 + dither2^[col_index]]));
734 Inc(input_ptr);
735 output_ptr^ := JSAMPLE (pixcode);
736 Inc(output_ptr);
737 col_index := (col_index + 1) and ODITHER_MASK;
738 end;
739 row_index := (row_index + 1) and ODITHER_MASK;
740 cquantize^.row_index := row_index;
741 end;
742 end;
745 {METHODDEF}
746 procedure quantize_fs_dither (cinfo : j_decompress_ptr;
747 input_buf : JSAMPARRAY;
748 output_buf : JSAMPARRAY;
749 num_rows : int);
750 { General case, with Floyd-Steinberg dithering }
751 var
752 cquantize : my_cquantize_ptr;
753 cur : LOCFSERROR; {register} { current error or pixel value }
754 belowerr : LOCFSERROR; { error for pixel below cur }
755 bpreverr : LOCFSERROR; { error for below/prev col }
756 bnexterr : LOCFSERROR; { error for below/next col }
757 delta : LOCFSERROR;
758 prev_errorptr,
759 errorptr : FSERRORPTR; {register} { => fserrors[] at column before current }
760 input_ptr, {register}
761 output_ptr : JSAMPLE_PTR; {register}
762 colorindex_ci : JSAMPROW;
763 colormap_ci : JSAMPROW;
764 pixcode : int;
765 nc : int;
766 dir : int; { 1 for left-to-right, -1 for right-to-left }
767 dirnc : int; { dir * nc }
768 ci : int;
769 row : int;
770 col : JDIMENSION;
771 width : JDIMENSION;
772 range_limit : range_limit_table_ptr;
773 begin
774 cquantize := my_cquantize_ptr (cinfo^.cquantize);
775 nc := cinfo^.out_color_components;
776 width := cinfo^.output_width;
777 range_limit := cinfo^.sample_range_limit;
779 for row := 0 to pred(num_rows) do
780 begin
781 { Initialize output values to 0 so can process components separately }
782 jzero_far( (output_buf)^[row],
783 size_t(width * SIZEOF(JSAMPLE)));
784 for ci := 0 to pred(nc) do
785 begin
786 input_ptr := JSAMPLE_PTR(@ input_buf^[row]^[ci]);
787 output_ptr := JSAMPLE_PTR(output_buf^[row]);
788 errorptr := FSERRORPTR(cquantize^.fserrors[ci]); { => entry before first column }
789 if (cquantize^.on_odd_row) then
790 begin
791 { work right to left in this row }
792 Inc(input_ptr, (width-1) * JDIMENSION(nc)); { so point to rightmost pixel }
793 Inc(output_ptr, width-1);
794 dir := -1;
795 dirnc := -nc;
796 Inc(errorptr, (width+1)); { => entry after last column }
797 end
798 else
799 begin
800 { work left to right in this row }
801 dir := 1;
802 dirnc := nc;
803 {errorptr := cquantize^.fserrors[ci];}
804 end;
806 colorindex_ci := cquantize^.colorindex^[ci];
808 colormap_ci := (cquantize^.sv_colormap)^[ci];
809 { Preset error values: no error propagated to first pixel from left }
810 cur := 0;
811 { and no error propagated to row below yet }
812 belowerr := 0;
813 bpreverr := 0;
815 for col := pred(width) downto 0 do
816 begin
817 prev_errorptr := errorptr;
818 Inc(errorptr, dir); { advance errorptr to current column }
820 { cur holds the error propagated from the previous pixel on the
821 current line. Add the error propagated from the previous line
822 to form the complete error correction term for this pixel, and
823 round the error term (which is expressed * 16) to an integer.
824 RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct
825 for either sign of the error value.
826 Note: errorptr points to *previous* column's array entry. }
828 cur := (cur + errorptr^ + 8) div 16;
830 { Form pixel value + error, and range-limit to 0..MAXJSAMPLE.
831 The maximum error is +- MAXJSAMPLE; this sets the required size
832 of the range_limit array. }
834 Inc( cur, GETJSAMPLE(input_ptr^));
835 cur := GETJSAMPLE(range_limit^[cur]);
836 { Select output value, accumulate into output code for this pixel }
837 pixcode := GETJSAMPLE(colorindex_ci^[cur]);
838 Inc(output_ptr^, JSAMPLE (pixcode));
839 { Compute actual representation error at this pixel }
840 { Note: we can do this even though we don't have the final }
841 { pixel code, because the colormap is orthogonal. }
842 Dec(cur, GETJSAMPLE(colormap_ci^[pixcode]));
843 { Compute error fractions to be propagated to adjacent pixels.
844 Add these into the running sums, and simultaneously shift the
845 next-line error sums left by 1 column. }
847 bnexterr := cur;
848 delta := cur * 2;
849 Inc(cur, delta); { form error * 3 }
850 prev_errorptr^ := FSERROR (bpreverr + cur);
851 Inc(cur, delta); { form error * 5 }
852 bpreverr := belowerr + cur;
853 belowerr := bnexterr;
854 Inc(cur, delta); { form error * 7 }
855 { At this point cur contains the 7/16 error value to be propagated
856 to the next pixel on the current line, and all the errors for the
857 next line have been shifted over. We are therefore ready to move on. }
859 Inc(input_ptr, dirnc); { advance input ptr to next column }
860 Inc(output_ptr, dir); { advance output ptr to next column }
862 end;
863 { Post-loop cleanup: we must unload the final error value into the
864 final fserrors[] entry. Note we need not unload belowerr because
865 it is for the dummy column before or after the actual array. }
867 errorptr^ := FSERROR (bpreverr); { unload prev err into array }
868 { Nomssi : ?? }
869 end;
870 cquantize^.on_odd_row := not cquantize^.on_odd_row;
871 end;
872 end;
875 { Allocate workspace for Floyd-Steinberg errors. }
877 {LOCAL}
878 procedure alloc_fs_workspace (cinfo : j_decompress_ptr);
879 var
880 cquantize : my_cquantize_ptr;
881 arraysize : size_t;
882 i : int;
883 begin
884 cquantize := my_cquantize_ptr (cinfo^.cquantize);
885 arraysize := size_t ((cinfo^.output_width + 2) * SIZEOF(FSERROR));
886 for i := 0 to pred(cinfo^.out_color_components) do
887 begin
888 cquantize^.fserrors[i] := FS_ERROR_FIELD_PTR(
889 cinfo^.mem^.alloc_large(j_common_ptr(cinfo), JPOOL_IMAGE, arraysize));
890 end;
891 end;
894 { Initialize for one-pass color quantization. }
896 {METHODDEF}
897 procedure start_pass_1_quant (cinfo : j_decompress_ptr;
898 is_pre_scan : boolean);
899 var
900 cquantize : my_cquantize_ptr;
901 arraysize : size_t;
902 i : int;
903 begin
904 cquantize := my_cquantize_ptr (cinfo^.cquantize);
905 { Install my colormap. }
906 cinfo^.colormap := cquantize^.sv_colormap;
907 cinfo^.actual_number_of_colors := cquantize^.sv_actual;
909 { Initialize for desired dithering mode. }
910 case (cinfo^.dither_mode) of
911 JDITHER_NONE:
912 if (cinfo^.out_color_components = 3) then
913 cquantize^.pub.color_quantize := color_quantize3
914 else
915 cquantize^.pub.color_quantize := color_quantize;
916 JDITHER_ORDERED:
917 begin
918 if (cinfo^.out_color_components = 3) then
919 cquantize^.pub.color_quantize := quantize3_ord_dither
920 else
921 cquantize^.pub.color_quantize := quantize_ord_dither;
922 cquantize^.row_index := 0; { initialize state for ordered dither }
923 { If user changed to ordered dither from another mode,
924 we must recreate the color index table with padding.
925 This will cost extra space, but probably isn't very likely. }
927 if (not cquantize^.is_padded) then
928 create_colorindex(cinfo);
929 { Create ordered-dither tables if we didn't already. }
930 if (cquantize^.odither[0] = NIL) then
931 create_odither_tables(cinfo);
932 end;
933 JDITHER_FS:
934 begin
935 cquantize^.pub.color_quantize := quantize_fs_dither;
936 cquantize^.on_odd_row := FALSE; { initialize state for F-S dither }
937 { Allocate Floyd-Steinberg workspace if didn't already. }
938 if (cquantize^.fserrors[0] = NIL) then
939 alloc_fs_workspace(cinfo);
940 { Initialize the propagated errors to zero. }
941 arraysize := size_t ((cinfo^.output_width + 2) * SIZEOF(FSERROR));
942 for i := 0 to pred(cinfo^.out_color_components) do
943 jzero_far({far} pointer( cquantize^.fserrors[i] ), arraysize);
944 end;
945 else
946 ERREXIT(j_common_ptr(cinfo), JERR_NOT_COMPILED);
947 end;
948 end;
951 { Finish up at the end of the pass. }
953 {METHODDEF}
954 procedure finish_pass_1_quant (cinfo : j_decompress_ptr);
955 begin
956 { no work in 1-pass case }
957 end;
960 { Switch to a new external colormap between output passes.
961 Shouldn't get to this module! }
963 {METHODDEF}
964 procedure new_color_map_1_quant (cinfo : j_decompress_ptr);
965 begin
966 ERREXIT(j_common_ptr(cinfo), JERR_MODE_CHANGE);
967 end;
970 { Module initialization routine for 1-pass color quantization. }
972 {GLOBAL}
973 procedure jinit_1pass_quantizer (cinfo : j_decompress_ptr);
974 var
975 cquantize : my_cquantize_ptr;
976 begin
977 cquantize := my_cquantize_ptr(
978 cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
979 SIZEOF(my_cquantizer)));
980 cinfo^.cquantize := jpeg_color_quantizer_ptr(cquantize);
981 cquantize^.pub.start_pass := start_pass_1_quant;
982 cquantize^.pub.finish_pass := finish_pass_1_quant;
983 cquantize^.pub.new_color_map := new_color_map_1_quant;
984 cquantize^.fserrors[0] := NIL; { Flag FS workspace not allocated }
985 cquantize^.odither[0] := NIL; { Also flag odither arrays not allocated }
987 { Make sure my internal arrays won't overflow }
988 if (cinfo^.out_color_components > MAX_Q_COMPS) then
989 ERREXIT1(j_common_ptr(cinfo), JERR_QUANT_COMPONENTS, MAX_Q_COMPS);
990 { Make sure colormap indexes can be represented by JSAMPLEs }
991 if (cinfo^.desired_number_of_colors > (MAXJSAMPLE+1)) then
992 ERREXIT1(j_common_ptr(cinfo), JERR_QUANT_MANY_COLORS, MAXJSAMPLE+1);
994 { Create the colormap and color index table. }
995 create_colormap(cinfo);
996 create_colorindex(cinfo);
998 { Allocate Floyd-Steinberg workspace now if requested.
999 We do this now since it is FAR storage and may affect the memory
1000 manager's space calculations. If the user changes to FS dither
1001 mode in a later pass, we will allocate the space then, and will
1002 possibly overrun the max_memory_to_use setting. }
1004 if (cinfo^.dither_mode = JDITHER_FS) then
1005 alloc_fs_workspace(cinfo);
1006 end;
1009 end.