Tizen 2.1 base
[platform/upstream/hplip.git] / ip / xcolrspc.c
1 /* libhpojip -- HP OfficeJet image-processing library. */
2
3 /* Copyright (C) 1995-2002 Hewlett-Packard Company
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
12  * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
13  * NON-INFRINGEMENT.  See the GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
18  * MA 02111-1307, USA.
19  *
20  * In addition, as a special exception, Hewlett-Packard Company
21  * gives permission to link the code of this program with any
22  * version of the OpenSSL library which is distributed under a
23  * license identical to that listed in the included LICENSE.OpenSSL
24  * file, and distribute linked combinations including the two.
25  * You must obey the GNU General Public License in all respects
26  * for all of the code used other than OpenSSL.  If you modify
27  * this file, you may extend this exception to your version of the
28  * file, but you are not obligated to do so.  If you do not wish to
29  * do so, delete this exception statement from your version.
30  */
31
32 /* Original author: Mark Overton and others.
33  *
34  * Ported to Linux by David Paschal.
35  */
36
37 /******************************************************************************\
38  *
39  * xcolrspc.c - Converts between color spaces
40  *
41  ******************************************************************************
42  *
43  * Name of Global Jump-Table:
44  *
45  *    colorTbl
46  *
47  * Items in aXformInfo array passed into setXformSpec:
48  *
49  *    aXformInfo[IP_CNV_COLOR_SPACE_WHICH_CNV] = Which color-space conversion to do:
50  *       IP_CNV_YCC_TO_CIELAB = ycc    -> cielab
51  *       IP_CNV_CIELAB_TO_YCC = cielab -> ycc
52  *       IP_CNV_YCC_TO_SRGB   = ycc    -> srgb
53  *       IP_CNV_SRGB_TO_YCC   = srgb   -> ycc
54  *       IP_CNV_LHS_TO_SRGB   = lhs    -> srgb
55  *       IP_CNV_SRGB_TO_LHS   = srgb   -> lhs
56  *       IP_CNV_BGR_SWAP      = rgb<->bgr swap
57  *
58  *    aXformInfo[IP_CNV_COLOR_SPACE_GAMMA] = Gamma value for gamma correction,
59  *                    in 16.16 fixed-point.
60  *                    In the YCC->CIELab conversion, the data will be
61  *                    inverse-gamma corrected using 1/Gamma.
62  *                    In the CIELab->YCC conversion, it will be gamma corrected
63  *                    using Gamma.
64  *                    This Gamma value is ignored in the other conversions.
65  *                    A value of 0.0 makes us use a default Gamma of 2.2.
66  *                    You must set this to 1.0 if you want to disable Gamma.
67  *
68  *                    Gamma is done here because the pixels are in RGB at one
69  *                    point in the YCC<->CIELab conversions. Since you can't do
70  *                    Gamma on YCC or CIELab data, it can't be done outside
71  *                    this xform for those two conversions.
72  *
73  * Capabilities and Limitations:
74  *
75  *    Does the space conversions listed above.  Conversions will only be done on
76  *    24-bit data; monochrome data are passed through unchanged.
77  *
78  * Default Input Traits, and Output Traits:
79  *
80  *          trait             default input             output
81  *    -------------------  ---------------------  ------------------------
82  *    iPixelsPerRow         * passed into output   same as default input
83  *    iBitsPerPixel         * must be <= 24        same as default input
84  *    iComponentsPerPixel     passed into output   same as default input
85  *    lHorizDPI               passed into output   same as default input
86  *    lVertDPI                passed into output   same as default input
87  *    lNumRows                passed into output   same as default input
88  *    iNumPages               passed into output   same as default input
89  *    iPageNum                passed into output   same as default input
90  *
91  *    Above, a "*" by an item indicates it must be valid (not negative).
92  *
93  * Feb 1998 Mark Overton -- wrote original code, with dummy conversions
94  * Apr 1998 Mark Overton -- added actual conversion code, adapted from
95  *                          Cindy Samson's code
96  *
97 \******************************************************************************/
98
99 #include "math.h"   // needed for pow and floor
100 #include "hpip.h"
101 #include "ipdefs.h"
102 #include "string.h"    /* for memset and memcpy */
103 #include "assert.h"
104
105 /* xsc_clean[Uu]p.h: */
106
107 int Send_yTable[100] = {
108 210,212,213,214,215,216,
109 217,218,219,220,221,223,
110 224,225,226,228,230,232,
111 233,234,235,237,238,239,
112 240,242,243,244,245,246,
113 247,248,249,250,251,252,
114 253,254,255,255,255,255,
115 255,255,255,255};
116
117 /* end xsc_clean[Uu]p.h */
118
119
120 #if 0
121     #include "stdio.h"
122     #include <tchar.h>
123     #define PRINT(msg,arg1,arg2) \
124         _ftprintf(stderr, msg, (int)arg1, (int)arg2)
125 #else
126     #define PRINT(msg,arg1,arg2)
127 #endif
128
129 #define CHECK_VALUE 0x4ba1dace
130
131
132 typedef struct {
133     IP_IMAGE_TRAITS traits;     /* traits of the input image */
134     IP_WHICH_CNV    which_cnv;  /* which space-conversion to do */
135     BYTE      bGammaTbl[256];   /* Gamma-correction table */
136     DWORD     dwRowsDone;       /* number of rows converted so far */
137     DWORD     dwInNextPos;      /* file pos for subsequent input */
138     DWORD     dwOutNextPos;     /* file pos for subsequent output */
139     DWORD     dwValidChk;       /* struct validity check value */
140 } COL_INST, *PCOL_INST;
141
142 static BOOL fInited = FALSE;
143
144 //Neutral Shift Data Definition
145 #define NEUTRAL_SHIFT_SEND   TRUE  
146
147
148 // constants to convert [r,g,b] into Y
149 #define RGBTOY_R_FAC      0.30078125f
150 #define RGBTOY_G_FAC      0.5859375f
151 #define RGBTOY_B_FAC      0.11328125f
152
153 // constants to convert [y,cb,cr] into [r,g,b]
154 #define YCCTORGB_CR_TO_R  1.39946f
155 #define YCCTORGB_CB_TO_G -0.344228f
156 #define YCCTORGB_CR_TO_G -0.717202f
157 #define YCCTORGB_CB_TO_B  1.77243f
158
159
160 // The above constants used for converting between RGB and YCC are based
161 // on the following conversion matrices.  The code assumes that the
162 // 0.003 and 0.006 below are zero.
163 #if 0
164     static float RGBtoYCC[3][3]= {  // input is RGB
165         0.30078125f,  0.5859375f,   0.11328125f,  // Y
166        -0.16796875f, -0.33203125f,  0.5f,         // Cb
167         0.5f,        -0.41796875f, -0.08203125f   // Cr
168     };
169
170     static float YCCtoRGB[3][3]= {  // input is YCbCr
171         1.0f,  0.003f,     1.39946f,    // R
172         1.0f, -0.344228f, -0.717202f,   // G
173         1.0f,  1.77243f,   0.006f       // B
174     };
175 #endif
176
177
178 #define X_SCALE  (255.0/244.0)
179 #define Y_SCALE  (255.0/255.0)
180 #define Z_SCALE  (255.0/210.0)
181
182 #define DEFAULT_GAMMA 2.2f
183 #define SLIGHT_BOOST  (255.0/253.0)   // todo - get rid of this
184
185
186 /****************************************************************************\
187  ****************************************************************************
188  **                                                                        **
189  **                    W O R K E R   R O U T I N E S                       **
190  **                                                                        **
191  ****************************************************************************
192 \****************************************************************************/
193
194
195
196 #define CLIP(wilma) ((wilma>255) ? 255 : ((wilma<0) ? 0 : (wilma)))
197
198 #define TERM_FRAC_BITS   4    // # frac bits in temp x/y/z terms
199 #define CONV_FRAC_BITS   4    // # frac bits in "_fix" conversion tables
200 #define CONV_FRAC_ROUND  (1L<<(CONV_FRAC_BITS-1))
201 #define TBL33_FRAC_BITS  16   // # bits of fraction in 3x3 tables
202 #define TABLE_FRAC_SCALE (1L << TBL33_FRAC_BITS)
203
204
205 // these tables are computed by initTables
206
207 static BYTE  YtoL       [256];   // these are for to/from CIELab
208 static BYTE  LtoY       [256];
209 static short cubeRoot   [256];
210 static BYTE  cube       [256];
211
212 static short cb2b       [256];   // these are for [y,cb,cr]->[r,g,b]
213 static short cr2r       [256];
214 static short cr2g_fix   [256];
215 static short cb2g_fix   [256];
216
217 static short r2y_fix    [256];   // these are for [r,g,b]->Y
218 static short g2y_fix    [256];
219 static short b2y_fix    [256];
220
221 static BYTE  by2cb     [2*256]; // these are for [r,g,b]->CbCr
222 static BYTE  ry2cr     [2*256];
223
224
225
226 // VectMult - Multiplies a pixel by a 3x3 matrix, with fixed-point math
227 //
228 static void VectMult(
229     int   inPixel[3],  // in:  input pixel
230     int   outPixel[3], // out: output pixel
231     long *pMat)        // in:  3x3 matrix with TBL33_FRAC_BITS of fraction
232 {
233     int    i;
234
235     for (i=0; i<3; i++) {
236         outPixel[i] = (int)( pMat[0]*inPixel[0] + 
237                              pMat[1]*inPixel[1] +
238                              pMat[2]*inPixel[2] + (1L<<(TBL33_FRAC_BITS-1))
239                       ) >> TBL33_FRAC_BITS;
240         pMat += 3;
241     }
242 }
243
244
245
246 // initTables - Computes look-up tables
247 //
248 // CIE Illuminant D50 white point Xn=96.422 Yn=100 Zn=82.521
249 // CIE Illuminant D65 white point Xn=95.04  Yn=100 Zn=108.89
250 // FAX gamut Range:
251 // L* = [0,100]
252 // a* = [-85, 85]
253 // b* = [-75, 125]
254 //
255 // NL = 255/100*l
256 // Na = 255/170 x a* + 128
257 // Nb = 255/200 x b* + 96
258 //
259
260 static void initTables (void)
261 {
262     int   val;
263     int   icr, icb;
264     float fval;
265     float t;
266
267     for (val=0; val<=255; val++)
268     {
269         fval = (float)val / 255.0f;
270
271         // compute Y->L array
272
273         if (fval > 0.008856f) t = 116.0f*(float)pow(fval,1.0/3.0) - 16.0f;
274         else                  t = 903.3f*fval;
275         t = (255.0f/100.0f)*t;
276         if (t < 0.0f)   t = 0.0f;
277         if (t > 255.0f) t = 255.0f;
278         YtoL[val] = (BYTE)(t + 0.5f);
279
280         // compute L->Y array
281
282         if (val <= 7)
283             t = val * (100.0f/903.3f);
284         else {
285             t = (fval*100.0f+16.0f) / 116.0f;
286             t = 255.0f*t*t*t;
287         }
288         LtoY[val] = (BYTE)(t + 0.5f);
289
290         // compute cube-root array.
291         // Input is 0..255. We divide it by 255 so it's 0..1, take cube root,
292         // and scale result to 0..255.  Adjustment is for small numbers.
293
294         if (fval > 0.008856f) t = (float)pow(fval, 1.0f/3.0f);
295         else                  t = 7.7867f*fval + 16.0f/116.0f;
296         cubeRoot[val] = (short)(t*255.0f*(1L<<TERM_FRAC_BITS) + 0.5f);
297
298         cube[val] = (BYTE)(255.0f*fval*fval*fval);
299         // above, we don't round because we won't reach full black in lab->ycc conv
300
301         // compute ycc<->rgb conversion tables
302
303         fval = (float)val;
304
305         r2y_fix[val] = (short)(SLIGHT_BOOST*RGBTOY_R_FAC*fval*(1<<CONV_FRAC_BITS));
306         g2y_fix[val] = (short)(SLIGHT_BOOST*RGBTOY_G_FAC*fval*(1<<CONV_FRAC_BITS));
307         b2y_fix[val] = (short)(SLIGHT_BOOST*RGBTOY_B_FAC*fval*(1<<CONV_FRAC_BITS));
308
309         fval -= 128.0f;
310
311         cb2b    [val] = (short)(floor(YCCTORGB_CB_TO_B*fval + 0.5));
312         cr2r    [val] = (short)(floor(YCCTORGB_CR_TO_R*fval + 0.5));
313         cb2g_fix[val] = (short)(YCCTORGB_CB_TO_G*fval*(1<<CONV_FRAC_BITS));
314         cr2g_fix[val] = (short)(YCCTORGB_CR_TO_G*fval*(1<<CONV_FRAC_BITS));
315     }
316
317
318     for (val=0; val<=2*255; val++)
319     {
320         fval = (float)val - 255.0f;
321
322         icb = (int)floor(fval/YCCTORGB_CB_TO_B + 0.5);
323         if (icb>=-4 && icb<=4)   // make sure white is white
324            icb = 0;
325         icb += 128;
326         by2cb[val] = (BYTE)CLIP(icb);
327
328         icr = (int)floor(fval/YCCTORGB_CR_TO_R + 0.5);
329         if (icr>=-4 && icr<=4)   // make sure white is white.
330             icr = 0;
331         icr += 128;
332         ry2cr[val] = (BYTE)CLIP(icr);
333     }
334 }
335
336
337
338 static void calcGammaTable (
339     PCOL_INST g,
340     DWORD     dwGamma)   /* Gamma value in 16.16 fixed-point */
341 {
342     #define MAX_GAMMA_SLOPE 4
343
344     int   i;
345     int   maxval;
346     float fGamma, f, gamval;
347     BYTE  bGamVal;
348
349     fGamma = (dwGamma == 0) ? DEFAULT_GAMMA : (float)dwGamma/(1L<<16);
350
351     switch (g->which_cnv) {
352         case IP_CNV_YCC_TO_CIELAB:
353         /* YCC is assumed to have been Gamma corrected. So we must do
354          * inverse Gamma when converting to CIELab
355          */
356         fGamma = 1.0f / fGamma;
357         break;
358
359         case IP_CNV_CIELAB_TO_YCC:
360         /* CIELab has not been Gamma corrected, so we must do forward
361          * Gamma when going to YCC.
362          */
363         break;
364
365         default:
366         /* No Gamma for the other conversions */
367         fGamma = 1.0f;
368     }
369
370     if (fGamma == 1.0f) {
371         /* No gamma correction: use identity table */
372         for (i=0; i<=255; i++)
373             g->bGammaTbl[i] = i;
374     } else {
375         fGamma = 1.0f / fGamma;
376         for (i=0; i<=255; i++) {
377             f = (float)i / 255.0f;
378             gamval = (float)pow(f, fGamma);
379             bGamVal = (BYTE)(255.0f*gamval + 0.5f);
380             maxval = (int)(i * MAX_GAMMA_SLOPE);
381             if (fGamma<1.0f && bGamVal>maxval)
382                 bGamVal = maxval;
383             g->bGammaTbl[i] = bGamVal;
384         }
385     }
386 }
387
388
389
390 /****************************************************************************\
391  ****************************************************************************
392  **                                                                        **
393  **                  YCC -> sRGB   and   YCC -> CIELAB                     **
394  **                                                                        **
395  ****************************************************************************
396 \****************************************************************************/
397
398
399 /*  Table for Molokai (and Wizard, I think) */
400 #if 0
401 static long RGBtoXYZ50[9] = {
402     (long)(0.4358530*X_SCALE*TABLE_FRAC_SCALE + 0.5),
403     (long)(0.3840300*X_SCALE*TABLE_FRAC_SCALE + 0.5),
404     (long)(0.1431260*X_SCALE*TABLE_FRAC_SCALE + 0.5),
405
406     (long)(0.2225640*Y_SCALE*TABLE_FRAC_SCALE + 0.5),
407     (long)(0.7200520*Y_SCALE*TABLE_FRAC_SCALE + 0.5),
408     (long)(0.0607176*Y_SCALE*TABLE_FRAC_SCALE + 0.5),
409
410     (long)(0.0139307*Z_SCALE*TABLE_FRAC_SCALE + 0.5),
411     (long)(0.0973260*Z_SCALE*TABLE_FRAC_SCALE + 0.5),
412     (long)(0.7142870*Z_SCALE*TABLE_FRAC_SCALE + 0.5)
413 };
414 #endif
415
416
417 /*  Table for Polaris and Avalon */
418 #if 1
419 static long RGBtoXYZ50[9] = {
420     (long)(0.464700*X_SCALE*TABLE_FRAC_SCALE + 0.5),
421     (long)(0.339211*X_SCALE*TABLE_FRAC_SCALE + 0.5),
422     (long)(0.156961*X_SCALE*TABLE_FRAC_SCALE + 0.5),
423
424     (long)(0.220615*Y_SCALE*TABLE_FRAC_SCALE + 0.5),
425     (long)(0.700919*Y_SCALE*TABLE_FRAC_SCALE + 0.5),
426     (long)(0.053199*Y_SCALE*TABLE_FRAC_SCALE + 0.5),
427
428     (long)(0.005146*Z_SCALE*TABLE_FRAC_SCALE + 0.5),
429     (long)(0.050405*Z_SCALE*TABLE_FRAC_SCALE + 0.5),
430     (long)(0.774384*Z_SCALE*TABLE_FRAC_SCALE + 0.5)
431 };
432 #endif
433
434
435
436 // YCCToCIELab - Converts a pixel (3 unsigned bytes) from YCC to fax LAB
437 //
438 // Conversions done herein:
439 //    YCC -> sRGB -> inverse Gamma -> XYZ(d65) -> XYZ(d50) -> LAB
440 //    Some of the above steps are combined for speed.
441 //                           
442 static void YCCToCIELab (
443     PBYTE pYCC,      // in:  YCC pixel (3 unsigned bytes)
444     PBYTE pCIELab,   // out: LAB pixel (3 unsigned bytes)
445     PBYTE pGamma)    // in:  inverse Gamma table
446 {
447     int iy, icb,icr;
448     int sR, sG, sB;
449     int sRGBval[3];
450     int XYZ50val[3];
451     int x, y, z;
452     int xterm, yterm, zterm;
453     int L, a, b;
454     int absCr, absCb; //Neutral Shift Purpose
455    
456
457     iy  = pYCC[0];
458     icb = pYCC[1];
459     icr = pYCC[2];
460
461 #ifdef NEUTRAL_SHIFT_SEND
462
463       absCb = abs(icb-128);
464       absCr = abs(icr-128);
465     
466       if (iy>=210)
467     {
468       iy = Send_yTable[iy-210];
469     }
470
471     if (iy ==255)
472     {
473         
474       if ((absCb < 5) && (absCr <5))
475       {
476         icr = icb = 128;
477       }
478     }
479     else if (iy>240)
480     {
481       if ((absCb < 4) && (absCr <4))
482       {
483         icr=icb=128;
484         iy = 255;
485       }
486       else if ((absCb < 3) && (absCr <3))
487       {
488         icr=icb=128;
489       }
490     }
491     else if (iy>230)
492     {         
493       if ((absCb < 3) && (absCr <3))
494       {
495         icr=icb=128;
496         iy = 250;
497       }
498     }
499     else if (iy>220)
500     {
501       if ((absCb < 3) && (absCr <3))
502       {
503         icr=icb=128;
504         iy = 240;
505       }
506     }
507     else if (iy >60)
508     {
509       if ((absCb <3) && (absCr <3))
510       {
511         icr=icb=128;
512       }
513     }
514     
515   #endif
516
517 /* END NEUTRAL SHIFT */
518     // iy=77; icb=85; icr=255;    // solid red
519     // ycc=29,255,107  is  solid blue
520
521
522     /**** Convert YCC to sRGB ****/
523
524     sR = iy + cr2r[icr];
525     sR = CLIP(sR);
526
527     sG = iy + ((cr2g_fix[icr] + cb2g_fix[icb] + CONV_FRAC_ROUND) >> CONV_FRAC_BITS);
528     sG = CLIP(sG);
529
530     sB = iy + cb2b[icb];
531     sB = CLIP(sB);
532
533     /**** Inverse Gamma correction, and Convert sRGB(d65) to XYZ(d50) ****/
534
535     sRGBval[0] = (long)pGamma[sR];
536     sRGBval[1] = (long)pGamma[sG];
537     sRGBval[2] = (long)pGamma[sB];
538
539     VectMult (sRGBval, XYZ50val, RGBtoXYZ50);
540
541     x = CLIP(XYZ50val[0]);
542     y = CLIP(XYZ50val[1]);
543     z = CLIP(XYZ50val[2]);
544
545     /**** Convert XYZ(d50) to fax LAB ****/
546
547     pCIELab[0] = L = YtoL[y];
548     xterm = cubeRoot[x];
549     yterm = cubeRoot[y];
550     zterm = cubeRoot[z];
551
552     b = yterm - zterm;
553     b += (96<<TERM_FRAC_BITS) + (1<<(TERM_FRAC_BITS-1));
554     b >>= TERM_FRAC_BITS;
555     pCIELab[2] = (BYTE)CLIP(b);
556
557     if (b < 0) {  /* todo - adjustment for out-of-gamut bright blue */
558         /* xterm and L factors below of 6,1 -> rgb of 32,31,229     */
559         /* xterm and L factors below of 8,2 -> rgb of 84,80,255     */
560         /* xterm and L factors below of 6,0.5 are visually best     */
561         xterm += 6*b;
562         L -= b>>1;
563         pCIELab[0] = (BYTE)CLIP(L);
564     }
565
566     // a = (long)((1<<10)*500.0/170.0) * (xterm-yterm) >> 10;
567     // the 3*a - a/16 below is close enough to (500.0/170.0)*a
568     a = xterm - yterm;
569     a = a + a + a - (a>>4);  // multiply by approx 500/170
570     a += (128<<TERM_FRAC_BITS) + (1<<(TERM_FRAC_BITS-1));
571     a >>= TERM_FRAC_BITS;
572     pCIELab[1] = (BYTE)CLIP(a);
573 }
574
575
576
577 // YCCTosRGB - Converts a pixel (3 unsigned bytes) from YCC to sRGB
578 //
579 static void YCCTosRGB (
580     PBYTE pYCC,    // in:  YCC  pixel (3 unsigned bytes)
581     PBYTE psRGB)   // out: sRGB pixel (3 unsigned bytes)
582 {
583     int iy, icb, icr;
584     int sR, sG, sB;
585
586     iy  = pYCC[0];
587     icb = pYCC[1];
588     icr = pYCC[2];
589
590     sR = iy + cr2r[icr];
591     psRGB[0] = (BYTE)CLIP(sR);
592
593     sG = iy + ((cr2g_fix[icr] + cb2g_fix[icb] + CONV_FRAC_ROUND) >> CONV_FRAC_BITS);
594     psRGB[1] = (BYTE)CLIP(sG);
595
596     sB = iy + cb2b[icb];
597     psRGB[2] = (BYTE)CLIP(sB);
598 }
599
600
601
602 /****************************************************************************\
603  ****************************************************************************
604  **                                                                        **
605  **                  sRGB -> YCC   and   CIELAB -> YCC                     **
606  **                                                                        **
607  ****************************************************************************
608 \****************************************************************************/
609
610
611 static long XYZ50tosRGB[9] = {
612    (long)( 3.1344500*TABLE_FRAC_SCALE  /* *(255.0/248.0) */  /X_SCALE + 0.5),
613    (long)(-1.6177000*TABLE_FRAC_SCALE  /* *(255.0/248.0) */  /Y_SCALE - 0.5),
614    (long)(-0.4905000*TABLE_FRAC_SCALE  /* *(255.0/248.0) */  /Z_SCALE - 0.5),
615
616    (long)(-0.9788600*TABLE_FRAC_SCALE  /* *(255.0/258.0) */  /X_SCALE - 0.5),
617    (long)( 1.9164800*TABLE_FRAC_SCALE  /* *(255.0/258.0) */  /Y_SCALE + 0.5),
618    (long)( 0.0334962*TABLE_FRAC_SCALE  /* *(255.0/258.0) */  /Z_SCALE + 0.5),
619
620    (long)( 0.0719813*TABLE_FRAC_SCALE  /* *(255.0/254.0) */  /X_SCALE + 0.5),
621    (long)(-0.2290660*TABLE_FRAC_SCALE  /* *(255.0/254.0) */  /Y_SCALE - 0.5),
622    (long)( 1.4050500*TABLE_FRAC_SCALE  /* *(255.0/254.0) */  /Z_SCALE + 0.5)
623 };
624
625
626
627 // CIELabToYCC - Converts a pixel (3 unsigned bytes) from fax LAB to YCC
628 //
629 // Conversions done herein:
630 //    LAB(d50) -> XYZ(d50) -> XYZ(d65) -> sRGB -> Gamma -> YCC
631 //    Some of the above steps are combined for speed.
632 //
633 static void CIELabToYCC (
634     PBYTE pCIELab,   // in:  LAB pixel (3 unsigned bytes)
635     PBYTE pYCC,      // out: YCC pixel (3 unsigned bytes)
636     PBYTE pGamma)    // in:  Gamma table
637 {
638     int   a, b, xterm, yterm, zterm;
639     int   Y;
640     long  factor;
641     int   XYZ50[3];
642     int   sRGB[3];
643     int   sR,sG,sB;
644     int   iy;
645     int   icr, icb;
646
647     /**** LAB -> XYZ, both in d50 ****/
648
649     factor = (long)((1L<<16)*170.0/500.0);
650     a = (int)(((((long)pCIELab[1]-128) * factor) + 0x8000L) >> 16);
651     b = (int)pCIELab[2] - 96;
652
653     XYZ50[1] = Y = LtoY[pCIELab[0]];
654     yterm = (cubeRoot[Y] + (1<<(TERM_FRAC_BITS-1))) >> TERM_FRAC_BITS;
655
656     xterm = a + yterm;
657     XYZ50[0] = cube[CLIP(xterm)];
658
659     zterm = yterm - b;
660     XYZ50[2] = cube[CLIP(zterm)];
661
662     /**** XYZ(d50)->XYZ(d65)->sRGB via 3x3 matrix, then Gamma correct ****/
663
664     VectMult (XYZ50, sRGB, XYZ50tosRGB);
665
666     sR = pGamma[CLIP(sRGB[0])];
667     sG = pGamma[CLIP(sRGB[1])];
668     sB = pGamma[CLIP(sRGB[2])];
669
670     /**** sRGB -> YCC ****/
671
672     iy = r2y_fix[sR] + g2y_fix[sG] + b2y_fix[sB];
673     iy = (iy + CONV_FRAC_ROUND) >> CONV_FRAC_BITS;
674     iy = CLIP(iy);
675
676     //It is done inside the Neutral Shift area
677     //pYCC[0] = (BYTE)iy;
678
679     //pYCC[1] = (by2cb+255)[sB-iy];
680    // pYCC[2] = (ry2cr+255)[sR-iy];
681     icb = (int)((by2cb+255)[sB-iy]); //it is pYCC[1]
682     icr = (int)((ry2cr+255)[sR-iy]); //it is pYCC[2]
683
684   pYCC[0] = (BYTE)iy;
685   pYCC[1] = (BYTE)icb;
686   pYCC[2] = (BYTE)icr;
687
688
689
690 }
691
692
693
694 // sRGBToYCC - Converts a pixel (3 unsigned bytes) from sRGB to YCC
695 //
696 static void sRGBToYCC (
697     PBYTE psRGB,   // in:  sRGB pixel (3 unsigned bytes)
698     PBYTE pYCC)    // out: YCC  pixel (3 unsigned bytes)
699 {
700     int sR, sG, sB;
701     int iy;
702
703     sR = psRGB[0];
704     sG = psRGB[1];
705     sB = psRGB[2];
706
707     iy = r2y_fix[sR] + g2y_fix[sG] + b2y_fix[sB];
708     iy = (iy + CONV_FRAC_ROUND) >> CONV_FRAC_BITS;
709     iy = CLIP(iy);
710     pYCC[0] = (BYTE)iy;
711
712     pYCC[1] = (by2cb+255)[sB-iy];
713     pYCC[2] = (ry2cr+255)[sR-iy];
714 }
715
716
717
718 /****************************************************************************\
719  ****************************************************************************
720  **                                                                        **
721  **                  sRGB -> HLS   and   HLS -> YCC                        **
722  **                                                                        **
723  ****************************************************************************
724 \****************************************************************************/
725
726
727
728 // sRGBToLHS - Converts a pixel (3 unsigned bytes) from sRGB to LHS
729 //
730 static void sRGBToLHS (
731     PBYTE psRGB,   // in:  sRGB pixel (3 unsigned bytes)
732     PBYTE pLHS)    // out: LHS  pixel (3 unsigned bytes)
733 {
734     int R, G, B;
735     int L, H, S;   // these are in 0..255
736     int    maxVal, minVal, diff, sum, numerator;
737
738     R = (unsigned)psRGB[0];
739     G = (unsigned)psRGB[1];
740     B = (unsigned)psRGB[2];
741
742     maxVal = IP_MAX (R, G);
743     maxVal = IP_MAX (maxVal, B);
744     minVal = IP_MIN (R, G);
745     minVal = IP_MIN (minVal, B);
746     diff   = maxVal - minVal;
747     sum    = maxVal + minVal;
748     L      = sum >> 1;
749
750     if (diff <= 1) {
751         S = 0;
752         H = 0;
753     } else {
754         // below is really 255*diff / (...), but avoiding the multiply
755         S = ((diff<<9) - diff - diff) / (L<=127 ? sum : 510-sum);
756         S = (S+1) >> 1;   // round to 8 bits
757             
758         // determine the hue
759         if (R == maxVal) { 
760             numerator = (maxVal-B) - (maxVal-G);
761             H = 0;         // red is at 0 degrees
762         } else if (G == maxVal) { 
763             numerator = (maxVal-R) - (maxVal-B);
764             H = (1<<12)*1/3;   // green is at 120 degrees
765         } else {  // blue-dominant
766             numerator = (maxVal-G) - (maxVal-R);
767             H = (1<<12)*2/3;   // blue is at 240 degrees
768         }
769
770         // The line below is same as:  hue += ((1<<12)/6) * numerator / diff;
771         // but is faster and more accurate.
772         H += (numerator<<11) / (diff+diff+diff);
773         H = (H + (1<<3)) >> 4;   // rounds 12 bits down to 8 bits
774     }
775
776     pLHS[0] = (unsigned char)L;
777     pLHS[1] = (unsigned char)H;
778     pLHS[2] = (unsigned char)S;
779 }
780
781
782
783 // LHSTosRGB - Converts a pixel (3 unsigned bytes) from LHS to sRGB
784 //
785 static void LHSTosRGB (
786     PBYTE pLHS,    // in:  LHS  pixel (3 unsigned bytes)
787     PBYTE psRGB)   // out: sRGB pixel (3 unsigned bytes)
788 {
789     int L, H, S;
790     int R=0, G=0, B=0;
791     int hbase, hfrac, product, maxVal, minVal, midVal;
792
793     L = (unsigned)pLHS[0];   // 1.0 is at 255
794     H = (unsigned)pLHS[1];   // 1.0 is at 255 (which is 360 degrees)
795     S = (unsigned)pLHS[2];   // 1.0 is at 255
796
797     // In RGB_to_HLS, L=sum/2, which truncates.  The average error from this
798     // truncation is 0.25, which is the (1<<4) added below.
799     L = (L<<6) + (1<<4);   // now 1.0 is at 255*(1<<6), 6 bits of frac
800     S = S<<6;
801
802     H *= 6;
803     hbase = H >> 8;       // in 0..5, and is the basic hue
804     hfrac = H & 0x00ff;   // fractional offset from basic hue to next basic hue
805
806     product = L*S;
807     product = (product + (product>>8)) >> (8+6);  // approx division by 255*(1<<6)
808     if (L <= (127<<6)+(1<<4)) maxVal = L + product;
809     else                      maxVal = L + S - product;
810
811     minVal = L + L - maxVal;
812     midVal = minVal + (((maxVal-minVal) * ((hbase&1) ? 256-hfrac : hfrac)) >> 8);
813
814     // round the results to 8 bits by shifting out the 6 frac bits
815     minVal = (minVal+(1<<5)) >> 6;
816     midVal = (midVal+(1<<5)) >> 6;
817     maxVal = (maxVal+(1<<5)) >> 6;
818
819     // I ran this routine with all possible h-l-s values (2^24 of them!), and
820     // none produced a value outside 0..255, so we don't do the checks below.
821     // if (maxVal < 0) maxVal=0; else if (maxVal > 255) maxVal = 255;
822     // if (midVal < 0) midVal=0; else if (midVal > 255) midVal = 255;
823     // if (minVal < 0) minVal=0; else if (minVal > 255) minVal = 255;
824
825     switch (hbase)
826     {
827         case 0:  R = maxVal;  G = midVal;  B = minVal;  break;
828         case 1:  R = midVal;  G = maxVal;  B = minVal;  break;
829         case 2:  R = minVal;  G = maxVal;  B = midVal;  break;
830         case 3:  R = minVal;  G = midVal;  B = maxVal;  break;
831         case 4:  R = midVal;  G = minVal;  B = maxVal;  break;
832         case 5:  R = maxVal;  G = minVal;  B = midVal;  break;
833     }
834
835     psRGB[0] = (BYTE)R;
836     psRGB[1] = (BYTE)G;
837     psRGB[2] = (BYTE)B;
838 }
839
840
841
842 /****************************************************************************\
843  ****************************************************************************
844  **                                                                        **
845  **                      E N T R Y   P O I N T S                           **
846  **                                                                        **
847  ****************************************************************************
848 \****************************************************************************/
849
850
851
852 /*****************************************************************************\
853  *
854  * color_openXform - Creates a new instance of the transformer
855  *
856  *****************************************************************************
857  *
858  * This returns a handle for the new instance to be passed into
859  * all subsequent calls.
860  *
861  * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
862  *
863 \*****************************************************************************/
864
865 static WORD color_openXform (
866     IP_XFORM_HANDLE *pXform)   /* out: returned handle */
867 {
868     PCOL_INST g;
869
870     if (! fInited) {
871         initTables ();
872         fInited = TRUE;
873     }
874
875     INSURE (pXform != NULL);
876     IP_MEM_ALLOC (sizeof(COL_INST), g);
877     *pXform = g;
878     memset (g, 0, sizeof(COL_INST));
879     g->dwValidChk = CHECK_VALUE;
880     return IP_DONE;
881
882     fatal_error:
883     return IP_FATAL_ERROR;
884 }
885
886
887
888 /*****************************************************************************\
889  *
890  * color_setDefaultInputTraits - Specifies default input image traits
891  *
892  *****************************************************************************
893  *
894  * The header of the file-type handled by the transform probably does
895  * not include *all* the image traits we'd like to know.  Those not
896  * specified in the file-header are filled in from info provided by
897  * this routine.
898  *
899  * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
900  *
901 \*****************************************************************************/
902
903 static WORD color_setDefaultInputTraits (
904     IP_XFORM_HANDLE  hXform,     /* in: handle for xform */
905     PIP_IMAGE_TRAITS pTraits)    /* in: default image traits */
906 {
907     PCOL_INST g;
908
909     HANDLE_TO_PTR (hXform, g);
910
911     /* Insure that values we care about are correct */
912     INSURE (pTraits->iBitsPerPixel <= 24);
913     INSURE (pTraits->iPixelsPerRow > 0);
914
915     g->traits = *pTraits;   /* a structure copy */
916     return IP_DONE;
917
918     fatal_error:
919     return IP_FATAL_ERROR;
920 }
921
922
923
924 /*****************************************************************************\
925  *
926  * color_setXformSpec - Provides xform-specific information
927  *
928 \*****************************************************************************/
929
930 static WORD color_setXformSpec (
931     IP_XFORM_HANDLE hXform,         /* in: handle for xform */
932     DWORD_OR_PVOID  aXformInfo[])   /* in: xform information */
933 {
934     PCOL_INST g;
935
936     HANDLE_TO_PTR (hXform, g);
937     g->which_cnv = (IP_WHICH_CNV)aXformInfo[IP_CNV_COLOR_SPACE_WHICH_CNV].dword;
938     calcGammaTable (g, aXformInfo[IP_CNV_COLOR_SPACE_GAMMA].dword);
939
940     return IP_DONE;
941
942     fatal_error:
943     return IP_FATAL_ERROR;
944 }
945
946
947
948 /*****************************************************************************\
949  *
950  * color_getHeaderBufSize- Returns size of input buf needed to hold header
951  *
952 \*****************************************************************************/
953
954 static WORD color_getHeaderBufSize (
955     IP_XFORM_HANDLE  hXform,          /* in:  handle for xform */
956     DWORD           *pdwInBufLen)     /* out: buf size for parsing header */
957 {
958     /* since input is raw pixels, there is no header, so set it to zero */
959     *pdwInBufLen = 0;
960     return IP_DONE;
961 }
962
963
964
965 /*****************************************************************************\
966  *
967  * color_getActualTraits - Parses header, and returns input & output traits
968  *
969 \*****************************************************************************/
970
971 static WORD color_getActualTraits (
972     IP_XFORM_HANDLE  hXform,          /* in:  handle for xform */
973     DWORD            dwInputAvail,    /* in:  # avail bytes in input buf */
974     PBYTE            pbInputBuf,      /* in:  ptr to input buffer */
975     PDWORD           pdwInputUsed,    /* out: # bytes used from input buf */
976     PDWORD           pdwInputNextPos, /* out: file-pos to read from next */
977     PIP_IMAGE_TRAITS pIntraits,       /* out: input image traits */
978     PIP_IMAGE_TRAITS pOutTraits)      /* out: output image traits */
979 {
980     PCOL_INST g;
981
982     HANDLE_TO_PTR (hXform, g);
983
984     /* Since there is no header, we'll report no usage of input */
985     *pdwInputUsed    = 0;
986     *pdwInputNextPos = 0;
987
988     *pIntraits  = g->traits;   /* structure copies */
989     *pOutTraits = g->traits;
990
991     return IP_DONE | IP_READY_FOR_DATA;
992
993     fatal_error:
994     return IP_FATAL_ERROR;
995 }
996
997
998
999 /****************************************************************************\
1000  *
1001  * color_getActualBufSizes - Returns buf sizes needed for remainder of job
1002  *
1003 \****************************************************************************/
1004
1005 static WORD color_getActualBufSizes (
1006     IP_XFORM_HANDLE hXform,           /* in:  handle for xform */
1007     PDWORD          pdwMinInBufLen,   /* out: min input buf size */
1008     PDWORD          pdwMinOutBufLen)  /* out: min output buf size */
1009 {
1010     PCOL_INST g;
1011
1012     HANDLE_TO_PTR (hXform, g);
1013     *pdwMinInBufLen = *pdwMinOutBufLen =
1014         (g->traits.iPixelsPerRow*g->traits.iBitsPerPixel + 7) / 8;
1015     return IP_DONE;
1016
1017     fatal_error:
1018     return IP_FATAL_ERROR;
1019 }
1020
1021
1022
1023 /*****************************************************************************\
1024  *
1025  * color_convert - Converts one row
1026  *
1027 \*****************************************************************************/
1028
1029 static WORD color_convert (
1030     IP_XFORM_HANDLE hXform,
1031     DWORD           dwInputAvail,     /* in:  # avail bytes in in-buf */
1032     PBYTE           pbInputBuf,       /* in:  ptr to in-buffer */
1033     PDWORD          pdwInputUsed,     /* out: # bytes used from in-buf */
1034     PDWORD          pdwInputNextPos,  /* out: file-pos to read from next */
1035     DWORD           dwOutputAvail,    /* in:  # avail bytes in out-buf */
1036     PBYTE           pbOutputBuf,      /* in:  ptr to out-buffer */
1037     PDWORD          pdwOutputUsed,    /* out: # bytes written in out-buf */
1038     PDWORD          pdwOutputThisPos) /* out: file-pos to write the data */
1039 {
1040     PCOL_INST g;
1041     int       nBytes;
1042     PBYTE     pIn, pOut, pOutAfter;
1043
1044     HANDLE_TO_PTR (hXform, g);
1045
1046     /**** Check if we were told to flush ****/
1047
1048     if (pbInputBuf == NULL) {
1049         PRINT (_T("color_convert: Told to flush.\n"), 0, 0);
1050         *pdwInputUsed = *pdwOutputUsed = 0;
1051         *pdwInputNextPos  = g->dwInNextPos;
1052         *pdwOutputThisPos = g->dwOutNextPos;
1053         return IP_DONE;
1054     }
1055
1056     /**** Output a Row ****/
1057
1058     nBytes = (g->traits.iPixelsPerRow*g->traits.iBitsPerPixel + 7) / 8;
1059     INSURE (dwInputAvail  >= (DWORD)nBytes );
1060     INSURE (dwOutputAvail >= (DWORD)nBytes);
1061
1062     pIn  = pbInputBuf;
1063     pOut = pbOutputBuf;
1064     pOutAfter = pOut + nBytes;
1065
1066     if (g->traits.iBitsPerPixel < 24) {
1067         /* grayscale data; pass through unchanged */
1068         memcpy (pOut, pIn, nBytes);
1069     } else if (g->which_cnv == IP_CNV_BGR_SWAP) {
1070         while (pOut < pOutAfter) {
1071             pOut[0] = pIn[2];
1072             pOut[1] = pIn[1];
1073             pOut[2] = pIn[0];
1074             pIn  += 3;
1075             pOut += 3;
1076         }
1077     } else {
1078         while (pOut < pOutAfter) {
1079             switch (g->which_cnv) {
1080                 case IP_CNV_YCC_TO_CIELAB: YCCToCIELab (pIn, pOut, g->bGammaTbl);  break;
1081                 case IP_CNV_CIELAB_TO_YCC: CIELabToYCC (pIn, pOut, g->bGammaTbl);  break;
1082                 case IP_CNV_YCC_TO_SRGB:   YCCTosRGB   (pIn, pOut);                break;
1083                 case IP_CNV_SRGB_TO_YCC:   sRGBToYCC   (pIn, pOut);                break;
1084                 case IP_CNV_LHS_TO_SRGB:   LHSTosRGB   (pIn, pOut);                break;
1085                 case IP_CNV_SRGB_TO_LHS:   sRGBToLHS   (pIn, pOut);                break;
1086                 default:                   goto fatal_error;
1087             }
1088
1089             pIn  += 3;
1090             pOut += 3;
1091         }
1092     }
1093
1094     *pdwInputUsed     = nBytes;
1095     g->dwInNextPos   += nBytes;
1096     *pdwInputNextPos  = g->dwInNextPos;
1097
1098     *pdwOutputUsed    = nBytes;
1099     *pdwOutputThisPos = g->dwOutNextPos;
1100     g->dwOutNextPos  += nBytes;
1101
1102     g->dwRowsDone += 1;
1103
1104     return IP_CONSUMED_ROW | IP_PRODUCED_ROW | IP_READY_FOR_DATA;
1105
1106     fatal_error:
1107     return IP_FATAL_ERROR;
1108 }
1109
1110
1111
1112 /*****************************************************************************\
1113  *
1114  * color_insertedData - client inserted into our output stream
1115  *
1116 \*****************************************************************************/
1117
1118 static WORD color_insertedData (
1119     IP_XFORM_HANDLE hXform,
1120     DWORD           dwNumBytes)
1121 {
1122     fatalBreakPoint ();
1123     return IP_FATAL_ERROR;   /* must never be called (can't insert data) */
1124 }
1125
1126
1127
1128 /*****************************************************************************\
1129  *
1130  * color_newPage - Tells us to flush this page, and start a new page
1131  *
1132 \*****************************************************************************/
1133
1134 static WORD color_newPage (
1135     IP_XFORM_HANDLE hXform)
1136 {
1137     PCOL_INST g;
1138
1139     HANDLE_TO_PTR (hXform, g);
1140     return IP_DONE;   /* can't insert page-breaks, so ignore this call */
1141
1142     fatal_error:
1143     return IP_FATAL_ERROR;
1144
1145 }
1146
1147
1148
1149 /*****************************************************************************\
1150  *
1151  * color_closeXform - Destroys this instance
1152  *
1153 \*****************************************************************************/
1154
1155 static WORD color_closeXform (IP_XFORM_HANDLE hXform)
1156 {
1157     PCOL_INST g;
1158
1159     HANDLE_TO_PTR (hXform, g);
1160
1161     g->dwValidChk = 0;
1162     IP_MEM_FREE (g);       /* free memory for the instance */
1163
1164     return IP_DONE;
1165
1166     fatal_error:
1167     return IP_FATAL_ERROR;
1168 }
1169
1170
1171
1172 /*****************************************************************************\
1173  *
1174  * colorTbl - Jump-table for transform driver
1175  *
1176 \*****************************************************************************/
1177
1178 IP_XFORM_TBL colorTbl = {
1179     color_openXform,
1180     color_setDefaultInputTraits,
1181     color_setXformSpec,
1182     color_getHeaderBufSize,
1183     color_getActualTraits,
1184     color_getActualBufSizes,
1185     color_convert,
1186     color_newPage,
1187     color_insertedData,
1188     color_closeXform
1189 };
1190
1191 /* End of File */