001    /*
002     * LogLuvConversion
003     * 
004     * Copyright (c) 2002, 2003 Marco Schmidt.
005     * All rights reserved.
006     */
007    
008    package net.sourceforge.jiu.color.conversion;
009    
010    /**
011     * Convert from LogLuv color representation to RGB color space and
012     * from LogL to grayscale.
013     * <p>
014     * This implementation is based on the file <code>tif_luv.c</code> which
015     * is part of the TIFF library <a target="_top" href="http://www.libtiff.org">libtiff</a>.
016     * The original implementation was written by Greg W. Larson.
017     * <p>
018     * Learn more about the color type and its encoding on Greg's page
019     * <a target="_top" href="http://positron.cs.berkeley.edu/~gwlarson/pixformat/tiffluv.html">LogLuv 
020     * Encoding for TIFF Images</a>.
021     * @author Marco Schmidt
022     * @since 0.10.0
023     */
024    public class LogLuvConversion
025    {
026            private static final double M_LN2 = 0.69314718055994530942;
027            private static final double UVSCALE = 410.0;
028    
029            // constants from libtiff's uv_decode.h
030            private static final float UV_SQSIZ = 0.003500f;
031            private static final int UV_NDIVS = 16289;
032            private static final float UV_VSTART = 0.016940f;
033            private static final int UV_NVS = 163;
034            private static final double U_NEU = 0.210526316;
035            private static final double V_NEU = 0.473684211;
036            private static final double[] USTART =
037            {
038                    0.247663,
039                    0.243779,
040                    0.241684,
041                    0.237874,
042                    0.235906,
043                    0.232153,
044                    0.228352,
045                    0.226259,
046                    0.222371,
047                    0.220410,
048                    0.214710,
049                    0.212714,
050                    0.210721,
051                    0.204976,
052                    0.202986,
053                    0.199245,
054                    0.195525,
055                    0.193560,
056                    0.189878,
057                    0.186216,
058                    0.186216,
059                    0.182592,
060                    0.179003,
061                    0.175466,
062                    0.172001,
063                    0.172001,
064                    0.168612,
065                    0.168612,
066                    0.163575,
067                    0.158642,
068                    0.158642,
069                    0.158642,
070                    0.153815,
071                    0.153815,
072                    0.149097,
073                    0.149097,
074                    0.142746,
075                    0.142746,
076                    0.142746,
077                    0.138270,
078                    0.138270,
079                    0.138270,
080                    0.132166,
081                    0.132166,
082                    0.126204,
083                    0.126204,
084                    0.126204,
085                    0.120381,
086                    0.120381,
087                    0.120381,
088                    0.120381,
089                    0.112962,
090                    0.112962,
091                    0.112962,
092                    0.107450,
093                    0.107450,
094                    0.107450,
095                    0.107450,
096                    0.100343,
097                    0.100343,
098                    0.100343,
099                    0.095126,
100                    0.095126,
101                    0.095126,
102                    0.095126,
103                    0.088276,
104                    0.088276,
105                    0.088276,
106                    0.088276,
107                    0.081523,
108                    0.081523,
109                    0.081523,
110                    0.081523,
111                    0.074861,
112                    0.074861,
113                    0.074861,
114                    0.074861,
115                    0.068290,
116                    0.068290,
117                    0.068290,
118                    0.068290,
119                    0.063573,
120                    0.063573,
121                    0.063573,
122                    0.063573,
123                    0.057219,
124                    0.057219,
125                    0.057219,
126                    0.057219,
127                    0.050985,
128                    0.050985,
129                    0.050985,
130                    0.050985,
131                    0.050985,
132                    0.044859,
133                    0.044859,
134                    0.044859,
135                    0.044859,
136                    0.040571,
137                    0.040571,
138                    0.040571,
139                    0.040571,
140                    0.036339,
141                    0.036339,
142                    0.036339,
143                    0.036339,
144                    0.032139,
145                    0.032139,
146                    0.032139,
147                    0.032139,
148                    0.027947,
149                    0.027947,
150                    0.027947,
151                    0.023739,
152                    0.023739,
153                    0.023739,
154                    0.023739,
155                    0.019504,
156                    0.019504,
157                    0.019504,
158                    0.016976,
159                    0.016976,
160                    0.016976,
161                    0.016976,
162                    0.012639,
163                    0.012639,
164                    0.012639,
165                    0.009991,
166                    0.009991,
167                    0.009991,
168                    0.009016,
169                    0.009016,
170                    0.009016,
171                    0.006217,
172                    0.006217,
173                    0.005097,
174                    0.005097,
175                    0.005097,
176                    0.003909,
177                    0.003909,
178                    0.002340,
179                    0.002389,
180                    0.001068,
181                    0.001653,
182                    0.000717,
183                    0.001614,
184                    0.000270,
185                    0.000484,
186                    0.001103,
187                    0.001242,
188                    0.001188,
189                    0.001011,
190                    0.000709,
191                    0.000301,
192                    0.002416,
193                    0.003251,
194                    0.003246,
195                    0.004141,
196                    0.005963,
197                    0.008839,
198                    0.010490,
199                    0.016994,
200                    0.023659,
201            };
202    
203            private static final short[] NCUM =
204            {
205                    0,
206                    4,
207                    10,
208                    17,
209                    26,
210                    36,
211                    48,
212                    62,
213                    77,
214                    94,
215                    112,
216                    133,
217                    155,
218                    178,
219                    204,
220                    231,
221                    260,
222                    291,
223                    323,
224                    357,
225                    393,
226                    429,
227                    467,
228                    507,
229                    549,
230                    593,
231                    637,
232                    683,
233                    729,
234                    778,
235                    830,
236                    882,
237                    934,
238                    989,
239                    1044,
240                    1102,
241                    1160,
242                    1222,
243                    1284,
244                    1346,
245                    1411,
246                    1476,
247                    1541,
248                    1610,
249                    1679,
250                    1752,
251                    1825,
252                    1898,
253                    1975,
254                    2052,
255                    2129,
256                    2206,
257                    2288,
258                    2370,
259                    2452,
260                    2538,
261                    2624,
262                    2710,
263                    2796,
264                    2887,
265                    2978,
266                    3069,
267                    3164,
268                    3259,
269                    3354,
270                    3449,
271                    3549,
272                    3649,
273                    3749,
274                    3849,
275                    3954,
276                    4059,
277                    4164,
278                    4269,
279                    4379,
280                    4489,
281                    4599,
282                    4709,
283                    4824,
284                    4939,
285                    5054,
286                    5169,
287                    5288,
288                    5407,
289                    5526,
290                    5645,
291                    5769,
292                    5893,
293                    6017,
294                    6141,
295                    6270,
296                    6399,
297                    6528,
298                    6657,
299                    6786,
300                    6920,
301                    7054,
302                    7188,
303                    7322,
304                    7460,
305                    7598,
306                    7736,
307                    7874,
308                    8016,
309                    8158,
310                    8300,
311                    8442,
312                    8588,
313                    8734,
314                    8880,
315                    9026,
316                    9176,
317                    9326,
318                    9476,
319                    9630,
320                    9784,
321                    9938,
322                    10092,
323                    10250,
324                    10408,
325                    10566,
326                    10727,
327                    10888,
328                    11049,
329                    11210,
330                    11375,
331                    11540,
332                    11705,
333                    11873,
334                    12041,
335                    12209,
336                    12379,
337                    12549,
338                    12719,
339                    12892,
340                    13065,
341                    13240,
342                    13415,
343                    13590,
344                    13767,
345                    13944,
346                    14121,
347                    14291,
348                    14455,
349                    14612,
350                    14762,
351                    14905,
352                    15041,
353                    15170,
354                    15293,
355                    15408,
356                    15517,
357                    15620,
358                    15717,
359                    15806,
360                    15888,
361                    15964,
362                    16033,
363                    16095,
364                    16150,
365                    16197,
366                    16237,
367                    16268,
368            };
369    
370            private LogLuvConversion()
371            {
372            }
373    
374            /**
375             * Converts an unsigned 10 bit value (the argument must lie in the
376             * interval 0 to 1023) to a <code>double</code> luminance
377             * (brightness) value between <code>0.0</code> and <code>1.0</code>.
378             * This conversion is needed by both LogLuv to XYZ and LogL to grayscale.
379             * @param p10 input LogL value
380             * @return double value with luminance, between 0 and 1
381             */
382            public static double convertLogL10toY(int p10)
383            {
384                    if (p10 == 0)
385                    {
386                            return 0.0;
387                    }
388                    else
389                    {
390                            return Math.exp(M_LN2 / 64.0 * (p10 + 0.5) - M_LN2 * 12.0);
391                    }
392            }
393    
394            /**
395             * Converts a signed 16 bit value (the argument must lie in the
396             * interval -32768 to 32767) to a <code>double</code> luminance
397             * (brightness) value between <code>0.0</code> and <code>1.0</code>.
398             * This conversion is needed by both LogLuv to XYZ and LogL to grayscale.
399             * @param p16 input LogL value
400             * @return double value with luminance, between 0 and 1
401             */
402            public static double convertLogL16toY(int p16)
403            {
404                    int Le = p16 & 0x7fff;
405                    if (Le == 0)
406                    {
407                            return 0.0;
408                    }
409                    double Y = Math.exp(M_LN2 / 256.0 * (Le + 0.5) - M_LN2 * 64.0);
410                    if ((p16 & 0x8000) == 0)
411                    {
412                            return Y;
413                    }
414                    else
415                    {
416                            return -Y;
417                    }
418            }
419    
420            private static byte convertDoubleToByte(double d)
421            {
422                    if (d <= 0.0)
423                    {
424                            return 0;
425                    }
426                    else
427                    if (d >= 1.0)
428                    {
429                            return (byte)255;
430                    }
431                    else
432                    {
433                            double result = 255.0 * Math.sqrt(d);
434                            return (byte)result;
435                    }
436            }
437    
438            /**
439             * Converts a number of 24 bit LogLuv pixels to 24 bit RGB pixels.
440             * Each LogLuv pixel is stored as three consecutive bytes in the <code>logluv</code> byte array.
441             * The first byte and the top two bits of the second are the LogL value, the remaining
442             * 14 bits are an index that encodes u and v.
443             * @param logluv byte array with LogLuv data, must be at least num * 3 bytes large
444             * @param red the byte samples for the red channel will be written to this array
445             * @param green the byte samples for the green channel will be written to this array
446             * @param blue the byte samples for the blue channel will be written to this array
447             * @param num number of pixels to be converted
448             */
449            public static void convertLogLuv24InterleavedtoRGB24Planar(byte[] logluv, byte[] red, byte[] green, byte[] blue, int num)
450            {
451                    int srcOffs = 0;
452                    int destOffs = 0;
453                    while (num-- != 0)
454                    {
455                            // convert from LogLuv24 to XYZ
456                            float X = 0.0f;
457                            float Y = 0.0f;
458                            float Z = 0.0f;
459                            // first byte and top two bits of second make 10 bit value L10
460                            int v1 = logluv[srcOffs++] & 0xff;
461                            int v2 = logluv[srcOffs++] & 0xff;
462                            int v3 = logluv[srcOffs++] & 0xff;
463                            double L = convertLogL10toY(v1 << 2 | ((v2 >> 6) & 0x03));
464                            if (L > 0.0)
465                            {
466                                    int c = ((v2 & 0x3f) << 8) | v3;
467                                    double u = U_NEU; 
468                                    double v = V_NEU;
469                                    // uv_decode in tif_luv.c
470                                    int     upper = UV_NVS;
471                                    int lower = 0;
472                                    if (c >= 0 && c < UV_NDIVS)
473                                    {
474                                            lower = 0;
475                                            upper = UV_NVS;
476                                            int ui = 0;
477                                            int vi = 0;
478                                            while (upper - lower > 1)
479                                            {
480                                                    vi = (lower + upper) >> 1;
481                                                    ui = c - NCUM[vi];
482                                                    if (ui > 0)
483                                                    {
484                                                            lower = vi;
485                                                    }
486                                                    else
487                                                    if (ui < 0)
488                                                    {
489                                                            upper = vi;
490                                                    }
491                                                    else
492                                                    {
493                                                            lower = vi;
494                                                            break;
495                                                    }
496                                            }
497                                            vi = lower;
498                                            ui = c - NCUM[vi];
499                                            u = USTART[vi] + (ui + 0.5) * UV_SQSIZ;
500                                            v = UV_VSTART + (vi + 0.5) * UV_SQSIZ;
501                                    }
502                                    double s = 1.0 / (6.0 * u - 16.0 * v + 12.0);
503                                    double x = 9.0 * u * s;
504                                    double y = 4.0 * v * s;
505                                    X = (float)(x / y * L);
506                                    Y = (float)L;
507                                    Z = (float)((1.0 - x - y) / y * L);
508                            }
509                            // convert from XYZ to RGB
510                            double r =  2.690 * X + -1.276 * Y + -0.414 * Z;
511                            double g = -1.022 * X +  1.978 * Y +  0.044 * Z;
512                            double b =  0.061 * X + -0.224 * Y +  1.163 * Z;
513                            red[destOffs] = convertDoubleToByte(r);
514                            green[destOffs] = convertDoubleToByte(g);
515                            blue[destOffs] = convertDoubleToByte(b);
516                            destOffs++;
517                    }
518            }
519    
520            /**
521             * Converts a number of 32 bit LogLuv pixels to 24 bit RGB pixels.
522             * Each LogLuv pixel is stored as four consecutive bytes in the <code>logluv</code> byte array.
523             * The first two bytes represent the LogL value (most significant bytefirst), followed
524             * by the u value and then the v value.
525             * @param logluv byte array with LogLuv data, must be at least num * 4 bytes large
526             * @param red the byte samples for the red channel will be written to this array
527             * @param green the byte samples for the green channel will be written to this array
528             * @param blue the byte samples for the blue channel will be written to this array
529             * @param num number of pixels to be converted
530             */
531            public static void convertLogLuv32InterleavedtoRGB24Planar(byte[] logluv, byte[] red, byte[] green, byte[] blue, int num)
532            {
533                    int srcOffs = 0;
534                    int destOffs = 0;
535                    while (num-- != 0)
536                    {
537                            // convert from LogLuv32 to XYZ
538                            float X = 0.0f;
539                            float Y = 0.0f;
540                            float Z = 0.0f;
541                            int v1 = logluv[srcOffs++] & 0xff;
542                            int v2 = logluv[srcOffs++] & 0xff;
543                            double L = convertLogL16toY((short)((v1 << 8) | v2));
544                            if (L > 0.0)
545                            {
546                                    // decode color
547                                    double u = 1.0 / UVSCALE * ((logluv[srcOffs++] & 0xff) + 0.5);
548                                    double v = 1.0 / UVSCALE * ((logluv[srcOffs++] & 0xff) + 0.5);
549                                    double s = 1.0 / (6.0 * u - 16.0 * v + 12.0);
550                                    double x = 9.0 * u * s;
551                                    double y = 4.0 * v * s;
552                                    X = (float)(x / y * L);
553                                    Y = (float)L;
554                                    Z = (float)((1.0 - x - y) / y * L);
555                            }
556                            // convert from XYZ to RGB
557                            double r =  2.690 * X + -1.276 * Y + -0.414 * Z;
558                            double g = -1.022 * X +  1.978 * Y +  0.044 * Z;
559                            double b =  0.061 * X + -0.224 * Y +  1.163 * Z;
560                            red[destOffs] = convertDoubleToByte(r);
561                            green[destOffs] = convertDoubleToByte(g);
562                            blue[destOffs] = convertDoubleToByte(b);
563                            destOffs++;
564                    }
565            }
566    
567            /**
568             * Converts a number of 16 bit LogL samples to 8 bit grayscale samples.
569             * @param logl byte array with LogL samples, each 16 bit sample is stored as 
570             *  two consecutive bytes in order most-significant-byte least-significant-byte (network byte order);
571             *  the array must be at least num * 2 entries large
572             * @param gray the byte array to which the converted samples will be written
573             * @param num the number of samples to be converted
574             */
575            public static void convertLogL16toGray8(byte[] logl, byte[] gray, int num)
576            {
577                    int srcOffs = 0;
578                    int destOffs = 0;
579                    while (num-- != 0)
580                    {
581                            int v1 = logl[srcOffs++] & 0xff;
582                            int v2 = logl[srcOffs++] & 0xff;
583                            double L = convertLogL16toY((short)((v1 << 8) | v2));
584                            gray[destOffs++] = convertDoubleToByte(L);
585                    }
586            }
587    }