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