1 /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3  * This file is part of openfx-supportext <https://github.com/devernay/openfx-supportext>,
4  * Copyright (C) 2013-2018 INRIA
5  *
6  * openfx-supportext is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * openfx-supportext is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with openfx-supportext.  If not, see <http://www.gnu.org/licenses/gpl-2.0.html>
18  * ***** END LICENSE BLOCK ***** */
19 
20 /*
21  * OFX color-spaces transformations support as-well as bit-depth conversions.
22  */
23 
24 #include "ofxsLut.h"
25 
26 #include <algorithm>
27 #ifdef _WIN32
28 typedef unsigned __int32 uint32_t;
29 typedef unsigned char uint8_t;
30 #else
31 #include <stdint.h>
32 #endif
33 #include <limits>
34 #include <cmath>
35 
36 #ifndef M_PI
37 #define M_PI        3.14159265358979323846264338327950288   /* pi             */
38 #endif
39 
40 namespace OFX {
41 namespace Color {
42 // compile-time endianness checking found on:
43 // http://stackoverflow.com/questions/2100331/c-macro-definition-to-determine-big-endian-or-little-endian-machine
44 // if(O32_HOST_ORDER == O32_BIG_ENDIAN) will always be optimized by gcc -O2
45 enum
46 {
47     O32_LITTLE_ENDIAN = 0x03020100ul,
48     O32_BIG_ENDIAN = 0x00010203ul,
49     O32_PDP_ENDIAN = 0x01000302ul
50 };
51 
52 union o32_host_order_t
53 {
54     uint8_t bytes[4];
55     uint32_t value;
56 };
57 
58 static const o32_host_order_t o32_host_order = {
59     { 0, 1, 2, 3 }
60 };
61 #define O32_HOST_ORDER (o32_host_order.value)
62 unsigned short
hipart(const float f)63 Lut::hipart(const float f)
64 {
65     union
66     {
67         float f;
68         unsigned short us[2];
69     }
70 
71     tmp;
72 
73     tmp.us[0] = tmp.us[1] = 0;
74     tmp.f = f;
75 
76     if (O32_HOST_ORDER == O32_BIG_ENDIAN) {
77         return tmp.us[0];
78     } else if (O32_HOST_ORDER == O32_LITTLE_ENDIAN) {
79         return tmp.us[1];
80     } else {
81         assert( (O32_HOST_ORDER == O32_LITTLE_ENDIAN) || (O32_HOST_ORDER == O32_BIG_ENDIAN) );
82 
83         return 0;
84     }
85 }
86 
87 float
index_to_float(const unsigned short i)88 Lut::index_to_float(const unsigned short i)
89 {
90     union
91     {
92         float f;
93         unsigned short us[2];
94     }
95 
96     tmp;
97 
98     /* positive and negative zeros, and all gradual underflow, turn into zero: */
99     if ( ( i < 0x80) || ( ( i >= 0x8000) && ( i < 0x8080) ) ) {
100         return 0;
101     }
102     /* All NaN's and infinity turn into the largest possible legal float: */
103     if ( ( i >= 0x7f80) && ( i < 0x8000) ) {
104         return std::numeric_limits<float>::max();
105     }
106     if (i >= 0xff80) {
107         return -std::numeric_limits<float>::max();
108     }
109     if (O32_HOST_ORDER == O32_BIG_ENDIAN) {
110         tmp.us[0] = i;
111         tmp.us[1] = 0x8000;
112     } else if (O32_HOST_ORDER == O32_LITTLE_ENDIAN) {
113         tmp.us[0] = 0x8000;
114         tmp.us[1] = i;
115     } else {
116         assert( (O32_HOST_ORDER == O32_LITTLE_ENDIAN) || (O32_HOST_ORDER == O32_BIG_ENDIAN) );
117     }
118 
119     return tmp.f;
120 }
121 
122 // r,g,b values are linear values from 0 to 1
123 // h = [0,OFXS_HUE_CIRCLE], s = [0,1], v = [0,1]
124 //		if s == 0, then h = 0 (undefined)
125 // Reference:
126 // "Color gamut transform pairs", Alvy Ray Smith, Proceeding SIGGRAPH '78
127 // https://doi.org/10.1145/800248.807361
128 // http://www.icst.pku.edu.cn/F/course/ImageProcessing/2018/resource/Color78.pdf
129 void
rgb_to_hsv(float r,float g,float b,float * h,float * s,float * v)130 rgb_to_hsv( float r,
131             float g,
132             float b,
133             float *h,
134             float *s,
135             float *v )
136 {
137     float min = (std::min)((std::min)(r, g), b);
138     float max = (std::max)((std::max)(r, g), b);
139 
140     *v = max;                               // v
141 
142     float delta = max - min;
143 
144     if (max != 0.) {
145         *s = delta / max;                       // s
146     } else {
147         // r = g = b = 0		// s = 0, v is undefined
148         *s = 0.f;
149         *h = 0.f;
150 
151         return;
152     }
153 
154     if (delta == 0.) {
155         *h = 0.f;                 // gray
156     } else if (r == max) {
157         *h = (g - b) / delta;                       // between yellow & magenta
158     } else if (g == max) {
159         *h = 2 + (b - r) / delta;                   // between cyan & yellow
160     } else {
161         *h = 4 + (r - g) / delta;                   // between magenta & cyan
162     }
163     *h *= OFXS_HUE_CIRCLE / 6;
164     if (*h < 0) {
165         *h += OFXS_HUE_CIRCLE;
166     }
167 }
168 
169 // r,g,b values are linear values from 0 to 1
170 // h = [0,OFXS_HUE_CIRCLE], s = [0,1], v = [0,1]
171 //		if s == 0, then h = 0 (undefined)
172 // Reference:
173 // "Color gamut transform pairs", Alvy Ray Smith, Proceeding SIGGRAPH '78
174 // https://doi.org/10.1145/800248.807361
175 // http://www.icst.pku.edu.cn/F/course/ImageProcessing/2018/resource/Color78.pdf
176 void
hsv_to_rgb(float h,float s,float v,float * r,float * g,float * b)177 hsv_to_rgb(float h,
178            float s,
179            float v,
180            float *r,
181            float *g,
182            float *b)
183 {
184     if (s == 0) {
185         // achromatic (grey)
186         *r = *g = *b = v;
187 
188         return;
189     }
190 
191     h *= 6. / OFXS_HUE_CIRCLE;            // sector 0 to 5
192     int i = (int)std::floor(h);
193     float f = h - i;          // factorial part of h
194     i = (i >= 0) ? (i % 6) : (i % 6) + 6; // take h modulo 360
195     float p = v * ( 1 - s );
196     float q = v * ( 1 - s * f );
197     float t = v * ( 1 - s * ( 1 - f ) );
198 
199     switch (i) {
200     case 0:
201         *r = v;
202         *g = t;
203         *b = p;
204         break;
205     case 1:
206         *r = q;
207         *g = v;
208         *b = p;
209         break;
210     case 2:
211         *r = p;
212         *g = v;
213         *b = t;
214         break;
215     case 3:
216         *r = p;
217         *g = q;
218         *b = v;
219         break;
220     case 4:
221         *r = t;
222         *g = p;
223         *b = v;
224         break;
225     default:                // case 5:
226         *r = v;
227         *g = p;
228         *b = q;
229         break;
230     }
231 } // hsv_to_rgb
232 
233 void
rgb_to_hsl(float r,float g,float b,float * h,float * s,float * l)234 rgb_to_hsl( float r,
235             float g,
236             float b,
237             float *h,
238             float *s,
239             float *l )
240 {
241     float min = (std::min)((std::min)(r, g), b);
242     float max = (std::max)((std::max)(r, g), b);
243 
244     *l = (min + max) / 2;
245 
246     float delta = max - min;
247 
248     if (max != 0.) {
249         *s = (*l <= 0.5) ? ( delta / (max + min) ) : ( delta / (2 - max - min) ); // s = delta/(1-abs(2L-1))
250     } else {
251         // r = g = b = 0		// s = 0
252         *s = 0.f;
253         *h = 0.f;
254 
255         return;
256     }
257 
258     if (delta == 0.) {
259         *h = 0.f;                 // gray
260     } else if (r == max) {
261         *h = (g - b) / delta;                       // between yellow & magenta
262     } else if (g == max) {
263         *h = 2 + (b - r) / delta;                   // between cyan & yellow
264     } else {
265         *h = 4 + (r - g) / delta;                   // between magenta & cyan
266     }
267     *h *= OFXS_HUE_CIRCLE / 6;
268     if (*h < 0) {
269         *h += OFXS_HUE_CIRCLE;
270     }
271 }
272 
273 void
hsl_to_rgb(float h,float s,float l,float * r,float * g,float * b)274 hsl_to_rgb(float h,
275            float s,
276            float l,
277            float *r,
278            float *g,
279            float *b)
280 {
281     if (s == 0) {
282         // achromatic (grey)
283         *r = *g = *b = l;
284 
285         return;
286     }
287 
288     h *= 6.f / OFXS_HUE_CIRCLE;            // sector 0 to 5
289     int i = (int)std::floor(h);
290     float f = h - i;          // factorial part of h
291     i = (i >= 0) ? (i % 6) : (i % 6) + 6; // take h modulo 360
292     float v = (l <= 0.5f) ? ( l * (1.0f + s) ) : (l + s - l * s);
293     float p = l + l - v;
294     float sv = (v - p ) / v;
295     float vsf = v * sv * f;
296     float t = p + vsf;
297     float q = v - vsf;
298 
299     switch (i) {
300     case 0:
301         *r = v;
302         *g = t;
303         *b = p;
304         break;
305     case 1:
306         *r = q;
307         *g = v;
308         *b = p;
309         break;
310     case 2:
311         *r = p;
312         *g = v;
313         *b = t;
314         break;
315     case 3:
316         *r = p;
317         *g = q;
318         *b = v;
319         break;
320     case 4:
321         *r = t;
322         *g = p;
323         *b = v;
324         break;
325     default:                // case 5:
326         *r = v;
327         *g = p;
328         *b = q;
329         break;
330     }
331 } // hsl_to_rgb
332 
333 //! Convert pixel values from RGB to HSI color spaces.
334 void
rgb_to_hsi(float r,float g,float b,float * h,float * s,float * i)335 rgb_to_hsi( float r,
336             float g,
337             float b,
338             float *h,
339             float *s,
340             float *i )
341 {
342     float nR = r; //(r < 0 ? 0 : (r > 1. ? 1. : r));
343     float nG = g; //(g < 0 ? 0 : (g > 1. ? 1. : g));
344     float nB = b; //(b < 0 ? 0 : (b > 1. ? 1. : b));
345     float m = (std::min)((std::min)(nR, nG), nB);
346     float theta = (float)(std::acos( 0.5f * ( (nR - nG) + (nR - nB) ) / std::sqrt( (std::max)( 0.f, (nR - nG) * (nR - nG) + (nR - nB) * (nG - nB) ) ) ) * (OFXS_HUE_CIRCLE / 2) / M_PI);
347     float sum = nR + nG + nB;
348 
349     if (theta > 0) {
350         *h = (nB <= nG) ? theta : (OFXS_HUE_CIRCLE - theta);
351     } else {
352         *h = 0.;
353     }
354     if (sum > 0) {
355         *s = 1 - 3 / sum * m;
356     } else {
357         *s = 0.;
358     }
359     *i = sum / 3;
360 }
361 
362 void
hsi_to_rgb(float h,float s,float i,float * r,float * g,float * b)363 hsi_to_rgb(float h,
364            float s,
365            float i,
366            float *r,
367            float *g,
368            float *b)
369 {
370     float a = i * (1 - s);
371 
372     if ( h < (OFXS_HUE_CIRCLE / 3) ) {
373         *b = a;
374         *r = (float)( i * ( 1 + s * std::cos( h * M_PI / (OFXS_HUE_CIRCLE / 2) ) / std::cos( ( (OFXS_HUE_CIRCLE / 6) - h ) * M_PI / (OFXS_HUE_CIRCLE / 2) ) ) );
375         *g = 3 * i - (*r + *b);
376     } else if ( h < (OFXS_HUE_CIRCLE * 2 / 3) ) {
377         h -= OFXS_HUE_CIRCLE / 3;
378         *r = a;
379         *g = (float)( i * ( 1 + s * std::cos( h * M_PI / (OFXS_HUE_CIRCLE / 2) ) / std::cos( ( (OFXS_HUE_CIRCLE / 6) - h ) * M_PI / (OFXS_HUE_CIRCLE / 2) ) ) );
380         *b = 3 * i - (*r + *g);
381     } else {
382         h -= OFXS_HUE_CIRCLE * 2 / 3;
383         *g = a;
384         *b = (float)( i * ( 1 + s * std::cos( h * M_PI / (OFXS_HUE_CIRCLE / 2) ) / std::cos( ( (OFXS_HUE_CIRCLE / 6) - h ) * M_PI / (OFXS_HUE_CIRCLE / 2) ) ) );
385         *r = 3 * i - (*g + *b);
386     }
387 } // hsi_to_rgb
388 
389 // R'G'B' in the range 0-1 to Y'CbCr in the video range
390 // (Y' = 16/255 to 235/255, CbCr = 16/255 to 240/255)
391 void
rgb_to_ycbcr601(float r,float g,float b,float * y,float * cb,float * cr)392 rgb_to_ycbcr601(float r,
393                 float g,
394                 float b,
395                 float *y,
396                 float *cb,
397                 float *cr)
398 {
399     /// ref: CImg (BT.601)
400     //*y  = ((255*(66*r + 129*g + 25*b) + 128)/256 + 16)/255;
401     //*cb = ((255*(-38*r - 74*g + 112*b) + 128)/256 + 128)/255,
402     //*cr = ((255*(112*r - 94*g - 18*b) + 128)/256 + 128)/255;
403 
404     /// ref: http://www.equasys.de/colorconversion.html (BT.601)
405     /// also http://www.intersil.com/data/an/AN9717.pdf
406     *y  =  0.257f * r + 0.504f * g + 0.098f * b + 16 / 255.f;
407     *cb = -0.148f * r - 0.291f * g + 0.439f * b + 128 / 255.f;
408     *cr =  0.439f * r - 0.368f * g - 0.071f * b + 128 / 255.f;
409 }
410 
411 // Y'CbCr in the video range (Y' = 16/255 to 235/255, CbCr = 16/255 to 240/255)
412 // to R'G'B' in the range 0-1
413 void
ycbcr_to_rgb601(float y,float cb,float cr,float * r,float * g,float * b)414 ycbcr_to_rgb601(float y,
415                 float cb,
416                 float cr,
417                 float *r,
418                 float *g,
419                 float *b)
420 {
421     /// ref: CImg (BT.601)
422     //y  = y * 255 - 16;
423     //cb = cb * 255 - 128;
424     //cr = cr * 255 - 128;
425     //*r = (298 * y + 409 * cr + 128)/256/255;
426     //*g = (298 * y - 100 * cb - 208 * cr + 128)/256/255;
427     //*b = (298 * y + 516 * cb + 128)/256/255;
428 
429     /// ref: http://www.equasys.de/colorconversion.html (BT.601)
430     /// also http://www.intersil.com/data/an/AN9717.pdf
431     *r = 1.164f * (y - 16 / 255.f) + 1.596f * (cr - 128 / 255.f);
432     *g = 1.164f * (y - 16 / 255.f) - 0.813f * (cr - 128 / 255.f) - 0.392f * (cb - 128 / 255.f);
433     *b = 1.164f * (y - 16 / 255.f) + 2.017f * (cb - 128 / 255.f);
434 } // ycbcr_to_rgb
435 
436 // R'G'B' in the range 0-1 to Y'CbCr in the video range
437 // (Y' = 16/255 to 235/255, CbCr = 16/255 to 240/255)
438 void
rgb_to_ycbcr709(float r,float g,float b,float * y,float * cb,float * cr)439 rgb_to_ycbcr709(float r,
440                 float g,
441                 float b,
442                 float *y,
443                 float *cb,
444                 float *cr)
445 {
446     // ref: http://www.poynton.com/PDFs/coloureq.pdf (BT.709)
447     //*y  =  0.2215 * r +0.7154 * g +0.0721 * b;
448     //*cb = -0.1145 * r -0.3855 * g +0.5000 * b + 128./255;
449     //*cr =  0.5016 * r -0.4556 * g -0.0459 * b + 128./255;
450 
451     // ref: http://www.equasys.de/colorconversion.html (BT.709)
452     *y  =  0.183f * r + 0.614f * g + 0.062f * b + 16 / 255.f;
453     *cb = -0.101f * r - 0.339f * g + 0.439f * b + 128 / 255.f;
454     *cr =  0.439f * r - 0.399f * g - 0.040f * b + 128 / 255.f;
455 }
456 
457 // Y'CbCr in the video range (Y' = 16/255 to 235/255, CbCr = 16/255 to 240/255)
458 // to R'G'B' in the range 0-1
459 void
ycbcr_to_rgb709(float y,float cb,float cr,float * r,float * g,float * b)460 ycbcr_to_rgb709(float y,
461                 float cb,
462                 float cr,
463                 float *r,
464                 float *g,
465                 float *b)
466 {
467     // ref: http://www.equasys.de/colorconversion.html (BT.709)
468     *r = 1.164f * (y - 16 / 255.f) + 1.793f * (cr - 128 / 255.f);
469     *g = 1.164f * (y - 16 / 255.f) - 0.533f * (cr - 128 / 255.f) - 0.213f * (cb - 128 / 255.f);
470     *b = 1.164f * (y - 16 / 255.f) + 2.112f * (cb - 128 / 255.f);
471 } // ycbcr_to_rgb
472 
473 // R'G'B' in the range 0-1 to Y'CbCr Analog (Y' in the range 0-1, PbPr in the range -0.5 - 0.5)
474 void
rgb_to_ypbpr601(float r,float g,float b,float * y,float * pb,float * pr)475 rgb_to_ypbpr601(float r,
476                 float g,
477                 float b,
478                 float *y,
479                 float *pb,
480                 float *pr)
481 {
482     // ref: https://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.601_conversion
483     // also http://www.equasys.de/colorconversion.html (BT.601)
484     // and http://public.kitware.com/vxl/doc/release/core/vil/html/vil__colour__space_8cxx_source.html
485     //*y  =  0.299f    * r + 0.587f    * g + 0.114f * b;
486     //*pb = -0.168736f * r - 0.331264f * g + 0.500f * b;
487     //*pr =  0.500f    * r - 0.418688f * g - 0.081312f * b;
488 
489 #define Kb 0.114f
490 #define Kr 0.299f
491     *y  =  Kr * r + (1 - Kr - Kb) * g + Kb * b;
492     *pb =  (b - *y) / ( 2 * (1 - Kb) );
493     *pr =  (r - *y) / ( 2 * (1 - Kr) );
494 }
495 
496 // Y'CbCr Analog (Y' in the range 0-1, PbPr in the range -0.5 - 0.5) to R'G'B' in the range 0-1
497 void
ypbpr_to_rgb601(float y,float pb,float pr,float * r,float * g,float * b)498 ypbpr_to_rgb601(float y,
499                 float pb,
500                 float pr,
501                 float *r,
502                 float *g,
503                 float *b)
504 {
505     // https://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.601_conversion
506     // also ref: http://www.equasys.de/colorconversion.html (BT.601)
507     // and http://public.kitware.com/vxl/doc/release/core/vil/html/vil__colour__space_8cxx_source.html
508     //*r = y                + 1.402f    * pr,
509     //*g = y - 0.344136 * pb - 0.714136f * pr;
510     //*b = y + 1.772f   * pb;
511 
512     *b = pb * ( 2 * (1 - Kb) ) + y;
513     *r = pr * ( 2 * (1 - Kr) ) + y;
514     *g = (y - Kr * *r - Kb * *b) / (1 - Kr - Kb);
515 #undef Kb
516 #undef Kr
517 } // yuv_to_rgb
518 
519 // R'G'B' in the range 0-1 to Y'CbCr Analog (Y' in the range 0-1, PbPr in the range -0.5 - 0.5)
520 void
rgb_to_ypbpr709(float r,float g,float b,float * y,float * pb,float * pr)521 rgb_to_ypbpr709(float r,
522                 float g,
523                 float b,
524                 float *y,
525                 float *pb,
526                 float *pr)
527 {
528     // ref: http://www.equasys.de/colorconversion.html (BT.709)
529     //*y  =  0.2126f * r + 0.7152f * g + 0.0722f * b;
530     //*pb = -0.115f  * r - 0.385f  * g + 0.500f  * b; // or (b - y)/1.8556
531     //*pr =  0.500f  * r - 0.454f  * g - 0.046f  * b; // or (r - y)/1.5748
532 
533     // ref: http://www.poynton.com/PDFs/coloureq.pdf (10.5)
534     //*y  =  0.2215f * r + 0.7154f * g + 0.0721f * b;
535     //*pb = -0.1145f * r - 0.3855f * g + 0.5000f  * b;
536     //*pr =  0.5016f * r - 0.4556f * g - 0.0459f  * b;
537 
538     //*y  =  0.2126390058 * r + 0.7151686783 * g + 0.07219231534 * b;
539     //*pb =  (b - *y) / 1.8556;
540     //*pr =  (r - *y) / 1.5748;
541 #define Kb 0.07219231534f
542 #define Kr 0.2126390058f
543     *y  =  Kr * r + (1 - Kr - Kb) * g + Kb * b;
544     *pb =  (b - *y) / ( 2 * (1 - Kb) );
545     *pr =  (r - *y) / ( 2 * (1 - Kr) );
546 }
547 
548 // Y'CbCr Analog (Y in the range 0-1, PbPr in the range -0.5 - 0.5) to R'G'B' in the range 0-1
549 void
ypbpr_to_rgb709(float y,float pb,float pr,float * r,float * g,float * b)550 ypbpr_to_rgb709(float y,
551                 float pb,
552                 float pr,
553                 float *r,
554                 float *g,
555                 float *b)
556 {
557     // ref: http://www.equasys.de/colorconversion.html (BT.709)
558     //*r = y               + 1.575f * pr,
559     //*g = y - 0.187f * pb - 0.468f * pr;
560     //*b = y + 1.856f * pb;
561 
562     // ref: http://www.poynton.com/PDFs/coloureq.pdf (10.5)
563     // (there is a sign error on the R' coeff for Cr in Poynton's doc)
564     //*r = y                + 1.5701f * pr,
565     //*g = y - 0.1870f * pb - 0.4664f * pr;
566     //*b = y + 1.8556f * pb;
567 
568     //*b = pb * 1.8556 + y;
569     //*r = pr * 1.5748 + y;
570     ////*g = (y - 0.2126f * *r - 0.0722f * *b) / 0.7152f;
571     //*g = (y - 0.2126390058 * *r - 0.07219231534 * *b) / 0.7151686783;
572     *b = pb * ( 2 * (1 - Kb) ) + y;
573     *r = pr * ( 2 * (1 - Kr) ) + y;
574     *g = (y - Kr * *r - Kb * *b) / (1 - Kr - Kb);
575 #undef Kb
576 #undef Kr
577 } // yuv_to_rgb
578 
579 // R'G'B' in the range 0-1 to Y'CbCr Analog (Y' in the range 0-1, PbPr in the range -0.5 - 0.5)
580 void
rgb_to_ypbpr2020(float r,float g,float b,float * y,float * pb,float * pr)581 rgb_to_ypbpr2020(float r,
582                  float g,
583                  float b,
584                  float *y,
585                  float *pb,
586                  float *pr)
587 {
588     // ref: https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.2020-0-201208-S!!PDF-E.pdf
589     // (Rec.2020, table 4 p4)
590     //
591     //*y  =  0.2627f * r + 0.6780f * g + 0.0593f * b;
592     //*pb =  (b - *y) / 1.8814;
593     //*pr =  (r - *y) / 1.4746;
594 
595     // ref: http://www.poynton.com/PDFs/coloureq.pdf (10.5)
596     //*y  =  0.2215f * r + 0.7154f * g + 0.0721f * b;
597     //*pb = -0.1145f * r - 0.3855f * g + 0.5000f  * b;
598     //*pr =  0.5016f * r - 0.4556f * g - 0.0459f  * b;
599 #define Kb 0.0593f
600 #define Kr 0.2627f
601     *y  =  Kr * r + (1 - Kr - Kb) * g + Kb * b;
602     *pb =  (b - *y) / ( 2 * (1 - Kb) );
603     *pr =  (r - *y) / ( 2 * (1 - Kr) );
604 }
605 
606 // Y'CbCr Analog (Y in the range 0-1, PbPr in the range -0.5 - 0.5) to R'G'B' in the range 0-1
607 void
ypbpr_to_rgb2020(float y,float pb,float pr,float * r,float * g,float * b)608 ypbpr_to_rgb2020(float y,
609                  float pb,
610                  float pr,
611                  float *r,
612                  float *g,
613                  float *b)
614 {
615     // ref: https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.2020-0-201208-S!!PDF-E.pdf
616     // (Rec.2020, table 4 p4)
617     //
618     //*b = pb * 1.8814 + y;
619     //*r = pr * 1.4746 + y;
620     //*g = (y - 0.2627f * *r - 0.0593f * *b) / 0.6780f;
621     *b = pb * ( 2 * (1 - Kb) ) + y;
622     *r = pr * ( 2 * (1 - Kr) ) + y;
623     *g = (y - Kr * *r - Kb * *b) / (1 - Kr - Kb);
624 #undef Kb
625 #undef Kr
626 } // yuv_to_rgb
627 
628 // R'G'B' in the range 0-1 to Y'UV (Y' in the range 0-1, U in the range -0.436 - 0.436,
629 // V in the range -0.615 - 0.615)
630 void
rgb_to_yuv601(float r,float g,float b,float * y,float * u,float * v)631 rgb_to_yuv601(float r,
632               float g,
633               float b,
634               float *y,
635               float *u,
636               float *v)
637 {
638     /// ref: https://en.wikipedia.org/wiki/YUV#SDTV_with_BT.601
639     *y =  0.299f   * r + 0.587f   * g + 0.114f  * b;
640     *u = -0.14713f * r - 0.28886f * g + 0.436f  * b;
641     *v =  0.615f   * r - 0.51499f * g - 0.10001f * b;
642 }
643 
644 // Y'UV (Y' in the range 0-1, U in the range -0.436 - 0.436,
645 // V in the range -0.615 - 0.615) to R'G'B' in the range 0-1
646 void
yuv_to_rgb601(float y,float u,float v,float * r,float * g,float * b)647 yuv_to_rgb601(float y,
648               float u,
649               float v,
650               float *r,
651               float *g,
652               float *b)
653 {
654     /// ref: https://en.wikipedia.org/wiki/YUV#SDTV_with_BT.601
655     *r = y                + 1.13983f * v,
656     *g = y - 0.39465f * u - 0.58060f * v;
657     *b = y + 2.03211f * u;
658 } // yuv_to_rgb
659 
660 // R'G'B' in the range 0-1 to Y'UV (Y' in the range 0-1, U in the range -0.436 - 0.436,
661 // V in the range -0.615 - 0.615)
662 void
rgb_to_yuv709(float r,float g,float b,float * y,float * u,float * v)663 rgb_to_yuv709(float r,
664               float g,
665               float b,
666               float *y,
667               float *u,
668               float *v)
669 {
670     /// ref: https://en.wikipedia.org/wiki/YUV#HDTV_with_BT.709
671     *y =  0.2126f  * r + 0.7152f  * g + 0.0722f  * b;
672     *u = -0.09991f * r - 0.33609f * g + 0.436f   * b;
673     *v =  0.615f   * r - 0.55861f * g - 0.05639f * b;
674 }
675 
676 // Y'UV (Y in the range 0-1, U in the range -0.436 - 0.436,
677 // V in the range -0.615 - 0.615) to R'G'B' in the range 0-1
678 void
yuv_to_rgb709(float y,float u,float v,float * r,float * g,float * b)679 yuv_to_rgb709(float y,
680               float u,
681               float v,
682               float *r,
683               float *g,
684               float *b)
685 {
686     /// ref: https://en.wikipedia.org/wiki/YUV#HDTV_with_BT.709
687     *r = y               + 1.28033f * v,
688     *g = y - 0.21482f * u - 0.38059f * v;
689     *b = y + 2.12798f * u;
690 } // yuv_to_rgb
691 
692 static inline
693 float
labf(float x)694 labf(float x)
695 {
696     return ( (x) >= 0.008856f ? ( std::pow(x, (float)1 / 3) ) : (7.787f * x + 16.0f / 116) );
697 }
698 
699 // Convert pixel values from XYZ to Lab color spaces.
700 // Uses the standard D65 white point.
701 void
xyz_to_lab(float x,float y,float z,float * l,float * a,float * b)702 xyz_to_lab(float x,
703            float y,
704            float z,
705            float *l,
706            float *a,
707            float *b)
708 {
709     const float fx = labf( x / (0.412453f + 0.357580f + 0.180423f) );
710     const float fy = labf( y / (0.212671f + 0.715160f + 0.072169f) );
711     const float fz = labf( z / (0.019334f + 0.119193f + 0.950227f) );
712 
713     *l = 116 * fy - 16;
714     *a = 500 * (fx - fy);
715     *b = 200 * (fy - fz);
716 }
717 
718 static inline
719 float
labfi(float x)720 labfi(float x)
721 {
722     return ( x >= 0.206893f ? (x * x * x) : ( (x - 16.0f / 116) / 7.787f ) );
723 }
724 
725 // Convert pixel values from Lab to XYZ color spaces.
726 // Uses the standard D65 white point.
727 void
lab_to_xyz(float l,float a,float b,float * x,float * y,float * z)728 lab_to_xyz(float l,
729            float a,
730            float b,
731            float *x,
732            float *y,
733            float *z)
734 {
735     const float cy = (l + 16) / 116;
736 
737     *y = (0.212671f + 0.715160f + 0.072169f) * labfi(cy);
738     const float cx = a / 500 + cy;
739     *x = (0.412453f + 0.357580f + 0.180423f) * labfi(cx);
740     const float cz = cy - b / 200;
741     *z = (0.019334f + 0.119193f + 0.950227f) * labfi(cz);
742 }
743 
744 // Convert pixel values from RGB to Lab color spaces.
745 // Uses the standard D65 white point.
746 void
rgb709_to_lab(float r,float g,float b,float * l,float * a,float * b_)747 rgb709_to_lab(float r,
748               float g,
749               float b,
750               float *l,
751               float *a,
752               float *b_)
753 {
754     float x, y, z;
755 
756     rgb709_to_xyz(r, g, b, &x, &y, &z);
757     xyz_to_lab(x, y, z, l, a, b_);
758 }
759 
760 // Convert pixel values from RGB to Lab color spaces.
761 // Uses the standard D65 white point.
762 void
lab_to_rgb709(float l,float a,float b,float * r,float * g,float * b_)763 lab_to_rgb709(float l,
764               float a,
765               float b,
766               float *r,
767               float *g,
768               float *b_)
769 {
770     float x, y, z;
771 
772     lab_to_xyz(l, a, b, &x, &y, &z);
773     xyz_to_rgb709(x, y, z, r, g, b_);
774 }
775 }         // namespace Color
776 } //namespace OFX
777 
778