PageRenderTime 42ms CodeModel.GetById 38ms app.highlight 2ms RepoModel.GetById 0ms app.codeStats 0ms

/packages/pasjpeg/src/jccolor.pas

https://github.com/slibre/freepascal
Pascal | 529 lines | 360 code | 64 blank | 105 comment | 34 complexity | a381c245c15d2510691f31dcb7a46f4f MD5 | raw file
Possible License(s): LGPL-2.0, LGPL-2.1, LGPL-3.0
  1Unit JcColor;
  2
  3{  This file contains input colorspace conversion routines. }
  4
  5{ Original : jccolor.c ;  Copyright (C) 1991-1996, Thomas G. Lane. }
  6
  7interface
  8
  9{$I jconfig.inc}
 10
 11uses
 12  jmorecfg,
 13  jinclude,
 14  jdeferr,
 15  jerror,
 16  jpeglib;
 17
 18{ Module initialization routine for input colorspace conversion. }
 19
 20{GLOBAL}
 21procedure jinit_color_converter (cinfo : j_compress_ptr);
 22
 23implementation
 24
 25{ Private subobject }
 26type
 27  jTInt32 = 0..Pred(MaxInt div SizeOf(INT32));
 28  INT32_FIELD = array[jTInt32] of INT32;
 29  INT32_FIELD_PTR = ^INT32_FIELD;
 30
 31type
 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. }
 69const
 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}
 95procedure rgb_ycc_start (cinfo : j_compress_ptr); far;
 96const
 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)) );
105var
106  cconvert : my_cconvert_ptr;
107  rgb_ycc_tab : INT32_FIELD_PTR;
108  i : INT32;
109begin
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;
136end;
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}
150procedure rgb_ycc_convert (cinfo : j_compress_ptr;
151                           input_buf : JSAMPARRAY;
152                           output_buf :  JSAMPIMAGE;
153                           output_row : JDIMENSION;
154                           num_rows : int); far;
155var
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;
163begin
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;
202end;
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}
214procedure rgb_gray_convert (cinfo : j_compress_ptr;
215                            input_buf : JSAMPARRAY;
216                            output_buf : JSAMPIMAGE;
217                            output_row : JDIMENSION;
218                            num_rows : int); far;
219var
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;
227begin
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;
251end;
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}
261procedure cmyk_ycck_convert (cinfo : j_compress_ptr;
262                             input_buf : JSAMPARRAY;
263                             output_buf : JSAMPIMAGE;
264                             output_row : JDIMENSION;
265                             num_rows : int); far;
266var
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;
274begin
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;
316end;
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}
324procedure grayscale_convert (cinfo : j_compress_ptr;
325                            input_buf : JSAMPARRAY;
326                            output_buf : JSAMPIMAGE;
327                            output_row : JDIMENSION;
328                            num_rows: int); far;
329var
330  {register} inptr : JSAMPROW;
331  {register} outptr : JSAMPROW;
332  {register} col : JDIMENSION;
333  num_cols :JDIMENSION;
334  instride : int;
335begin
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;
352end;
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}
360procedure null_convert (cinfo : j_compress_ptr;
361                        input_buf : JSAMPARRAY;
362                        output_buf : JSAMPIMAGE;
363                        output_row : JDIMENSION;
364                        num_rows : int); far;
365var
366  {register} inptr : JSAMPROW;
367  {register} outptr : JSAMPROW;
368  {register} col : JDIMENSION;
369  {register} ci : int;
370  nc : int;
371  num_cols : JDIMENSION;
372begin
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;
393end;
394
395
396{ Empty method for start_pass. }
397
398{METHODDEF}
399procedure null_method (cinfo : j_compress_ptr); far;
400begin
401  { no work needed }
402end;
403
404
405{ Module initialization routine for input colorspace conversion. }
406
407{GLOBAL}
408procedure jinit_color_converter (cinfo : j_compress_ptr);
409var
410  cconvert : my_cconvert_ptr;
411begin
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;
527end;
528
529end.