blob: 4ad975550c3a42ada54ce1e7b6688487dc8a99fc [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3 *
4 * This code is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 only, as
6 * published by the Free Software Foundation. Sun designates this
7 * particular file as subject to the "Classpath" exception as provided
8 * by Sun in the LICENSE file that accompanied this code.
9 *
10 * This code is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 2 along with this work; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21 * CA 95054 USA or visit www.sun.com if you need additional information or
22 * have any questions.
23 */
24
25// This file is available under and governed by the GNU General Public
26// License version 2 only, as published by the Free Software Foundation.
27// However, the following notice accompanied the original version of this
28// file:
29//
30//
31// Little cms
32// Copyright (C) 1998-2006 Marti Maria
33//
34// Permission is hereby granted, free of charge, to any person obtaining
35// a copy of this software and associated documentation files (the "Software"),
36// to deal in the Software without restriction, including without limitation
37// the rights to use, copy, modify, merge, publish, distribute, sublicense,
38// and/or sell copies of the Software, and to permit persons to whom the Software
39// is furnished to do so, subject to the following conditions:
40//
41// The above copyright notice and this permission notice shall be included in
42// all copies or substantial portions of the Software.
43//
44// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
45// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
46// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
47// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
48// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
49// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
50// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
51
52// inter PCS conversions XYZ <-> CIE L* a* b*
53
54#include "lcms.h"
55
56/*
57
58
59 CIE 15:2004 CIELab is defined as:
60
61 L* = 116*f(Y/Yn) - 16 0 <= L* <= 100
62 a* = 500*[f(X/Xn) - f(Y/Yn)]
63 b* = 200*[f(Y/Yn) - f(Z/Zn)]
64
65 and
66
67 f(t) = t^(1/3) 1 >= t > (24/116)^3
68 (841/108)*t + (16/116) 0 <= t <= (24/116)^3
69
70
71 Reverse transform is:
72
73 X = Xn*[a* / 500 + (L* + 16) / 116] ^ 3 if (X/Xn) > (24/116)
74 = Xn*(a* / 500 + L* / 116) / 7.787 if (X/Xn) <= (24/116)
75
76
77
78 Following ICC. PCS in Lab is coded as:
79
80 8 bit Lab PCS:
81
82 L* 0..100 into a 0..ff byte.
83 a* t + 128 range is -128.0 +127.0
84 b*
85
86 16 bit Lab PCS:
87
88 L* 0..100 into a 0..ff00 word.
89 a* t + 128 range is -128.0 +127.9961
90 b*
91
92
93 We are always playing with 16 bits-data, so I will ignore the
94 8-bits encoding scheme.
95
96
97Interchange Space Component Actual Range Encoded Range
98CIE XYZ X 0 -> 1.99997 0x0000 -> 0xffff
99CIE XYZ Y 0 -> 1.99997 0x0000 -> 0xffff
100CIE XYZ Z 0 -> 1.99997 0x0000 -> 0xffff
101
102Version 2,3
103-----------
104
105CIELAB (16 bit) L* 0 -> 100.0 0x0000 -> 0xff00
106CIELAB (16 bit) a* -128.0 -> +127.996 0x0000 -> 0x8000 -> 0xffff
107CIELAB (16 bit) b* -128.0 -> +127.996 0x0000 -> 0x8000 -> 0xffff
108
109
110Version 4
111---------
112
113CIELAB (16 bit) L* 0 -> 100.0 0x0000 -> 0xffff
114CIELAB (16 bit) a* -128.0 -> +127 0x0000 -> 0x8080 -> 0xffff
115CIELAB (16 bit) b* -128.0 -> +127 0x0000 -> 0x8080 -> 0xffff
116
117*/
118
119
120
121
122// On most modern computers, D > 4 M (i.e. a division takes more than 4
123// multiplications worth of time), so it is probably preferable to compute
124// a 24 bit result directly.
125
126// #define ITERATE 1
127
128static
129float CubeRoot(float x)
130{
131 float fr, r;
132 int ex, shx;
133
134 /* Argument reduction */
135 fr = (float) frexp(x, &ex); /* separate into mantissa and exponent */
136 shx = ex % 3;
137
138 if (shx > 0)
139 shx -= 3; /* compute shx such that (ex - shx) is divisible by 3 */
140
141 ex = (ex - shx) / 3; /* exponent of cube root */
142 fr = (float) ldexp(fr, shx);
143
144 /* 0.125 <= fr < 1.0 */
145
146#ifdef ITERATE
147 /* Compute seed with a quadratic approximation */
148
149 fr = (-0.46946116F * fr + 1.072302F) * fr + 0.3812513F;/* 0.5<=fr<1 */
150 r = ldexp(fr, ex); /* 6 bits of precision */
151
152 /* Newton-Raphson iterations */
153
154 r = (float)(2.0/3.0) * r + (float)(1.0/3.0) * x / (r * r); /* 12 bits */
155 r = (float)(2.0/3.0) * r + (float)(1.0/3.0) * x / (r * r); /* 24 bits */
156#else /* ITERATE */
157
158 /* Use quartic rational polynomial with error < 2^(-24) */
159
160 fr = (float) (((((45.2548339756803022511987494 * fr +
161 192.2798368355061050458134625) * fr +
162 119.1654824285581628956914143) * fr +
163 13.43250139086239872172837314) * fr +
164 0.1636161226585754240958355063)
165 /
166 ((((14.80884093219134573786480845 * fr +
167 151.9714051044435648658557668) * fr +
168 168.5254414101568283957668343) * fr +
169 33.9905941350215598754191872) * fr +
170 1.0));
171 r = (float) ldexp(fr, ex); /* 24 bits of precision */
172#endif
173 return r;
174}
175
176static
177double f(double t)
178{
179
180 const double Limit = (24.0/116.0) * (24.0/116.0) * (24.0/116.0);
181
182 if (t <= Limit)
183 return (841.0/108.0) * t + (16.0/116.0);
184 else
185 return CubeRoot((float) t);
186}
187
188
189static
190double f_1(double t)
191{
192 const double Limit = (24.0/116.0);
193
194 if (t <= Limit)
195 {
196 double tmp;
197
198 tmp = (108.0/841.0) * (t - (16.0/116.0));
199 if (tmp <= 0.0) return 0.0;
200 else return tmp;
201 }
202
203 return t * t * t;
204}
205
206
207
208void LCMSEXPORT cmsXYZ2Lab(LPcmsCIEXYZ WhitePoint, LPcmsCIELab Lab, const cmsCIEXYZ* xyz)
209{
210 double fx, fy, fz;
211
212 if (xyz -> X == 0 && xyz -> Y == 0 && xyz -> Z == 0)
213 {
214 Lab -> L = 0;
215 Lab -> a = 0;
216 Lab -> b = 0;
217 return;
218 }
219
220 if (WhitePoint == NULL)
221 WhitePoint = cmsD50_XYZ();
222
223 fx = f(xyz->X / WhitePoint->X);
224 fy = f(xyz->Y / WhitePoint->Y);
225 fz = f(xyz->Z / WhitePoint->Z);
226
227 Lab->L = 116.0* fy - 16.;
228
229 Lab->a = 500.0*(fx - fy);
230 Lab->b = 200.0*(fy - fz);
231}
232
233
234
235void cmsXYZ2LabEncoded(WORD XYZ[3], WORD Lab[3])
236{
237 Fixed32 X, Y, Z;
238 double x, y, z, L, a, b;
239 double fx, fy, fz;
240 Fixed32 wL, wa, wb;
241
242 X = (Fixed32) XYZ[0] << 1;
243 Y = (Fixed32) XYZ[1] << 1;
244 Z = (Fixed32) XYZ[2] << 1;
245
246
247 if (X==0 && Y==0 && Z==0) {
248
249 Lab[0] = 0;
250 Lab[1] = Lab[2] = 0x8000;
251 return;
252 }
253
254 // PCS is in D50
255
256
257 x = FIXED_TO_DOUBLE(X) / D50X;
258 y = FIXED_TO_DOUBLE(Y) / D50Y;
259 z = FIXED_TO_DOUBLE(Z) / D50Z;
260
261
262 fx = f(x);
263 fy = f(y);
264 fz = f(z);
265
266 L = 116.* fy - 16.;
267
268 a = 500.*(fx - fy);
269 b = 200.*(fy - fz);
270
271 a += 128.;
272 b += 128.;
273
274 wL = (int) (L * 652.800 + .5);
275 wa = (int) (a * 256.0 + .5);
276 wb = (int) (b * 256.0 + .5);
277
278
279 Lab[0] = Clamp_L(wL);
280 Lab[1] = Clamp_ab(wa);
281 Lab[2] = Clamp_ab(wb);
282
283
284}
285
286
287
288
289
290
291void LCMSEXPORT cmsLab2XYZ(LPcmsCIEXYZ WhitePoint, LPcmsCIEXYZ xyz, const cmsCIELab* Lab)
292{
293 double x, y, z;
294
295 if (Lab -> L <= 0) {
296 xyz -> X = 0;
297 xyz -> Y = 0;
298 xyz -> Z = 0;
299 return;
300 }
301
302
303 if (WhitePoint == NULL)
304 WhitePoint = cmsD50_XYZ();
305
306 y = (Lab-> L + 16.0) / 116.0;
307 x = y + 0.002 * Lab -> a;
308 z = y - 0.005 * Lab -> b;
309
310 xyz -> X = f_1(x) * WhitePoint -> X;
311 xyz -> Y = f_1(y) * WhitePoint -> Y;
312 xyz -> Z = f_1(z) * WhitePoint -> Z;
313
314}
315
316
317
318void cmsLab2XYZEncoded(WORD Lab[3], WORD XYZ[3])
319{
320 double L, a, b;
321 double X, Y, Z, x, y, z;
322
323
324 L = ((double) Lab[0] * 100.0) / 65280.0;
325 if (L==0.0) {
326
327 XYZ[0] = 0; XYZ[1] = 0; XYZ[2] = 0;
328 return;
329 }
330
331 a = ((double) Lab[1] / 256.0) - 128.0;
332 b = ((double) Lab[2] / 256.0) - 128.0;
333
334 y = (L + 16.) / 116.0;
335 x = y + 0.002 * a;
336 z = y - 0.005 * b;
337
338 X = f_1(x) * D50X;
339 Y = f_1(y) * D50Y;
340 Z = f_1(z) * D50Z;
341
342 // Convert to 1.15 fixed format PCS
343
344
345 XYZ[0] = _cmsClampWord((int) floor(X * 32768.0 + 0.5));
346 XYZ[1] = _cmsClampWord((int) floor(Y * 32768.0 + 0.5));
347 XYZ[2] = _cmsClampWord((int) floor(Z * 32768.0 + 0.5));
348
349
350}
351
352static
353double L2float3(WORD v)
354{
355 Fixed32 fix32;
356
357 fix32 = (Fixed32) v;
358 return (double) fix32 / 652.800;
359}
360
361
362// the a/b part
363
364static
365double ab2float3(WORD v)
366{
367 Fixed32 fix32;
368
369 fix32 = (Fixed32) v;
370 return ((double) fix32/256.0)-128.0;
371}
372
373static
374WORD L2Fix3(double L)
375{
376 return (WORD) (L * 652.800 + 0.5);
377}
378
379static
380WORD ab2Fix3(double ab)
381{
382 return (WORD) ((ab + 128.0) * 256.0 + 0.5);
383}
384
385
386// ICC 4.0 -- ICC has changed PCS Lab encoding.
387
388static
389WORD L2Fix4(double L)
390{
391 return (WORD) (L * 655.35 + 0.5);
392}
393
394static
395WORD ab2Fix4(double ab)
396{
397 return (WORD) ((ab + 128.0) * 257.0 + 0.5);
398}
399
400static
401double L2float4(WORD v)
402{
403 Fixed32 fix32;
404
405 fix32 = (Fixed32) v;
406 return (double) fix32 / 655.35;
407}
408
409
410// the a/b part
411
412static
413double ab2float4(WORD v)
414{
415 Fixed32 fix32;
416
417 fix32 = (Fixed32) v;
418 return ((double) fix32/257.0)-128.0;
419}
420
421
422void LCMSEXPORT cmsLabEncoded2Float(LPcmsCIELab Lab, const WORD wLab[3])
423{
424 Lab->L = L2float3(wLab[0]);
425 Lab->a = ab2float3(wLab[1]);
426 Lab->b = ab2float3(wLab[2]);
427}
428
429
430void LCMSEXPORT cmsLabEncoded2Float4(LPcmsCIELab Lab, const WORD wLab[3])
431{
432 Lab->L = L2float4(wLab[0]);
433 Lab->a = ab2float4(wLab[1]);
434 Lab->b = ab2float4(wLab[2]);
435}
436
437static
438double Clamp_L_double(double L)
439{
440 if (L < 0) L = 0;
441 if (L > 100) L = 100;
442
443 return L;
444}
445
446
447static
448double Clamp_ab_double(double ab)
449{
450 if (ab < -128) ab = -128.0;
451 if (ab > +127.9961) ab = +127.9961;
452
453 return ab;
454}
455
456void LCMSEXPORT cmsFloat2LabEncoded(WORD wLab[3], const cmsCIELab* fLab)
457{
458 cmsCIELab Lab;
459
460
461 Lab.L = Clamp_L_double(fLab ->L);
462 Lab.a = Clamp_ab_double(fLab ->a);
463 Lab.b = Clamp_ab_double(fLab ->b);
464
465 wLab[0] = L2Fix3(Lab.L);
466 wLab[1] = ab2Fix3(Lab.a);
467 wLab[2] = ab2Fix3(Lab.b);
468}
469
470
471void LCMSEXPORT cmsFloat2LabEncoded4(WORD wLab[3], const cmsCIELab* fLab)
472{
473 cmsCIELab Lab;
474
475
476 Lab.L = fLab ->L;
477 Lab.a = fLab ->a;
478 Lab.b = fLab ->b;
479
480
481 if (Lab.L < 0) Lab.L = 0;
482 if (Lab.L > 100.) Lab.L = 100.;
483
484 if (Lab.a < -128.) Lab.a = -128.;
485 if (Lab.a > 127.) Lab.a = 127.;
486 if (Lab.b < -128.) Lab.b = -128.;
487 if (Lab.b > 127.) Lab.b = 127.;
488
489
490 wLab[0] = L2Fix4(Lab.L);
491 wLab[1] = ab2Fix4(Lab.a);
492 wLab[2] = ab2Fix4(Lab.b);
493}
494
495
496
497
498void LCMSEXPORT cmsLab2LCh(LPcmsCIELCh LCh, const cmsCIELab* Lab)
499{
500 double a, b;
501
502 LCh -> L = Clamp_L_double(Lab -> L);
503
504 a = Clamp_ab_double(Lab -> a);
505 b = Clamp_ab_double(Lab -> b);
506
507 LCh -> C = pow(a * a + b * b, 0.5);
508
509 if (a == 0 && b == 0)
510 LCh -> h = 0;
511 else
512 LCh -> h = atan2(b, a);
513
514
515 LCh -> h *= (180. / M_PI);
516
517
518 while (LCh -> h >= 360.) // Not necessary, but included as a check.
519 LCh -> h -= 360.;
520
521 while (LCh -> h < 0)
522 LCh -> h += 360.;
523
524}
525
526
527
528
529void LCMSEXPORT cmsLCh2Lab(LPcmsCIELab Lab, const cmsCIELCh* LCh)
530{
531
532 double h = (LCh -> h * M_PI) / 180.0;
533
534 Lab -> L = Clamp_L_double(LCh -> L);
535 Lab -> a = Clamp_ab_double(LCh -> C * cos(h));
536 Lab -> b = Clamp_ab_double(LCh -> C * sin(h));
537
538}
539
540
541
542
543
544// In XYZ All 3 components are encoded using 1.15 fixed point
545
546static
547WORD XYZ2Fix(double d)
548{
549 return (WORD) floor(d * 32768.0 + 0.5);
550}
551
552
553void LCMSEXPORT cmsFloat2XYZEncoded(WORD XYZ[3], const cmsCIEXYZ* fXYZ)
554{
555 cmsCIEXYZ xyz;
556
557 xyz.X = fXYZ -> X;
558 xyz.Y = fXYZ -> Y;
559 xyz.Z = fXYZ -> Z;
560
561
562 // Clamp to encodeable values.
563 // 1.99997 is reserved as out-of-gamut marker
564
565
566 if (xyz.Y <= 0) {
567
568 xyz.X = 0;
569 xyz.Y = 0;
570 xyz.Z = 0;
571 }
572
573
574 if (xyz.X > 1.99996)
575 xyz.X = 1.99996;
576
577 if (xyz.X < 0)
578 xyz.X = 0;
579
580 if (xyz.Y > 1.99996)
581 xyz.Y = 1.99996;
582
583 if (xyz.Y < 0)
584 xyz.Y = 0;
585
586
587 if (xyz.Z > 1.99996)
588 xyz.Z = 1.99996;
589
590 if (xyz.Z < 0)
591 xyz.Z = 0;
592
593
594
595 XYZ[0] = XYZ2Fix(xyz.X);
596 XYZ[1] = XYZ2Fix(xyz.Y);
597 XYZ[2] = XYZ2Fix(xyz.Z);
598
599}
600
601
602// To convert from Fixed 1.15 point to double
603
604static
605double XYZ2float(WORD v)
606{
607 Fixed32 fix32;
608
609 // From 1.15 to 15.16
610
611 fix32 = v << 1;
612
613 // From fixed 15.16 to double
614
615 return FIXED_TO_DOUBLE(fix32);
616}
617
618
619void LCMSEXPORT cmsXYZEncoded2Float(LPcmsCIEXYZ fXYZ, const WORD XYZ[3])
620{
621
622 fXYZ -> X = XYZ2float(XYZ[0]);
623 fXYZ -> Y = XYZ2float(XYZ[1]);
624 fXYZ -> Z = XYZ2float(XYZ[2]);
625
626}