DEADSOFTWARE

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