1 /* libhpojip -- HP OfficeJet image-processing library. */
3 /* Copyright (C) 1995-2002 Hewlett-Packard Company
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.
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.
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,
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.
32 /* Original author: Mark Overton and others.
34 * Ported to Linux by David Paschal.
37 /******************************************************************************\
39 * xcolrspc.c - Converts between color spaces
41 ******************************************************************************
43 * Name of Global Jump-Table:
47 * Items in aXformInfo array passed into setXformSpec:
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
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
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.
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.
73 * Capabilities and Limitations:
75 * Does the space conversions listed above. Conversions will only be done on
76 * 24-bit data; monochrome data are passed through unchanged.
78 * Default Input Traits, and Output Traits:
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
91 * Above, a "*" by an item indicates it must be valid (not negative).
93 * Feb 1998 Mark Overton -- wrote original code, with dummy conversions
94 * Apr 1998 Mark Overton -- added actual conversion code, adapted from
97 \******************************************************************************/
99 #include "math.h" // needed for pow and floor
102 #include "string.h" /* for memset and memcpy */
105 /* xsc_clean[Uu]p.h: */
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,
117 /* end xsc_clean[Uu]p.h */
123 #define PRINT(msg,arg1,arg2) \
124 _ftprintf(stderr, msg, (int)arg1, (int)arg2)
126 #define PRINT(msg,arg1,arg2)
129 #define CHECK_VALUE 0x4ba1dace
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;
142 static BOOL fInited = FALSE;
144 //Neutral Shift Data Definition
145 #define NEUTRAL_SHIFT_SEND TRUE
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
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
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.
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
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
178 #define X_SCALE (255.0/244.0)
179 #define Y_SCALE (255.0/255.0)
180 #define Z_SCALE (255.0/210.0)
182 #define DEFAULT_GAMMA 2.2f
183 #define SLIGHT_BOOST (255.0/253.0) // todo - get rid of this
186 /****************************************************************************\
187 ****************************************************************************
189 ** W O R K E R R O U T I N E S **
191 ****************************************************************************
192 \****************************************************************************/
196 #define CLIP(wilma) ((wilma>255) ? 255 : ((wilma<0) ? 0 : (wilma)))
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)
205 // these tables are computed by initTables
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];
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];
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];
221 static BYTE by2cb [2*256]; // these are for [r,g,b]->CbCr
222 static BYTE ry2cr [2*256];
226 // VectMult - Multiplies a pixel by a 3x3 matrix, with fixed-point math
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
235 for (i=0; i<3; i++) {
236 outPixel[i] = (int)( pMat[0]*inPixel[0] +
238 pMat[2]*inPixel[2] + (1L<<(TBL33_FRAC_BITS-1))
239 ) >> TBL33_FRAC_BITS;
246 // initTables - Computes look-up tables
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
256 // Na = 255/170 x a* + 128
257 // Nb = 255/200 x b* + 96
260 static void initTables (void)
267 for (val=0; val<=255; val++)
269 fval = (float)val / 255.0f;
271 // compute Y->L array
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);
280 // compute L->Y array
283 t = val * (100.0f/903.3f);
285 t = (fval*100.0f+16.0f) / 116.0f;
288 LtoY[val] = (BYTE)(t + 0.5f);
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.
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);
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
301 // compute ycc<->rgb conversion tables
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));
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));
318 for (val=0; val<=2*255; val++)
320 fval = (float)val - 255.0f;
322 icb = (int)floor(fval/YCCTORGB_CB_TO_B + 0.5);
323 if (icb>=-4 && icb<=4) // make sure white is white
326 by2cb[val] = (BYTE)CLIP(icb);
328 icr = (int)floor(fval/YCCTORGB_CR_TO_R + 0.5);
329 if (icr>=-4 && icr<=4) // make sure white is white.
332 ry2cr[val] = (BYTE)CLIP(icr);
338 static void calcGammaTable (
340 DWORD dwGamma) /* Gamma value in 16.16 fixed-point */
342 #define MAX_GAMMA_SLOPE 4
346 float fGamma, f, gamval;
349 fGamma = (dwGamma == 0) ? DEFAULT_GAMMA : (float)dwGamma/(1L<<16);
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
356 fGamma = 1.0f / fGamma;
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.
366 /* No Gamma for the other conversions */
370 if (fGamma == 1.0f) {
371 /* No gamma correction: use identity table */
372 for (i=0; i<=255; i++)
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)
383 g->bGammaTbl[i] = bGamVal;
390 /****************************************************************************\
391 ****************************************************************************
393 ** YCC -> sRGB and YCC -> CIELAB **
395 ****************************************************************************
396 \****************************************************************************/
399 /* Table for Molokai (and Wizard, I think) */
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),
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),
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)
417 /* Table for Polaris and Avalon */
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),
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),
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)
436 // YCCToCIELab - Converts a pixel (3 unsigned bytes) from YCC to fax LAB
438 // Conversions done herein:
439 // YCC -> sRGB -> inverse Gamma -> XYZ(d65) -> XYZ(d50) -> LAB
440 // Some of the above steps are combined for speed.
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
452 int xterm, yterm, zterm;
454 int absCr, absCb; //Neutral Shift Purpose
461 #ifdef NEUTRAL_SHIFT_SEND
463 absCb = abs(icb-128);
464 absCr = abs(icr-128);
468 iy = Send_yTable[iy-210];
474 if ((absCb < 5) && (absCr <5))
481 if ((absCb < 4) && (absCr <4))
486 else if ((absCb < 3) && (absCr <3))
493 if ((absCb < 3) && (absCr <3))
501 if ((absCb < 3) && (absCr <3))
509 if ((absCb <3) && (absCr <3))
517 /* END NEUTRAL SHIFT */
518 // iy=77; icb=85; icr=255; // solid red
519 // ycc=29,255,107 is solid blue
522 /**** Convert YCC to sRGB ****/
527 sG = iy + ((cr2g_fix[icr] + cb2g_fix[icb] + CONV_FRAC_ROUND) >> CONV_FRAC_BITS);
533 /**** Inverse Gamma correction, and Convert sRGB(d65) to XYZ(d50) ****/
535 sRGBval[0] = (long)pGamma[sR];
536 sRGBval[1] = (long)pGamma[sG];
537 sRGBval[2] = (long)pGamma[sB];
539 VectMult (sRGBval, XYZ50val, RGBtoXYZ50);
541 x = CLIP(XYZ50val[0]);
542 y = CLIP(XYZ50val[1]);
543 z = CLIP(XYZ50val[2]);
545 /**** Convert XYZ(d50) to fax LAB ****/
547 pCIELab[0] = L = YtoL[y];
553 b += (96<<TERM_FRAC_BITS) + (1<<(TERM_FRAC_BITS-1));
554 b >>= TERM_FRAC_BITS;
555 pCIELab[2] = (BYTE)CLIP(b);
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 */
563 pCIELab[0] = (BYTE)CLIP(L);
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
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);
577 // YCCTosRGB - Converts a pixel (3 unsigned bytes) from YCC to sRGB
579 static void YCCTosRGB (
580 PBYTE pYCC, // in: YCC pixel (3 unsigned bytes)
581 PBYTE psRGB) // out: sRGB pixel (3 unsigned bytes)
591 psRGB[0] = (BYTE)CLIP(sR);
593 sG = iy + ((cr2g_fix[icr] + cb2g_fix[icb] + CONV_FRAC_ROUND) >> CONV_FRAC_BITS);
594 psRGB[1] = (BYTE)CLIP(sG);
597 psRGB[2] = (BYTE)CLIP(sB);
602 /****************************************************************************\
603 ****************************************************************************
605 ** sRGB -> YCC and CIELAB -> YCC **
607 ****************************************************************************
608 \****************************************************************************/
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),
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),
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)
627 // CIELabToYCC - Converts a pixel (3 unsigned bytes) from fax LAB to YCC
629 // Conversions done herein:
630 // LAB(d50) -> XYZ(d50) -> XYZ(d65) -> sRGB -> Gamma -> YCC
631 // Some of the above steps are combined for speed.
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
638 int a, b, xterm, yterm, zterm;
647 /**** LAB -> XYZ, both in d50 ****/
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;
653 XYZ50[1] = Y = LtoY[pCIELab[0]];
654 yterm = (cubeRoot[Y] + (1<<(TERM_FRAC_BITS-1))) >> TERM_FRAC_BITS;
657 XYZ50[0] = cube[CLIP(xterm)];
660 XYZ50[2] = cube[CLIP(zterm)];
662 /**** XYZ(d50)->XYZ(d65)->sRGB via 3x3 matrix, then Gamma correct ****/
664 VectMult (XYZ50, sRGB, XYZ50tosRGB);
666 sR = pGamma[CLIP(sRGB[0])];
667 sG = pGamma[CLIP(sRGB[1])];
668 sB = pGamma[CLIP(sRGB[2])];
670 /**** sRGB -> YCC ****/
672 iy = r2y_fix[sR] + g2y_fix[sG] + b2y_fix[sB];
673 iy = (iy + CONV_FRAC_ROUND) >> CONV_FRAC_BITS;
676 //It is done inside the Neutral Shift area
677 //pYCC[0] = (BYTE)iy;
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]
694 // sRGBToYCC - Converts a pixel (3 unsigned bytes) from sRGB to YCC
696 static void sRGBToYCC (
697 PBYTE psRGB, // in: sRGB pixel (3 unsigned bytes)
698 PBYTE pYCC) // out: YCC pixel (3 unsigned bytes)
707 iy = r2y_fix[sR] + g2y_fix[sG] + b2y_fix[sB];
708 iy = (iy + CONV_FRAC_ROUND) >> CONV_FRAC_BITS;
712 pYCC[1] = (by2cb+255)[sB-iy];
713 pYCC[2] = (ry2cr+255)[sR-iy];
718 /****************************************************************************\
719 ****************************************************************************
721 ** sRGB -> HLS and HLS -> YCC **
723 ****************************************************************************
724 \****************************************************************************/
728 // sRGBToLHS - Converts a pixel (3 unsigned bytes) from sRGB to LHS
730 static void sRGBToLHS (
731 PBYTE psRGB, // in: sRGB pixel (3 unsigned bytes)
732 PBYTE pLHS) // out: LHS pixel (3 unsigned bytes)
735 int L, H, S; // these are in 0..255
736 int maxVal, minVal, diff, sum, numerator;
738 R = (unsigned)psRGB[0];
739 G = (unsigned)psRGB[1];
740 B = (unsigned)psRGB[2];
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;
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
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
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
776 pLHS[0] = (unsigned char)L;
777 pLHS[1] = (unsigned char)H;
778 pLHS[2] = (unsigned char)S;
783 // LHSTosRGB - Converts a pixel (3 unsigned bytes) from LHS to sRGB
785 static void LHSTosRGB (
786 PBYTE pLHS, // in: LHS pixel (3 unsigned bytes)
787 PBYTE psRGB) // out: sRGB pixel (3 unsigned bytes)
791 int hbase, hfrac, product, maxVal, minVal, midVal;
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
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
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
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;
811 minVal = L + L - maxVal;
812 midVal = minVal + (((maxVal-minVal) * ((hbase&1) ? 256-hfrac : hfrac)) >> 8);
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;
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;
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;
842 /****************************************************************************\
843 ****************************************************************************
845 ** E N T R Y P O I N T S **
847 ****************************************************************************
848 \****************************************************************************/
852 /*****************************************************************************\
854 * color_openXform - Creates a new instance of the transformer
856 *****************************************************************************
858 * This returns a handle for the new instance to be passed into
859 * all subsequent calls.
861 * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
863 \*****************************************************************************/
865 static WORD color_openXform (
866 IP_XFORM_HANDLE *pXform) /* out: returned handle */
875 INSURE (pXform != NULL);
876 IP_MEM_ALLOC (sizeof(COL_INST), g);
878 memset (g, 0, sizeof(COL_INST));
879 g->dwValidChk = CHECK_VALUE;
883 return IP_FATAL_ERROR;
888 /*****************************************************************************\
890 * color_setDefaultInputTraits - Specifies default input image traits
892 *****************************************************************************
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
899 * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
901 \*****************************************************************************/
903 static WORD color_setDefaultInputTraits (
904 IP_XFORM_HANDLE hXform, /* in: handle for xform */
905 PIP_IMAGE_TRAITS pTraits) /* in: default image traits */
909 HANDLE_TO_PTR (hXform, g);
911 /* Insure that values we care about are correct */
912 INSURE (pTraits->iBitsPerPixel <= 24);
913 INSURE (pTraits->iPixelsPerRow > 0);
915 g->traits = *pTraits; /* a structure copy */
919 return IP_FATAL_ERROR;
924 /*****************************************************************************\
926 * color_setXformSpec - Provides xform-specific information
928 \*****************************************************************************/
930 static WORD color_setXformSpec (
931 IP_XFORM_HANDLE hXform, /* in: handle for xform */
932 DWORD_OR_PVOID aXformInfo[]) /* in: xform information */
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);
943 return IP_FATAL_ERROR;
948 /*****************************************************************************\
950 * color_getHeaderBufSize- Returns size of input buf needed to hold header
952 \*****************************************************************************/
954 static WORD color_getHeaderBufSize (
955 IP_XFORM_HANDLE hXform, /* in: handle for xform */
956 DWORD *pdwInBufLen) /* out: buf size for parsing header */
958 /* since input is raw pixels, there is no header, so set it to zero */
965 /*****************************************************************************\
967 * color_getActualTraits - Parses header, and returns input & output traits
969 \*****************************************************************************/
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 */
982 HANDLE_TO_PTR (hXform, g);
984 /* Since there is no header, we'll report no usage of input */
986 *pdwInputNextPos = 0;
988 *pIntraits = g->traits; /* structure copies */
989 *pOutTraits = g->traits;
991 return IP_DONE | IP_READY_FOR_DATA;
994 return IP_FATAL_ERROR;
999 /****************************************************************************\
1001 * color_getActualBufSizes - Returns buf sizes needed for remainder of job
1003 \****************************************************************************/
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 */
1012 HANDLE_TO_PTR (hXform, g);
1013 *pdwMinInBufLen = *pdwMinOutBufLen =
1014 (g->traits.iPixelsPerRow*g->traits.iBitsPerPixel + 7) / 8;
1018 return IP_FATAL_ERROR;
1023 /*****************************************************************************\
1025 * color_convert - Converts one row
1027 \*****************************************************************************/
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 */
1042 PBYTE pIn, pOut, pOutAfter;
1044 HANDLE_TO_PTR (hXform, g);
1046 /**** Check if we were told to flush ****/
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;
1056 /**** Output a Row ****/
1058 nBytes = (g->traits.iPixelsPerRow*g->traits.iBitsPerPixel + 7) / 8;
1059 INSURE (dwInputAvail >= (DWORD)nBytes );
1060 INSURE (dwOutputAvail >= (DWORD)nBytes);
1064 pOutAfter = pOut + nBytes;
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) {
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;
1094 *pdwInputUsed = nBytes;
1095 g->dwInNextPos += nBytes;
1096 *pdwInputNextPos = g->dwInNextPos;
1098 *pdwOutputUsed = nBytes;
1099 *pdwOutputThisPos = g->dwOutNextPos;
1100 g->dwOutNextPos += nBytes;
1104 return IP_CONSUMED_ROW | IP_PRODUCED_ROW | IP_READY_FOR_DATA;
1107 return IP_FATAL_ERROR;
1112 /*****************************************************************************\
1114 * color_insertedData - client inserted into our output stream
1116 \*****************************************************************************/
1118 static WORD color_insertedData (
1119 IP_XFORM_HANDLE hXform,
1123 return IP_FATAL_ERROR; /* must never be called (can't insert data) */
1128 /*****************************************************************************\
1130 * color_newPage - Tells us to flush this page, and start a new page
1132 \*****************************************************************************/
1134 static WORD color_newPage (
1135 IP_XFORM_HANDLE hXform)
1139 HANDLE_TO_PTR (hXform, g);
1140 return IP_DONE; /* can't insert page-breaks, so ignore this call */
1143 return IP_FATAL_ERROR;
1149 /*****************************************************************************\
1151 * color_closeXform - Destroys this instance
1153 \*****************************************************************************/
1155 static WORD color_closeXform (IP_XFORM_HANDLE hXform)
1159 HANDLE_TO_PTR (hXform, g);
1162 IP_MEM_FREE (g); /* free memory for the instance */
1167 return IP_FATAL_ERROR;
1172 /*****************************************************************************\
1174 * colorTbl - Jump-table for transform driver
1176 \*****************************************************************************/
1178 IP_XFORM_TBL colorTbl = {
1180 color_setDefaultInputTraits,
1182 color_getHeaderBufSize,
1183 color_getActualTraits,
1184 color_getActualBufSizes,