DEADSOFTWARE

hopefully no more windows
[d2df-editor.git] / src / lib / vampimg / JpegLib / imjccolor.pas
1 unit imjccolor;
3 { This file contains input colorspace conversion routines. }
5 { Original : jccolor.c ; Copyright (C) 1991-1996, Thomas G. Lane. }
7 interface
9 {$I imjconfig.inc}
11 uses
12 imjmorecfg,
13 imjinclude,
14 imjdeferr,
15 imjerror,
16 imjpeglib;
18 { Module initialization routine for input colorspace conversion. }
20 {GLOBAL}
21 procedure jinit_color_converter (cinfo : j_compress_ptr);
23 implementation
25 { Private subobject }
26 type
27 INT32_FIELD = array[0..MaxInt div SizeOf(INT32) - 1] of INT32;
28 INT32_FIELD_PTR = ^INT32_FIELD;
30 type
31 my_cconvert_ptr = ^my_color_converter;
32 my_color_converter = record
33 pub : jpeg_color_converter; { public fields }
35 { Private state for RGB -> YCC conversion }
36 rgb_ycc_tab : INT32_FIELD_PTR; { => table for RGB to YCbCr conversion }
37 end; {my_color_converter;}
40 {*************** RGB -> YCbCr conversion: most common case *************}
42 {
43 YCbCr is defined per CCIR 601-1, except that Cb and Cr are
44 normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5.
45 The conversion equations to be implemented are therefore
46 Y = 0.29900 * R + 0.58700 * G + 0.11400 * B
47 Cb = -0.16874 * R - 0.33126 * G + 0.50000 * B + CENTERJSAMPLE
48 Cr = 0.50000 * R - 0.41869 * G - 0.08131 * B + CENTERJSAMPLE
49 (These numbers are derived from TIFF 6.0 section 21, dated 3-June-92.)
50 Note: older versions of the IJG code used a zero offset of MAXJSAMPLE/2,
51 rather than CENTERJSAMPLE, for Cb and Cr. This gave equal positive and
52 negative swings for Cb/Cr, but meant that grayscale values (Cb=Cr=0)
53 were not represented exactly. Now we sacrifice exact representation of
54 maximum red and maximum blue in order to get exact grayscales.
56 To avoid floating-point arithmetic, we represent the fractional constants
57 as integers scaled up by 2^16 (about 4 digits precision); we have to divide
58 the products by 2^16, with appropriate rounding, to get the correct answer.
60 For even more speed, we avoid doing any multiplications in the inner loop
61 by precalculating the constants times R,G,B for all possible values.
62 For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table);
63 for 12-bit samples it is still acceptable. It's not very reasonable for
64 16-bit samples, but if you want lossless storage you shouldn't be changing
65 colorspace anyway.
66 The CENTERJSAMPLE offsets and the rounding fudge-factor of 0.5 are included
67 in the tables to save adding them separately in the inner loop. }
68 const
69 SCALEBITS = 16; { speediest right-shift on some machines }
70 CBCR_OFFSET = INT32(CENTERJSAMPLE shl SCALEBITS);
71 ONE_HALF = INT32(1) shl (SCALEBITS-1);
74 { We allocate one big table and divide it up into eight parts, instead of
75 doing eight alloc_small requests. This lets us use a single table base
76 address, which can be held in a register in the inner loops on many
77 machines (more than can hold all eight addresses, anyway). }
79 R_Y_OFF = 0; { offset to R => Y section }
80 G_Y_OFF = 1*(MAXJSAMPLE+1); { offset to G => Y section }
81 B_Y_OFF = 2*(MAXJSAMPLE+1); { etc. }
82 R_CB_OFF = 3*(MAXJSAMPLE+1);
83 G_CB_OFF = 4*(MAXJSAMPLE+1);
84 B_CB_OFF = 5*(MAXJSAMPLE+1);
85 R_CR_OFF = B_CB_OFF; { B=>Cb, R=>Cr are the same }
86 G_CR_OFF = 6*(MAXJSAMPLE+1);
87 B_CR_OFF = 7*(MAXJSAMPLE+1);
88 TABLE_SIZE = 8*(MAXJSAMPLE+1);
91 { Initialize for RGB->YCC colorspace conversion. }
93 {METHODDEF}
94 procedure rgb_ycc_start (cinfo : j_compress_ptr);
95 const
96 FIX_0_29900 = INT32(Round(0.29900 * (1 shl SCALEBITS)));
97 FIX_0_58700 = INT32(Round(0.58700 * (1 shl SCALEBITS)));
98 FIX_0_11400 = INT32(Round(0.11400 * (1 shl SCALEBITS)));
99 FIX_0_16874 = INT32(Round(0.16874 * (1 shl SCALEBITS)));
100 FIX_0_33126 = INT32(Round(0.33126 * (1 shl SCALEBITS)));
101 FIX_0_50000 = INT32(Round(0.50000 * (1 shl SCALEBITS)));
102 FIX_0_41869 = INT32(Round(0.41869 * (1 shl SCALEBITS)));
103 FIX_0_08131 = INT32(Round(0.08131 * (1 shl SCALEBITS)));
104 var
105 cconvert : my_cconvert_ptr;
106 rgb_ycc_tab : INT32_FIELD_PTR;
107 i : INT32;
108 begin
109 cconvert := my_cconvert_ptr (cinfo^.cconvert);
111 { Allocate and fill in the conversion tables. }
112 rgb_ycc_tab := INT32_FIELD_PTR(
113 cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
114 (TABLE_SIZE * SIZEOF(INT32))) );
115 cconvert^.rgb_ycc_tab := rgb_ycc_tab;
117 for i := 0 to MAXJSAMPLE do
118 begin
119 rgb_ycc_tab^[i+R_Y_OFF] := FIX_0_29900 * i;
120 rgb_ycc_tab^[i+G_Y_OFF] := FIX_0_58700 * i;
121 rgb_ycc_tab^[i+B_Y_OFF] := FIX_0_11400 * i + ONE_HALF;
122 rgb_ycc_tab^[i+R_CB_OFF] := (-FIX_0_16874) * i;
123 rgb_ycc_tab^[i+G_CB_OFF] := (-FIX_0_33126) * i;
124 { We use a rounding fudge-factor of 0.5-epsilon for Cb and Cr.
125 This ensures that the maximum output will round to MAXJSAMPLE
126 not MAXJSAMPLE+1, and thus that we don't have to range-limit. }
128 rgb_ycc_tab^[i+B_CB_OFF] := FIX_0_50000 * i + CBCR_OFFSET + ONE_HALF-1;
129 { B=>Cb and R=>Cr tables are the same
130 rgb_ycc_tab^[i+R_CR_OFF] := FIX_0_50000 * i + CBCR_OFFSET + ONE_HALF-1;
132 rgb_ycc_tab^[i+G_CR_OFF] := (-FIX_0_41869) * i;
133 rgb_ycc_tab^[i+B_CR_OFF] := (-FIX_0_08131) * i;
134 end;
135 end;
138 { Convert some rows of samples to the JPEG colorspace.
140 Note that we change from the application's interleaved-pixel format
141 to our internal noninterleaved, one-plane-per-component format.
142 The input buffer is therefore three times as wide as the output buffer.
144 A starting row offset is provided only for the output buffer. The caller
145 can easily adjust the passed input_buf value to accommodate any row
146 offset required on that side. }
148 {METHODDEF}
149 procedure rgb_ycc_convert (cinfo : j_compress_ptr;
150 input_buf : JSAMPARRAY;
151 output_buf : JSAMPIMAGE;
152 output_row : JDIMENSION;
153 num_rows : int);
154 var
155 cconvert : my_cconvert_ptr;
156 {register} r, g, b : int;
157 {register} ctab : INT32_FIELD_PTR;
158 {register} inptr : JSAMPROW;
159 {register} outptr0, outptr1, outptr2 : JSAMPROW;
160 {register} col : JDIMENSION;
161 num_cols : JDIMENSION;
162 begin
163 cconvert := my_cconvert_ptr (cinfo^.cconvert);
164 ctab := cconvert^.rgb_ycc_tab;
165 num_cols := cinfo^.image_width;
167 while (num_rows > 0) do
168 begin
169 Dec(num_rows);
170 inptr := input_buf^[0];
171 Inc(JSAMPROW_PTR(input_buf));
172 outptr0 := output_buf^[0]^[output_row];
173 outptr1 := output_buf^[1]^[output_row];
174 outptr2 := output_buf^[2]^[output_row];
175 Inc(output_row);
176 for col := 0 to pred(num_cols) do
177 begin
178 r := GETJSAMPLE(inptr^[RGB_RED]);
179 g := GETJSAMPLE(inptr^[RGB_GREEN]);
180 b := GETJSAMPLE(inptr^[RGB_BLUE]);
181 Inc(JSAMPLE_PTR(inptr), RGB_PIXELSIZE);
182 { If the inputs are 0..MAXJSAMPLE, the outputs of these equations
183 must be too; we do not need an explicit range-limiting operation.
184 Hence the value being shifted is never negative, and we don't
185 need the general RIGHT_SHIFT macro. }
187 { Y }
188 outptr0^[col] := JSAMPLE(
189 ((ctab^[r+R_Y_OFF] + ctab^[g+G_Y_OFF] + ctab^[b+B_Y_OFF])
190 shr SCALEBITS) );
191 { Cb }
192 outptr1^[col] := JSAMPLE(
193 ((ctab^[r+R_CB_OFF] + ctab^[g+G_CB_OFF] + ctab^[b+B_CB_OFF])
194 shr SCALEBITS) );
195 { Cr }
196 outptr2^[col] := JSAMPLE(
197 ((ctab^[r+R_CR_OFF] + ctab^[g+G_CR_OFF] + ctab^[b+B_CR_OFF])
198 shr SCALEBITS) );
199 end;
200 end;
201 end;
204 {*************** Cases other than RGB -> YCbCr *************}
207 { Convert some rows of samples to the JPEG colorspace.
208 This version handles RGB -> grayscale conversion, which is the same
209 as the RGB -> Y portion of RGB -> YCbCr.
210 We assume rgb_ycc_start has been called (we only use the Y tables). }
212 {METHODDEF}
213 procedure rgb_gray_convert (cinfo : j_compress_ptr;
214 input_buf : JSAMPARRAY;
215 output_buf : JSAMPIMAGE;
216 output_row : JDIMENSION;
217 num_rows : int);
218 var
219 cconvert : my_cconvert_ptr;
220 {register} r, g, b : int;
221 {register} ctab :INT32_FIELD_PTR;
222 {register} inptr : JSAMPROW;
223 {register} outptr : JSAMPROW;
224 {register} col : JDIMENSION;
225 num_cols : JDIMENSION;
226 begin
227 cconvert := my_cconvert_ptr (cinfo^.cconvert);
228 ctab := cconvert^.rgb_ycc_tab;
229 num_cols := cinfo^.image_width;
231 while (num_rows > 0) do
232 begin
233 Dec(num_rows);
234 inptr := input_buf[0];
235 Inc(JSAMPROW_PTR(input_buf));
236 outptr := output_buf[0][output_row];
237 Inc(output_row);
238 for col := 0 to num_cols - 1 do
239 begin
240 r := GETJSAMPLE(inptr[RGB_RED]);
241 g := GETJSAMPLE(inptr[RGB_GREEN]);
242 b := GETJSAMPLE(inptr[RGB_BLUE]);
243 Inc(JSAMPLE_PTR(inptr), RGB_PIXELSIZE);
244 (* Y *)
245 // kylix 3 compiler crashes on this
246 // it also crashes Delphi OSX compiler 9 years later :(
247 {$IF not (Defined(DCC) and not Defined(MSWINDOWS))}
248 outptr[col] := JSAMPLE(((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF]) shr SCALEBITS));
249 {$IFEND}
250 end;
251 end;
252 end;
255 { Convert some rows of samples to the JPEG colorspace.
256 This version handles Adobe-style CMYK -> YCCK conversion,
257 where we convert R=1-C, G=1-M, and B=1-Y to YCbCr using the same
258 conversion as above, while passing K (black) unchanged.
259 We assume rgb_ycc_start has been called. }
261 {METHODDEF}
262 procedure cmyk_ycck_convert (cinfo : j_compress_ptr;
263 input_buf : JSAMPARRAY;
264 output_buf : JSAMPIMAGE;
265 output_row : JDIMENSION;
266 num_rows : int);
267 var
268 cconvert : my_cconvert_ptr;
269 {register} r, g, b : int;
270 {register} ctab : INT32_FIELD_PTR;
271 {register} inptr : JSAMPROW;
272 {register} outptr0, outptr1, outptr2, outptr3 : JSAMPROW;
273 {register} col : JDIMENSION;
274 num_cols : JDIMENSION;
275 begin
276 cconvert := my_cconvert_ptr (cinfo^.cconvert);
277 ctab := cconvert^.rgb_ycc_tab;
278 num_cols := cinfo^.image_width;
280 while (num_rows > 0) do
281 begin
282 Dec(num_rows);
283 inptr := input_buf^[0];
284 Inc(JSAMPROW_PTR(input_buf));
285 outptr0 := output_buf^[0]^[output_row];
286 outptr1 := output_buf^[1]^[output_row];
287 outptr2 := output_buf^[2]^[output_row];
288 outptr3 := output_buf^[3]^[output_row];
289 Inc(output_row);
290 for col := 0 to pred(num_cols) do
291 begin
292 r := MAXJSAMPLE - GETJSAMPLE(inptr^[0]);
293 g := MAXJSAMPLE - GETJSAMPLE(inptr^[1]);
294 b := MAXJSAMPLE - GETJSAMPLE(inptr^[2]);
295 { K passes through as-is }
296 outptr3^[col] := inptr^[3]; { don't need GETJSAMPLE here }
297 Inc(JSAMPLE_PTR(inptr), 4);
298 { If the inputs are 0..MAXJSAMPLE, the outputs of these equations
299 must be too; we do not need an explicit range-limiting operation.
300 Hence the value being shifted is never negative, and we don't
301 need the general RIGHT_SHIFT macro. }
303 { Y }
304 outptr0^[col] := JSAMPLE (
305 ((ctab^[r+R_Y_OFF] + ctab^[g+G_Y_OFF] + ctab^[b+B_Y_OFF])
306 shr SCALEBITS) );
307 { Cb }
308 outptr1^[col] := JSAMPLE(
309 ((ctab^[r+R_CB_OFF] + ctab^[g+G_CB_OFF] + ctab^[b+B_CB_OFF])
310 shr SCALEBITS) );
311 { Cr }
312 outptr2^[col] := JSAMPLE (
313 ((ctab^[r+R_CR_OFF] + ctab^[g+G_CR_OFF] + ctab^[b+B_CR_OFF])
314 shr SCALEBITS) );
315 end;
316 end;
317 end;
320 { Convert some rows of samples to the JPEG colorspace.
321 This version handles grayscale output with no conversion.
322 The source can be either plain grayscale or YCbCr (since Y = gray). }
324 {METHODDEF}
325 procedure grayscale_convert (cinfo : j_compress_ptr;
326 input_buf : JSAMPARRAY;
327 output_buf : JSAMPIMAGE;
328 output_row : JDIMENSION;
329 num_rows: int);
330 var
331 {register} inptr : JSAMPROW;
332 {register} outptr : JSAMPROW;
333 {register} col : JDIMENSION;
334 num_cols :JDIMENSION;
335 instride : int;
336 begin
337 num_cols := cinfo^.image_width;
338 instride := cinfo^.input_components;
340 while (num_rows > 0) do
341 begin
342 Dec(num_rows);
343 inptr := input_buf^[0];
344 Inc(JSAMPROW_PTR(input_buf));
345 outptr := output_buf^[0]^[output_row];
346 Inc(output_row);
347 for col := 0 to pred(num_cols) do
348 begin
349 outptr^[col] := inptr^[0]; { don't need GETJSAMPLE() here }
350 Inc(JSAMPLE_PTR(inptr), instride);
351 end;
352 end;
353 end;
356 { Convert some rows of samples to the JPEG colorspace.
357 This version handles multi-component colorspaces without conversion.
358 We assume input_components = num_components. }
360 {METHODDEF}
361 procedure null_convert (cinfo : j_compress_ptr;
362 input_buf : JSAMPARRAY;
363 output_buf : JSAMPIMAGE;
364 output_row : JDIMENSION;
365 num_rows : int);
366 var
367 {register} inptr : JSAMPROW;
368 {register} outptr : JSAMPROW;
369 {register} col : JDIMENSION;
370 {register} ci : int;
371 nc : int;
372 num_cols : JDIMENSION;
373 begin
374 nc := cinfo^.num_components;
375 num_cols := cinfo^.image_width;
377 while (num_rows > 0) do
378 begin
379 Dec(num_rows);
380 { It seems fastest to make a separate pass for each component. }
381 for ci := 0 to pred(nc) do
382 begin
383 inptr := input_buf^[0];
384 outptr := output_buf^[ci]^[output_row];
385 for col := 0 to pred(num_cols) do
386 begin
387 outptr^[col] := inptr^[ci]; { don't need GETJSAMPLE() here }
388 Inc(JSAMPLE_PTR(inptr), nc);
389 end;
390 end;
391 Inc(JSAMPROW_PTR(input_buf));
392 Inc(output_row);
393 end;
394 end;
397 { Empty method for start_pass. }
399 {METHODDEF}
400 procedure null_method (cinfo : j_compress_ptr);
401 begin
402 { no work needed }
403 end;
406 { Module initialization routine for input colorspace conversion. }
408 {GLOBAL}
409 procedure jinit_color_converter (cinfo : j_compress_ptr);
410 var
411 cconvert : my_cconvert_ptr;
412 begin
413 cconvert := my_cconvert_ptr(
414 cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
415 SIZEOF(my_color_converter)) );
416 cinfo^.cconvert := jpeg_color_converter_ptr(cconvert);
417 { set start_pass to null method until we find out differently }
418 cconvert^.pub.start_pass := null_method;
420 { Make sure input_components agrees with in_color_space }
421 case (cinfo^.in_color_space) of
422 JCS_GRAYSCALE:
423 if (cinfo^.input_components <> 1) then
424 ERREXIT(j_common_ptr(cinfo), JERR_BAD_IN_COLORSPACE);
426 {$ifdef RGB_PIXELSIZE <> 3}
427 JCS_RGB:
428 if (cinfo^.input_components <> RGB_PIXELSIZE) then
429 ERREXIT(j_common_ptr(cinfo), JERR_BAD_IN_COLORSPACE);
430 {$else} { share code with YCbCr }
431 JCS_RGB,
432 {$endif}
433 JCS_YCbCr:
434 if (cinfo^.input_components <> 3) then
435 ERREXIT(j_common_ptr(cinfo), JERR_BAD_IN_COLORSPACE);
437 JCS_CMYK,
438 JCS_YCCK:
439 if (cinfo^.input_components <> 4) then
440 ERREXIT(j_common_ptr(cinfo), JERR_BAD_IN_COLORSPACE);
442 else { JCS_UNKNOWN can be anything }
443 if (cinfo^.input_components < 1) then
444 ERREXIT(j_common_ptr(cinfo), JERR_BAD_IN_COLORSPACE);
445 end;
447 { Check num_components, set conversion method based on requested space }
448 case (cinfo^.jpeg_color_space) of
449 JCS_GRAYSCALE:
450 begin
451 if (cinfo^.num_components <> 1) then
452 ERREXIT(j_common_ptr(cinfo), JERR_BAD_J_COLORSPACE);
453 if (cinfo^.in_color_space = JCS_GRAYSCALE) then
454 cconvert^.pub.color_convert := grayscale_convert
455 else
456 if (cinfo^.in_color_space = JCS_RGB) then
457 begin
458 cconvert^.pub.start_pass := rgb_ycc_start;
459 cconvert^.pub.color_convert := rgb_gray_convert;
460 end
461 else
462 if (cinfo^.in_color_space = JCS_YCbCr) then
463 cconvert^.pub.color_convert := grayscale_convert
464 else
465 ERREXIT(j_common_ptr(cinfo), JERR_CONVERSION_NOTIMPL);
466 end;
468 JCS_RGB:
469 begin
470 if (cinfo^.num_components <> 3) then
471 ERREXIT(j_common_ptr(cinfo), JERR_BAD_J_COLORSPACE);
472 if (cinfo^.in_color_space = JCS_RGB) and (RGB_PIXELSIZE = 3) then
473 cconvert^.pub.color_convert := null_convert
474 else
475 ERREXIT(j_common_ptr(cinfo), JERR_CONVERSION_NOTIMPL);
476 end;
478 JCS_YCbCr:
479 begin
480 if (cinfo^.num_components <> 3) then
481 ERREXIT(j_common_ptr(cinfo), JERR_BAD_J_COLORSPACE);
482 if (cinfo^.in_color_space = JCS_RGB) then
483 begin
484 cconvert^.pub.start_pass := rgb_ycc_start;
485 cconvert^.pub.color_convert := rgb_ycc_convert;
486 end
487 else
488 if (cinfo^.in_color_space = JCS_YCbCr) then
489 cconvert^.pub.color_convert := null_convert
490 else
491 ERREXIT(j_common_ptr(cinfo), JERR_CONVERSION_NOTIMPL);
492 end;
494 JCS_CMYK:
495 begin
496 if (cinfo^.num_components <> 4) then
497 ERREXIT(j_common_ptr(cinfo), JERR_BAD_J_COLORSPACE);
498 if (cinfo^.in_color_space = JCS_CMYK) then
499 cconvert^.pub.color_convert := null_convert
500 else
501 ERREXIT(j_common_ptr(cinfo), JERR_CONVERSION_NOTIMPL);
502 end;
504 JCS_YCCK:
505 begin
506 if (cinfo^.num_components <> 4) then
507 ERREXIT(j_common_ptr(cinfo), JERR_BAD_J_COLORSPACE);
508 if (cinfo^.in_color_space = JCS_CMYK) then
509 begin
510 cconvert^.pub.start_pass := rgb_ycc_start;
511 cconvert^.pub.color_convert := cmyk_ycck_convert;
512 end
513 else
514 if (cinfo^.in_color_space = JCS_YCCK) then
515 cconvert^.pub.color_convert := null_convert
516 else
517 ERREXIT(j_common_ptr(cinfo), JERR_CONVERSION_NOTIMPL);
518 end;
520 else { allow null conversion of JCS_UNKNOWN }
521 begin
522 if (cinfo^.jpeg_color_space <> cinfo^.in_color_space) or
523 (cinfo^.num_components <> cinfo^.input_components) then
524 ERREXIT(j_common_ptr(cinfo), JERR_CONVERSION_NOTIMPL);
525 cconvert^.pub.color_convert := null_convert;
526 end;
527 end;
528 end;
530 end.