1 Unit JcColor; 2 3 { This file contains input colorspace conversion routines. } 4 5 { Original : jccolor.c ; Copyright (C) 1991-1996, Thomas G. Lane. } 6 7 interface 8 9 {$I jconfig.inc} 10 11 uses 12 jmorecfg, 13 jinclude, 14 jdeferr, 15 jerror, 16 jpeglib; 17 18 { Module initialization routine for input colorspace conversion. } 19 20 {GLOBAL} 21 procedure jinit_color_converter (cinfo : j_compress_ptr); 22 23 implementation 24 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; 30 31 type 32 my_cconvert_ptr = ^my_color_converter; 33 my_color_converter = record 34 pub : jpeg_color_converter; { public fields } 35 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;} 39 40 41 {*************** RGB -> YCbCr conversion: most common case *************} 42 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. 56 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. 60 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); 73 74 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). } 79 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); 90 91 92 { Initialize for RGB->YCC colorspace conversion. } 93 94 {METHODDEF} 95 procedure rgb_ycc_start (cinfo : j_compress_ptr); far; 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); 111 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; 117 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. } 128 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; 132 } 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; 137 138 139 { Convert some rows of samples to the JPEG colorspace. 140 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. 144 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. } 148 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); far; 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; 167 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. } 187 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; 203 204 205 {*************** Cases other than RGB -> YCbCr *************} 206 207 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). } 212 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); far; 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; 231 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 outptr^[col] := JSAMPLE ( 247 ((ctab^[r+R_Y_OFF] + ctab^[g+G_Y_OFF] + ctab^[b+B_Y_OFF]) 248 shr SCALEBITS) ); 249 end; 250 end; 251 end; 252 253 254 { Convert some rows of samples to the JPEG colorspace. 255 This version handles Adobe-style CMYK -> YCCK conversion, 256 where we convert R=1-C, G=1-M, and B=1-Y to YCbCr using the same 257 conversion as above, while passing K (black) unchanged. 258 We assume rgb_ycc_start has been called. } 259 260 {METHODDEF} 261 procedure cmyk_ycck_convert (cinfo : j_compress_ptr; 262 input_buf : JSAMPARRAY; 263 output_buf : JSAMPIMAGE; 264 output_row : JDIMENSION; 265 num_rows : int); far; 266 var 267 cconvert : my_cconvert_ptr; 268 {register} r, g, b : int; 269 {register} ctab : INT32_FIELD_PTR; 270 {register} inptr : JSAMPROW; 271 {register} outptr0, outptr1, outptr2, outptr3 : JSAMPROW; 272 {register} col : JDIMENSION; 273 num_cols : JDIMENSION; 274 begin 275 cconvert := my_cconvert_ptr (cinfo^.cconvert); 276 ctab := cconvert^.rgb_ycc_tab; 277 num_cols := cinfo^.image_width; 278 279 while (num_rows > 0) do 280 begin 281 Dec(num_rows); 282 inptr := input_buf^[0]; 283 Inc(JSAMPROW_PTR(input_buf)); 284 outptr0 := output_buf^[0]^[output_row]; 285 outptr1 := output_buf^[1]^[output_row]; 286 outptr2 := output_buf^[2]^[output_row]; 287 outptr3 := output_buf^[3]^[output_row]; 288 Inc(output_row); 289 for col := 0 to pred(num_cols) do 290 begin 291 r := MAXJSAMPLE - GETJSAMPLE(inptr^[0]); 292 g := MAXJSAMPLE - GETJSAMPLE(inptr^[1]); 293 b := MAXJSAMPLE - GETJSAMPLE(inptr^[2]); 294 { K passes through as-is } 295 outptr3^[col] := inptr^[3]; { don't need GETJSAMPLE here } 296 Inc(JSAMPLE_PTR(inptr), 4); 297 { If the inputs are 0..MAXJSAMPLE, the outputs of these equations 298 must be too; we do not need an explicit range-limiting operation. 299 Hence the value being shifted is never negative, and we don't 300 need the general RIGHT_SHIFT macro. } 301 302 { Y } 303 outptr0^[col] := JSAMPLE ( 304 ((ctab^[r+R_Y_OFF] + ctab^[g+G_Y_OFF] + ctab^[b+B_Y_OFF]) 305 shr SCALEBITS) ); 306 { Cb } 307 outptr1^[col] := JSAMPLE( 308 ((ctab^[r+R_CB_OFF] + ctab^[g+G_CB_OFF] + ctab^[b+B_CB_OFF]) 309 shr SCALEBITS) ); 310 { Cr } 311 outptr2^[col] := JSAMPLE ( 312 ((ctab^[r+R_CR_OFF] + ctab^[g+G_CR_OFF] + ctab^[b+B_CR_OFF]) 313 shr SCALEBITS) ); 314 end; 315 end; 316 end; 317 318 319 { Convert some rows of samples to the JPEG colorspace. 320 This version handles grayscale output with no conversion. 321 The source can be either plain grayscale or YCbCr (since Y = gray). } 322 323 {METHODDEF} 324 procedure grayscale_convert (cinfo : j_compress_ptr; 325 input_buf : JSAMPARRAY; 326 output_buf : JSAMPIMAGE; 327 output_row : JDIMENSION; 328 num_rows: int); far; 329 var 330 {register} inptr : JSAMPROW; 331 {register} outptr : JSAMPROW; 332 {register} col : JDIMENSION; 333 num_cols :JDIMENSION; 334 instride : int; 335 begin 336 num_cols := cinfo^.image_width; 337 instride := cinfo^.input_components; 338 339 while (num_rows > 0) do 340 begin 341 Dec(num_rows); 342 inptr := input_buf^[0]; 343 Inc(JSAMPROW_PTR(input_buf)); 344 outptr := output_buf^[0]^[output_row]; 345 Inc(output_row); 346 for col := 0 to pred(num_cols) do 347 begin 348 outptr^[col] := inptr^[0]; { don't need GETJSAMPLE() here } 349 Inc(JSAMPLE_PTR(inptr), instride); 350 end; 351 end; 352 end; 353 354 355 { Convert some rows of samples to the JPEG colorspace. 356 This version handles multi-component colorspaces without conversion. 357 We assume input_components = num_components. } 358 359 {METHODDEF} 360 procedure null_convert (cinfo : j_compress_ptr; 361 input_buf : JSAMPARRAY; 362 output_buf : JSAMPIMAGE; 363 output_row : JDIMENSION; 364 num_rows : int); far; 365 var 366 {register} inptr : JSAMPROW; 367 {register} outptr : JSAMPROW; 368 {register} col : JDIMENSION; 369 {register} ci : int; 370 nc : int; 371 num_cols : JDIMENSION; 372 begin 373 nc := cinfo^.num_components; 374 num_cols := cinfo^.image_width; 375 376 while (num_rows > 0) do 377 begin 378 Dec(num_rows); 379 { It seems fastest to make a separate pass for each component. } 380 for ci := 0 to pred(nc) do 381 begin 382 inptr := input_buf^[0]; 383 outptr := output_buf^[ci]^[output_row]; 384 for col := 0 to pred(num_cols) do 385 begin 386 outptr^[col] := inptr^[ci]; { don't need GETJSAMPLE() here } 387 Inc(JSAMPLE_PTR(inptr), nc); 388 end; 389 end; 390 Inc(JSAMPROW_PTR(input_buf)); 391 Inc(output_row); 392 end; 393 end; 394 395 396 { Empty method for start_pass. } 397 398 {METHODDEF} 399 procedure null_method (cinfo : j_compress_ptr); far; 400 begin 401 { no work needed } 402 end; 403 404 405 { Module initialization routine for input colorspace conversion. } 406 407 {GLOBAL} 408 procedure jinit_color_converter (cinfo : j_compress_ptr); 409 var 410 cconvert : my_cconvert_ptr; 411 begin 412 cconvert := my_cconvert_ptr( 413 cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE, 414 SIZEOF(my_color_converter)) ); 415 cinfo^.cconvert := jpeg_color_converter_ptr(cconvert); 416 { set start_pass to null method until we find out differently } 417 cconvert^.pub.start_pass := null_method; 418 419 { Make sure input_components agrees with in_color_space } 420 case (cinfo^.in_color_space) of 421 JCS_GRAYSCALE: 422 if (cinfo^.input_components <> 1) then 423 ERREXIT(j_common_ptr(cinfo), JERR_BAD_IN_COLORSPACE); 424 425 {$ifdef RGB_PIXELSIZE <> 3} 426 JCS_RGB: 427 if (cinfo^.input_components <> RGB_PIXELSIZE) then 428 ERREXIT(j_common_ptr(cinfo), JERR_BAD_IN_COLORSPACE); 429 {$else} { share code with YCbCr } 430 JCS_RGB, 431 {$endif} 432 JCS_YCbCr: 433 if (cinfo^.input_components <> 3) then 434 ERREXIT(j_common_ptr(cinfo), JERR_BAD_IN_COLORSPACE); 435 436 JCS_CMYK, 437 JCS_YCCK: 438 if (cinfo^.input_components <> 4) then 439 ERREXIT(j_common_ptr(cinfo), JERR_BAD_IN_COLORSPACE); 440 441 else { JCS_UNKNOWN can be anything } 442 if (cinfo^.input_components < 1) then 443 ERREXIT(j_common_ptr(cinfo), JERR_BAD_IN_COLORSPACE); 444 end; 445 446 { Check num_components, set conversion method based on requested space } 447 case (cinfo^.jpeg_color_space) of 448 JCS_GRAYSCALE: 449 begin 450 if (cinfo^.num_components <> 1) then 451 ERREXIT(j_common_ptr(cinfo), JERR_BAD_J_COLORSPACE); 452 if (cinfo^.in_color_space = JCS_GRAYSCALE) then 453 cconvert^.pub.color_convert := grayscale_convert 454 else 455 if (cinfo^.in_color_space = JCS_RGB) then 456 begin 457 cconvert^.pub.start_pass := rgb_ycc_start; 458 cconvert^.pub.color_convert := rgb_gray_convert; 459 end 460 else 461 if (cinfo^.in_color_space = JCS_YCbCr) then 462 cconvert^.pub.color_convert := grayscale_convert 463 else 464 ERREXIT(j_common_ptr(cinfo), JERR_CONVERSION_NOTIMPL); 465 end; 466 467 JCS_RGB: 468 begin 469 if (cinfo^.num_components <> 3) then 470 ERREXIT(j_common_ptr(cinfo), JERR_BAD_J_COLORSPACE); 471 if (cinfo^.in_color_space = JCS_RGB) and (RGB_PIXELSIZE = 3) then 472 cconvert^.pub.color_convert := null_convert 473 else 474 ERREXIT(j_common_ptr(cinfo), JERR_CONVERSION_NOTIMPL); 475 end; 476 477 JCS_YCbCr: 478 begin 479 if (cinfo^.num_components <> 3) then 480 ERREXIT(j_common_ptr(cinfo), JERR_BAD_J_COLORSPACE); 481 if (cinfo^.in_color_space = JCS_RGB) then 482 begin 483 cconvert^.pub.start_pass := rgb_ycc_start; 484 cconvert^.pub.color_convert := rgb_ycc_convert; 485 end 486 else 487 if (cinfo^.in_color_space = JCS_YCbCr) then 488 cconvert^.pub.color_convert := null_convert 489 else 490 ERREXIT(j_common_ptr(cinfo), JERR_CONVERSION_NOTIMPL); 491 end; 492 493 JCS_CMYK: 494 begin 495 if (cinfo^.num_components <> 4) then 496 ERREXIT(j_common_ptr(cinfo), JERR_BAD_J_COLORSPACE); 497 if (cinfo^.in_color_space = JCS_CMYK) then 498 cconvert^.pub.color_convert := null_convert 499 else 500 ERREXIT(j_common_ptr(cinfo), JERR_CONVERSION_NOTIMPL); 501 end; 502 503 JCS_YCCK: 504 begin 505 if (cinfo^.num_components <> 4) then 506 ERREXIT(j_common_ptr(cinfo), JERR_BAD_J_COLORSPACE); 507 if (cinfo^.in_color_space = JCS_CMYK) then 508 begin 509 cconvert^.pub.start_pass := rgb_ycc_start; 510 cconvert^.pub.color_convert := cmyk_ycck_convert; 511 end 512 else 513 if (cinfo^.in_color_space = JCS_YCCK) then 514 cconvert^.pub.color_convert := null_convert 515 else 516 ERREXIT(j_common_ptr(cinfo), JERR_CONVERSION_NOTIMPL); 517 end; 518 519 else { allow null conversion of JCS_UNKNOWN } 520 begin 521 if (cinfo^.jpeg_color_space <> cinfo^.in_color_space) or 522 (cinfo^.num_components <> cinfo^.input_components) then 523 ERREXIT(j_common_ptr(cinfo), JERR_CONVERSION_NOTIMPL); 524 cconvert^.pub.color_convert := null_convert; 525 end; 526 end; 527 end; 528 529 end. 530