1 /* ***** BEGIN LICENSE BLOCK *****
2  * This file is part of openfx-misc <https://github.com/devernay/openfx-misc>,
3  * Copyright (C) 2013-2018 INRIA
4  *
5  * openfx-misc is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * openfx-misc is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with openfx-misc.  If not, see <http://www.gnu.org/licenses/gpl-2.0.html>
17  * ***** END LICENSE BLOCK ***** */
18 
19 /*
20  * OFX ColorTransform plugin.
21  */
22 
23 #include <cmath>
24 
25 #include "ofxsProcessing.H"
26 #include "ofxsMaskMix.h"
27 #include "ofxsMacros.h"
28 #include "ofxsLut.h"
29 
30 using namespace OFX;
31 
32 OFXS_NAMESPACE_ANONYMOUS_ENTER
33 
34 #define kPluginRGBToHSVName "RGBToHSV"
35 #define kPluginRGBToHSVDescription "Convert from linear RGB to HSV color model (hue, saturation, value, as defined by A. R. Smith in 1978). H is in degrees, S and V are in the same units as RGB. RGB is gamma-compressed using the sRGB Opto-Electronic Transfer Function (OETF) before conversion."
36 #define kPluginRGBToHSVIdentifier "net.sf.openfx.RGBToHSV"
37 
38 #define kPluginHSVToRGBName "HSVToRGB"
39 #define kPluginHSVToRGBDescription "Convert from HSV color model (hue, saturation, value, as defined by A. R. Smith in 1978) to linear RGB. H is in degrees, S and V are in the same units as RGB. RGB is gamma-decompressed using the sRGB Electro-Optical Transfer Function (EOTF) after conversion."
40 #define kPluginHSVToRGBIdentifier "net.sf.openfx.HSVToRGB"
41 
42 #define kPluginRGBToHSLName "RGBToHSL"
43 #define kPluginRGBToHSLDescription "Convert from RGB to HSL color model (hue, saturation, lightness, as defined by Joblove and Greenberg in 1978). H is in degrees, S and L are in the same units as RGB. RGB is gamma-compressed using the sRGB Opto-Electronic Transfer Function (OETF) before conversion."
44 #define kPluginRGBToHSLIdentifier "net.sf.openfx.RGBToHSL"
45 
46 #define kPluginHSLToRGBName "HSLToRGB"
47 #define kPluginHSLToRGBDescription "Convert from HSL color model (hue, saturation, lightness, as defined by Joblove and Greenberg in 1978) to linear RGB. H is in degrees, S and L are in the same units as RGB. RGB is gamma-decompressed using the sRGB Electro-Optical Transfer Function (EOTF) after conversion."
48 #define kPluginHSLToRGBIdentifier "net.sf.openfx.HSLToRGB"
49 
50 #define kPluginRGBToHSIName "RGBToHSI"
51 #define kPluginRGBToHSIDescription "Convert from linear RGB to HSI color model (hue, saturation, intensity, as defined by Gonzalez and Woods in 1992). H is in degrees, S and I are in the same units as RGB. RGB is gamma-compressed using the sRGB Opto-Electronic Transfer Function (OETF) before conversion.\n" \
52     "The HSI colour space (hue, saturation and intensity) attempts to produce a more intuitive representation of colour. The I axis represents the luminance information. The H and S axes are polar coordinates on the plane orthogonal to I. H is the angle, specified such that red is at zero, green at 120 degrees, and blue at 240 degrees. Hue thus represents what humans implicitly understand as colour. S is the magnitude of the colour vector projected in the plane orthogonal to I, and so represents the difference between pastel colours (low saturation) and vibrant colours (high saturation). The main drawback of this colour space is that hue is undefined if saturation is zero, making error propagation in transformations from the RGB colour space more complicated.\n" \
53     "It should also be noted that, although the HSI colour space may be more intuitive, is not \"perceptual\", in the sense that small displacements of equal size in different parts of the colour space will be perceived by human observers as changes of different magnitude. Attempts have been made to define such colour spaces: CIE-LAB and CIE-LUV are two examples."
54 #define kPluginRGBToHSIIdentifier "net.sf.openfx.RGBToHSI"
55 
56 #define kPluginHSIToRGBName "HSIToRGB"
57 #define kPluginHSIToRGBDescription "Convert from HSI color model (hue, saturation, intensity, as defined by Gonzalez and Woods in 1992) to linear RGB. H is in degrees, S and I are in the same units as RGB. RGB is gamma-decompressed using the sRGB Electro-Optical Transfer Function (EOTF) after conversion.\n" \
58     "The HSI colour space (hue, saturation and intensity) attempts to produce a more intuitive representation of colour. The I axis represents the luminance information. The H and S axes are polar coordinates on the plane orthogonal to I. H is the angle, specified such that red is at zero, green at 120 degrees, and blue at 240 degrees. Hue thus represents what humans implicitly understand as colour. S is the magnitude of the colour vector projected in the plane orthogonal to I, and so represents the difference between pastel colours (low saturation) and vibrant colours (high saturation). The main drawback of this colour space is that hue is undefined if saturation is zero, making error propagation in transformations from the RGB colour space more complicated.\n" \
59     "It should also be noted that, although the HSI colour space may be more intuitive, is not \"perceptual\", in the sense that small displacements of equal size in different parts of the colour space will be perceived by human observers as changes of different magnitude. Attempts have been made to define such colour spaces: CIE-LAB and CIE-LUV are two examples."
60 #define kPluginHSIToRGBIdentifier "net.sf.openfx.HSIToRGB"
61 
62 #define kPluginRGBToYCbCr601Name "RGBToYCbCr601"
63 #define kPluginRGBToYCbCr601Description "Convert from linear RGB to YCbCr color model (ITU.BT-601). RGB is gamma-compressed using the sRGB Opto-Electronic Transfer Function (OETF) before conversion."
64 #define kPluginRGBToYCbCr601Identifier "net.sf.openfx.RGBToYCbCr601"
65 
66 #define kPluginYCbCrToRGB601Name "YCbCrToRGB601"
67 #define kPluginYCbCrToRGB601Description "Convert from YCbCr color model (ITU.BT-601) to linear RGB. RGB is gamma-decompressed using the sRGB Electro-Optical Transfer Function (EOTF) after conversion."
68 #define kPluginYCbCrToRGB601Identifier "net.sf.openfx.YCbCrToRGB601"
69 
70 #define kPluginRGBToYCbCr709Name "RGBToYCbCr709"
71 #define kPluginRGBToYCbCr709Description "Convert from linear RGB to YCbCr color model (ITU.BT-709). RGB is gamma-compressed using the Rec.709 Opto-Electronic Transfer Function (OETF) before conversion."
72 #define kPluginRGBToYCbCr709Identifier "net.sf.openfx.RGBToYCbCr709"
73 
74 #define kPluginYCbCrToRGB709Name "YCbCrToRGB709"
75 #define kPluginYCbCrToRGB709Description "Convert from YCbCr color model (ITU.BT-709) to linear RGB. RGB is gamma-decompressed using the Rec.709 Electro-Optical Transfer Function (EOTF) after conversion."
76 #define kPluginYCbCrToRGB709Identifier "net.sf.openfx.YCbCrToRGB709"
77 
78 #define kPluginRGBToYPbPr601Name "RGBToYPbPr601"
79 #define kPluginRGBToYPbPr601Description "Convert from RGB to YPbPr color model (ITU.BT-601). RGB is gamma-compressed using the sRGB Opto-Electronic Transfer Function (OETF) before conversion."
80 #define kPluginRGBToYPbPr601Identifier "net.sf.openfx.RGBToYPbPr601"
81 
82 #define kPluginYPbPrToRGB601Name "YPbPrToRGB601"
83 #define kPluginYPbPrToRGB601Description "Convert from YPbPr color model (ITU.BT-601) to RGB. RGB is gamma-decompressed using the sRGB Electro-Optical Transfer Function (EOTF) after conversion."
84 #define kPluginYPbPrToRGB601Identifier "net.sf.openfx.YPbPrToRGB601"
85 
86 #define kPluginRGBToYPbPr709Name "RGBToYPbPr709"
87 #define kPluginRGBToYPbPr709Description "Convert from RGB to YPbPr color model (ITU.BT-709). RGB is gamma-compressed using the Rec.709 Opto-Electronic Transfer Function (OETF) before conversion."
88 #define kPluginRGBToYPbPr709Identifier "net.sf.openfx.RGBToYPbPr709"
89 
90 #define kPluginYPbPrToRGB709Name "YPbPrToRGB709"
91 #define kPluginYPbPrToRGB709Description "Convert from YPbPr color model (ITU.BT-709) to RGB. RGB is gamma-decompressed using the Rec.709 Electro-Optical Transfer Function (EOTF) after conversion."
92 #define kPluginYPbPrToRGB709Identifier "net.sf.openfx.YPbPrToRGB709"
93 
94 #define kPluginRGBToYUV601Name "RGBToYUV601"
95 #define kPluginRGBToYUV601Description "Convert from RGB to YUV color model (ITU.BT-601). RGB is gamma-compressed using the sRGB Opto-Electronic Transfer Function (OETF) before conversion."
96 #define kPluginRGBToYUV601Identifier "net.sf.openfx.RGBToYUV601"
97 
98 #define kPluginYUVToRGB601Name "YUVToRGB601"
99 #define kPluginYUVToRGB601Description "Convert from YUV color model (ITU.BT-601) to RGB. RGB is gamma-decompressed using the sRGB Electro-Optical Transfer Function (EOTF) after conversion."
100 #define kPluginYUVToRGB601Identifier "net.sf.openfx.YUVToRGB601"
101 
102 #define kPluginRGBToYUV709Name "RGBToYUV709"
103 #define kPluginRGBToYUV709Description "Convert from RGB to YUV color model (ITU.BT-709). RGB is gamma-compressed using the Rec.709 Opto-Electronic Transfer Function (OETF) before conversion."
104 #define kPluginRGBToYUV709Identifier "net.sf.openfx.RGBToYUV709"
105 
106 #define kPluginYUVToRGB709Name "YUVToRGB709"
107 #define kPluginYUVToRGB709Description "Convert from YUV color model (ITU.BT-709) to RGB. RGB is gamma-decompressed using the Rec.709 Electro-Optical Transfer Function (EOTF) after conversion."
108 #define kPluginYUVToRGB709Identifier "net.sf.openfx.YUVToRGB709"
109 
110 
111 #define kPluginRGB709ToXYZName "RGB709ToXYZ"
112 #define kPluginRGB709ToXYZDescription "Convert from RGB (Rec.709 with D65 illuminant) to XYZ color model. X, Y and Z are in the same units as RGB."
113 #define kPluginRGB709ToXYZIdentifier "net.sf.openfx.RGB709ToXYZ"
114 
115 #define kPluginXYZToRGB709Name "XYZToRGB709"
116 #define kPluginXYZToRGB709Description "Convert from XYZ color model to RGB (Rec.709 with D65 illuminant). X, Y and Z are in the same units as RGB."
117 #define kPluginXYZToRGB709Identifier "net.sf.openfx.XYZToRGB709"
118 
119 #define kPluginRGB709ToLabName "RGB709ToLab"
120 #define kPluginRGB709ToLabDescription "Convert from RGB (Rec.709 with D65 illuminant) to L*a*b color model. L*a*b coordinates are divided by 100 for better visualization."
121 #define kPluginRGB709ToLabIdentifier "net.sf.openfx.RGB709ToLab"
122 
123 #define kPluginLabToRGB709Name "LabToRGB709"
124 #define kPluginLabToRGB709Description "Convert from L*a*b color model to RGB (Rec.709 with D65 illuminant). L*a*b coordinates are divided by 100 for better visualization."
125 #define kPluginLabToRGB709Identifier "net.sf.openfx.LabToRGB709"
126 
127 #define kPluginXYZToLabName "XYZToLab"
128 #define kPluginXYZToLabDescription "Convert from CIE XYZ color space to CIE L*a*b color space. L*a*b coordinates are divided by 100 for better visualization."
129 #define kPluginXYZToLabIdentifier "net.sf.openfx.XYZToLab"
130 
131 #define kPluginLabToXYZName "LabToXYZ"
132 #define kPluginLabToXYZDescription "Convert from CIE L*a*b color space to CIE XYZ color space. L*a*b coordinates are divided by 100 for better visualization."
133 #define kPluginLabToXYZIdentifier "net.sf.openfx.LabToXYZ"
134 
135 #define kPluginXYZToxyYName "XYZToxyY"
136 #define kPluginXYZToxyYDescription "Convert from CIE XYZ color space to CIE xyY color space."
137 #define kPluginXYZToxyYIdentifier "net.sf.openfx.XYZToxyY"
138 
139 #define kPluginxyYToXYZName "xyYToXYZ"
140 #define kPluginxyYToXYZDescription "Convert from CIE xyY color space to CIE XYZ color space."
141 #define kPluginxyYToXYZIdentifier "net.sf.openfx.xyYToXYZ"
142 
143 #define kPluginGrouping "Color/Transform"
144 
145 // history:
146 // 1.0 initial version
147 // 2.0 named plugins more consistently, add a few conversions
148 #define kPluginVersionMajor 1 // Incrementing this number means that you have broken backwards compatibility of the plug-in.
149 #define kPluginVersionMinor 0 // Increment this when you have fixed a bug or made it faster.
150 
151 #define kSupportsTiles 1
152 #define kSupportsMultiResolution 1
153 #define kSupportsRenderScale 1
154 #define kSupportsMultipleClipPARs false
155 #define kSupportsMultipleClipDepths false
156 #define kRenderThreadSafety eRenderFullySafe
157 
158 #define kParamPremultRGBToXXXLabel "Unpremult"
159 #define kParamPremultRGBToXXXHint \
160     "Divide the image by the alpha channel before processing. " \
161     "Use if the input images are premultiplied."
162 
163 #define kParamPremultXXXToRGBLabel "Premult"
164 #define kParamPremultXXXToRGBHint \
165     "Multiply the image by the alpha channel after processing. " \
166     "Use to get premultiplied output images."
167 
168 #define kParamPremultChanged "premultChanged"
169 
170 
171 enum ColorTransformEnum
172 {
173     eColorTransformRGBToHSV,
174     eColorTransformHSVToRGB,
175     eColorTransformRGBToHSL,
176     eColorTransformHSLToRGB,
177     eColorTransformRGBToHSI,
178     eColorTransformHSIToRGB,
179     eColorTransformRGBToYCbCr601,
180     eColorTransformYCbCrToRGB601,
181     eColorTransformRGBToYCbCr709,
182     eColorTransformYCbCrToRGB709,
183     eColorTransformRGBToYPbPr601,
184     eColorTransformYPbPrToRGB601,
185     eColorTransformRGBToYPbPr709,
186     eColorTransformYPbPrToRGB709,
187     eColorTransformRGBToYUV601,
188     eColorTransformYUVToRGB601,
189     eColorTransformRGBToYUV709,
190     eColorTransformYUVToRGB709,
191     eColorTransformRGB709ToXYZ,
192     eColorTransformXYZToRGB709,
193     eColorTransformRGB709ToLab,
194     eColorTransformLabToRGB709,
195     eColorTransformXYZToLab,
196     eColorTransformLabToXYZ,
197     eColorTransformXYZToxyY,
198     eColorTransformxyYToXYZ,
199 };
200 
201 #define toRGB(e)   ( (e) == eColorTransformHSVToRGB || \
202                      (e) == eColorTransformHSLToRGB || \
203                      (e) == eColorTransformHSIToRGB || \
204                      (e) == eColorTransformYCbCrToRGB601 || \
205                      (e) == eColorTransformYCbCrToRGB709 || \
206                      (e) == eColorTransformYPbPrToRGB601 || \
207                      (e) == eColorTransformYPbPrToRGB709 || \
208                      (e) == eColorTransformYUVToRGB601 || \
209                      (e) == eColorTransformYUVToRGB709 || \
210                      (e) == eColorTransformXYZToRGB709 || \
211                      (e) == eColorTransformLabToRGB709 )
212 
213 #define fromRGB(e) ( !toRGB(e) && ( (e) != eColorTransformXYZToLab ) && ( (e) != eColorTransformLabToXYZ ) && ( (e) != eColorTransformXYZToxyY ) && ( (e) != eColorTransformxyYToXYZ ) )
214 
215 class ColorTransformProcessorBase
216     : public ImageProcessor
217 {
218 protected:
219     const Image *_srcImg;
220     bool _premult;
221     int _premultChannel;
222     double _mix;
223 
224 public:
225 
ColorTransformProcessorBase(ImageEffect & instance)226     ColorTransformProcessorBase(ImageEffect &instance)
227         : ImageProcessor(instance)
228         , _srcImg(NULL)
229         , _premult(false)
230         , _premultChannel(3)
231         , _mix(1.)
232     {
233     }
234 
setSrcImg(const Image * v)235     void setSrcImg(const Image *v) {_srcImg = v; }
236 
setValues(bool premult,int premultChannel)237     void setValues(bool premult,
238                    int premultChannel)
239     {
240         _premult = premult;
241         _premultChannel = premultChannel;
242     }
243 
244 private:
245 };
246 
247 
248 template <class PIX, int nComponents, int maxValue, ColorTransformEnum transform>
249 class ColorTransformProcessor
250     : public ColorTransformProcessorBase
251 {
252 public:
ColorTransformProcessor(ImageEffect & instance)253     ColorTransformProcessor(ImageEffect &instance)
254         : ColorTransformProcessorBase(instance)
255     {
256     }
257 
multiThreadProcessImages(OfxRectI procWindow)258     void multiThreadProcessImages(OfxRectI procWindow)
259     {
260         assert(nComponents == 3 || nComponents == 4);
261         assert(_dstImg);
262         float unpPix[4];
263         float tmpPix[4];
264         const bool dounpremult = _premult && fromRGB(transform);
265         const bool dopremult = _premult && toRGB(transform);
266 
267         for (int y = procWindow.y1; y < procWindow.y2; y++) {
268             if ( _effect.abort() ) {
269                 break;
270             }
271 
272             PIX *dstPix = (PIX *) _dstImg->getPixelAddress(procWindow.x1, y);
273 
274             for (int x = procWindow.x1; x < procWindow.x2; x++) {
275                 const PIX *srcPix = (const PIX *)  (_srcImg ? _srcImg->getPixelAddress(x, y) : 0);
276                 ofxsUnPremult<PIX, nComponents, maxValue>(srcPix, unpPix, dounpremult, _premultChannel);
277                 switch (transform) {
278                 case eColorTransformRGBToHSV:
279                     unpPix[0] = Color::to_func_srgb(unpPix[0]);
280                     unpPix[1] = Color::to_func_srgb(unpPix[1]);
281                     unpPix[2] = Color::to_func_srgb(unpPix[2]);
282                     Color::rgb_to_hsv(unpPix[0], unpPix[1], unpPix[2], &tmpPix[0], &tmpPix[1], &tmpPix[2]);
283                     break;
284 
285                 case eColorTransformHSVToRGB:
286                     Color::hsv_to_rgb(unpPix[0], unpPix[1], unpPix[2], &tmpPix[0], &tmpPix[1], &tmpPix[2]);
287                     tmpPix[0] = Color::from_func_srgb(tmpPix[0]);
288                     tmpPix[1] = Color::from_func_srgb(tmpPix[1]);
289                     tmpPix[2] = Color::from_func_srgb(tmpPix[2]);
290                     break;
291 
292                 case eColorTransformRGBToHSL:
293                     unpPix[0] = Color::to_func_srgb(unpPix[0]);
294                     unpPix[1] = Color::to_func_srgb(unpPix[1]);
295                     unpPix[2] = Color::to_func_srgb(unpPix[2]);
296                     Color::rgb_to_hsl(unpPix[0], unpPix[1], unpPix[2], &tmpPix[0], &tmpPix[1], &tmpPix[2]);
297                     break;
298 
299                 case eColorTransformHSLToRGB:
300                     Color::hsl_to_rgb(unpPix[0], unpPix[1], unpPix[2], &tmpPix[0], &tmpPix[1], &tmpPix[2]);
301                     tmpPix[0] = Color::from_func_srgb(tmpPix[0]);
302                     tmpPix[1] = Color::from_func_srgb(tmpPix[1]);
303                     tmpPix[2] = Color::from_func_srgb(tmpPix[2]);
304                     break;
305 
306                 case eColorTransformRGBToHSI:
307                     unpPix[0] = Color::to_func_srgb(unpPix[0]);
308                     unpPix[1] = Color::to_func_srgb(unpPix[1]);
309                     unpPix[2] = Color::to_func_srgb(unpPix[2]);
310                     Color::rgb_to_hsi(unpPix[0], unpPix[1], unpPix[2], &tmpPix[0], &tmpPix[1], &tmpPix[2]);
311                     break;
312 
313                 case eColorTransformHSIToRGB:
314                     Color::hsi_to_rgb(unpPix[0], unpPix[1], unpPix[2], &tmpPix[0], &tmpPix[1], &tmpPix[2]);
315                     tmpPix[0] = Color::from_func_srgb(tmpPix[0]);
316                     tmpPix[1] = Color::from_func_srgb(tmpPix[1]);
317                     tmpPix[2] = Color::from_func_srgb(tmpPix[2]);
318                     break;
319 
320 
321                 case eColorTransformRGBToYCbCr601:
322                     unpPix[0] = Color::to_func_srgb(unpPix[0]);
323                     unpPix[1] = Color::to_func_srgb(unpPix[1]);
324                     unpPix[2] = Color::to_func_srgb(unpPix[2]);
325                     Color::rgb_to_ycbcr601(unpPix[0], unpPix[1], unpPix[2], &tmpPix[0], &tmpPix[1], &tmpPix[2]);
326                     break;
327 
328                 case eColorTransformYCbCrToRGB601:
329                     Color::ycbcr_to_rgb601(unpPix[0], unpPix[1], unpPix[2], &tmpPix[0], &tmpPix[1], &tmpPix[2]);
330                     tmpPix[0] = Color::from_func_srgb(tmpPix[0]);
331                     tmpPix[1] = Color::from_func_srgb(tmpPix[1]);
332                     tmpPix[2] = Color::from_func_srgb(tmpPix[2]);
333                     break;
334 
335                 case eColorTransformRGBToYCbCr709:
336                     unpPix[0] = Color::to_func_Rec709(unpPix[0]);
337                     unpPix[1] = Color::to_func_Rec709(unpPix[1]);
338                     unpPix[2] = Color::to_func_Rec709(unpPix[2]);
339                     Color::rgb_to_ycbcr709(unpPix[0], unpPix[1], unpPix[2], &tmpPix[0], &tmpPix[1], &tmpPix[2]);
340                     break;
341 
342                 case eColorTransformYCbCrToRGB709:
343                     Color::ycbcr_to_rgb709(unpPix[0], unpPix[1], unpPix[2], &tmpPix[0], &tmpPix[1], &tmpPix[2]);
344                     tmpPix[0] = Color::from_func_Rec709(tmpPix[0]);
345                     tmpPix[1] = Color::from_func_Rec709(tmpPix[1]);
346                     tmpPix[2] = Color::from_func_Rec709(tmpPix[2]);
347                     break;
348 
349                 case eColorTransformRGBToYPbPr601:
350                     unpPix[0] = Color::to_func_srgb(unpPix[0]);
351                     unpPix[1] = Color::to_func_srgb(unpPix[1]);
352                     unpPix[2] = Color::to_func_srgb(unpPix[2]);
353                     Color::rgb_to_ypbpr601(unpPix[0], unpPix[1], unpPix[2], &tmpPix[0], &tmpPix[1], &tmpPix[2]);
354                     break;
355 
356                 case eColorTransformYPbPrToRGB601:
357                     Color::ypbpr_to_rgb601(unpPix[0], unpPix[1], unpPix[2], &tmpPix[0], &tmpPix[1], &tmpPix[2]);
358                     tmpPix[0] = Color::from_func_srgb(tmpPix[0]);
359                     tmpPix[1] = Color::from_func_srgb(tmpPix[1]);
360                     tmpPix[2] = Color::from_func_srgb(tmpPix[2]);
361                     break;
362 
363                 case eColorTransformRGBToYPbPr709:
364                     unpPix[0] = Color::to_func_Rec709(unpPix[0]);
365                     unpPix[1] = Color::to_func_Rec709(unpPix[1]);
366                     unpPix[2] = Color::to_func_Rec709(unpPix[2]);
367                     Color::rgb_to_ypbpr709(unpPix[0], unpPix[1], unpPix[2], &tmpPix[0], &tmpPix[1], &tmpPix[2]);
368                     break;
369 
370                 case eColorTransformYPbPrToRGB709:
371                     Color::ypbpr_to_rgb709(unpPix[0], unpPix[1], unpPix[2], &tmpPix[0], &tmpPix[1], &tmpPix[2]);
372                     tmpPix[0] = Color::from_func_Rec709(tmpPix[0]);
373                     tmpPix[1] = Color::from_func_Rec709(tmpPix[1]);
374                     tmpPix[2] = Color::from_func_Rec709(tmpPix[2]);
375                     break;
376 
377                 case eColorTransformRGBToYUV601:
378                     unpPix[0] = Color::to_func_srgb(unpPix[0]);
379                     unpPix[1] = Color::to_func_srgb(unpPix[1]);
380                     unpPix[2] = Color::to_func_srgb(unpPix[2]);
381                     Color::rgb_to_yuv601(unpPix[0], unpPix[1], unpPix[2], &tmpPix[0], &tmpPix[1], &tmpPix[2]);
382                     break;
383 
384                 case eColorTransformYUVToRGB601:
385                     Color::yuv_to_rgb601(unpPix[0], unpPix[1], unpPix[2], &tmpPix[0], &tmpPix[1], &tmpPix[2]);
386                     tmpPix[0] = Color::from_func_srgb(tmpPix[0]);
387                     tmpPix[1] = Color::from_func_srgb(tmpPix[1]);
388                     tmpPix[2] = Color::from_func_srgb(tmpPix[2]);
389                     break;
390 
391                 case eColorTransformRGBToYUV709:
392                     unpPix[0] = Color::to_func_Rec709(unpPix[0]);
393                     unpPix[1] = Color::to_func_Rec709(unpPix[1]);
394                     unpPix[2] = Color::to_func_Rec709(unpPix[2]);
395                     Color::rgb_to_yuv709(unpPix[0], unpPix[1], unpPix[2], &tmpPix[0], &tmpPix[1], &tmpPix[2]);
396                     break;
397 
398                 case eColorTransformYUVToRGB709:
399                     Color::yuv_to_rgb709(unpPix[0], unpPix[1], unpPix[2], &tmpPix[0], &tmpPix[1], &tmpPix[2]);
400                     tmpPix[0] = Color::from_func_Rec709(tmpPix[0]);
401                     tmpPix[1] = Color::from_func_Rec709(tmpPix[1]);
402                     tmpPix[2] = Color::from_func_Rec709(tmpPix[2]);
403                     break;
404 
405                 case eColorTransformRGB709ToXYZ:
406                     Color::rgb709_to_xyz(unpPix[0], unpPix[1], unpPix[2], &tmpPix[0], &tmpPix[1], &tmpPix[2]);
407                     break;
408 
409                 case eColorTransformXYZToRGB709:
410                     Color::xyz_to_rgb709(unpPix[0], unpPix[1], unpPix[2], &tmpPix[0], &tmpPix[1], &tmpPix[2]);
411                     break;
412 
413                 case eColorTransformRGB709ToLab:
414                     Color::rgb709_to_lab(unpPix[0], unpPix[1], unpPix[2], &tmpPix[0], &tmpPix[1], &tmpPix[2]);
415                     tmpPix[0] /= 100;
416                     tmpPix[1] /= 100;
417                     tmpPix[2] /= 100;
418                     break;
419 
420                 case eColorTransformLabToRGB709:
421                     unpPix[0] *= 100;
422                     unpPix[1] *= 100;
423                     unpPix[2] *= 100;
424                     Color::lab_to_rgb709(unpPix[0], unpPix[1], unpPix[2], &tmpPix[0], &tmpPix[1], &tmpPix[2]);
425                     break;
426 
427                 case eColorTransformXYZToLab:
428                     Color::xyz_to_lab(unpPix[0], unpPix[1], unpPix[2], &tmpPix[0], &tmpPix[1], &tmpPix[2]);
429                     tmpPix[0] /= 100;
430                     tmpPix[1] /= 100;
431                     tmpPix[2] /= 100;
432                     break;
433 
434                 case eColorTransformLabToXYZ:
435                     unpPix[0] *= 100;
436                     unpPix[1] *= 100;
437                     unpPix[2] *= 100;
438                     Color::lab_to_xyz(unpPix[0], unpPix[1], unpPix[2], &tmpPix[0], &tmpPix[1], &tmpPix[2]);
439                     break;
440 
441                 case eColorTransformXYZToxyY: {
442                     float X = unpPix[0];
443                     float Y = unpPix[1];
444                     float Z = unpPix[2];
445                     float XYZ = X + Y + Z;
446                     float invXYZ = XYZ <= 0 ? 0. : (1. / XYZ);
447                     tmpPix[0] = X * invXYZ;
448                     tmpPix[1] = Y * invXYZ;
449                     tmpPix[2] = Y;
450                     break;
451                 }
452                 case eColorTransformxyYToXYZ: {
453                     float x = unpPix[0];
454                     float y = unpPix[1];
455                     float Y = unpPix[2];
456                     float invy = (y <= 0) ? 0. : (1 / y);
457                     tmpPix[0] = x * Y * invy;
458                     tmpPix[1] = Y;
459                     tmpPix[2] = (1 - x - y) * Y * invy;
460                     break;
461                 }
462                 } // switch
463                 tmpPix[3] = unpPix[3];
464                 ofxsPremultMaskMixPix<PIX, nComponents, maxValue, true>(tmpPix, dopremult, _premultChannel, x, y, srcPix, /*doMasking=*/ false, /*maskImg=*/ NULL, /*mix=*/ 1.f, /*maskInvert=*/ false, dstPix);
465                 // increment the dst pixel
466                 dstPix += nComponents;
467             }
468         }
469     } // multiThreadProcessImages
470 };
471 
472 
473 ////////////////////////////////////////////////////////////////////////////////
474 /** @brief The plugin that does our work */
475 template <ColorTransformEnum transform>
476 class ColorTransformPlugin
477     : public ImageEffect
478 {
479 public:
480     /** @brief ctor */
ColorTransformPlugin(OfxImageEffectHandle handle)481     ColorTransformPlugin(OfxImageEffectHandle handle)
482         : ImageEffect(handle)
483         , _dstClip(NULL)
484         , _srcClip(NULL)
485         , _premult(NULL)
486         , _premultChannel(NULL)
487         , _premultChanged(NULL)
488     {
489         _dstClip = fetchClip(kOfxImageEffectOutputClipName);
490         assert( _dstClip && (!_dstClip->isConnected() || _dstClip->getPixelComponents() == ePixelComponentRGB ||
491                              _dstClip->getPixelComponents() == ePixelComponentRGBA) );
492         _srcClip = getContext() == eContextGenerator ? NULL : fetchClip(kOfxImageEffectSimpleSourceClipName);
493         assert( (!_srcClip && getContext() == eContextGenerator) ||
494                 ( _srcClip && (!_srcClip->isConnected() || _srcClip->getPixelComponents() ==  ePixelComponentRGB ||
495                                _srcClip->getPixelComponents() == ePixelComponentRGBA) ) );
496         if ( fromRGB(transform) || toRGB(transform) ) {
497             _premult = fetchBooleanParam(kParamPremult);
498             _premultChannel = fetchChoiceParam(kParamPremultChannel);
499             assert(_premult && _premultChannel);
500             _premultChanged = fetchBooleanParam(kParamPremultChanged);
501             assert(_premultChanged);
502         }
503     }
504 
505 private:
506     /* Override the render */
507     virtual void render(const RenderArguments &args) OVERRIDE FINAL;
508 
509     /* set up and run a processor */
510     void setupAndProcess(ColorTransformProcessorBase &, const RenderArguments &args);
511 
512     /** @brief get the clip preferences */
513     virtual void getClipPreferences(ClipPreferencesSetter &clipPreferences) OVERRIDE FINAL;
514 
515     /** @brief called when a clip has just been changed in some way (a rewire maybe) */
516     virtual void changedClip(const InstanceChangedArgs &args, const std::string &clipName) OVERRIDE FINAL;
517     virtual void changedParam(const InstanceChangedArgs &args, const std::string &paramName) OVERRIDE FINAL;
518 
519 private:
520     // do not need to delete these, the ImageEffect is managing them for us
521     Clip *_dstClip;
522     Clip *_srcClip;
523     BooleanParam* _premult;
524     ChoiceParam* _premultChannel;
525     BooleanParam* _premultChanged; // set to true the first time the user connects src
526 };
527 
528 
529 ////////////////////////////////////////////////////////////////////////////////
530 /** @brief render for the filter */
531 
532 ////////////////////////////////////////////////////////////////////////////////
533 // basic plugin render function, just a skelington to instantiate templates from
534 
535 /* set up and run a processor */
536 template <ColorTransformEnum transform>
537 void
setupAndProcess(ColorTransformProcessorBase & processor,const RenderArguments & args)538 ColorTransformPlugin<transform>::setupAndProcess(ColorTransformProcessorBase &processor,
539                                                  const RenderArguments &args)
540 {
541     auto_ptr<Image> dst( _dstClip->fetchImage(args.time) );
542 
543     if ( !dst.get() ) {
544         throwSuiteStatusException(kOfxStatFailed);
545     }
546     BitDepthEnum dstBitDepth    = dst->getPixelDepth();
547     PixelComponentEnum dstComponents  = dst->getPixelComponents();
548     if ( ( dstBitDepth != _dstClip->getPixelDepth() ) ||
549          ( dstComponents != _dstClip->getPixelComponents() ) ) {
550         setPersistentMessage(Message::eMessageError, "", "OFX Host gave image with wrong depth or components");
551         throwSuiteStatusException(kOfxStatFailed);
552     }
553     if ( (dst->getRenderScale().x != args.renderScale.x) ||
554          ( dst->getRenderScale().y != args.renderScale.y) ||
555          ( ( dst->getField() != eFieldNone) /* for DaVinci Resolve */ && ( dst->getField() != args.fieldToRender) ) ) {
556         setPersistentMessage(Message::eMessageError, "", "OFX Host gave image with wrong scale or field properties");
557         throwSuiteStatusException(kOfxStatFailed);
558     }
559     auto_ptr<const Image> src( ( _srcClip && _srcClip->isConnected() ) ?
560                                     _srcClip->fetchImage(args.time) : 0 );
561     if ( src.get() ) {
562         if ( (src->getRenderScale().x != args.renderScale.x) ||
563              ( src->getRenderScale().y != args.renderScale.y) ||
564              ( ( src->getField() != eFieldNone) /* for DaVinci Resolve */ && ( src->getField() != args.fieldToRender) ) ) {
565             setPersistentMessage(Message::eMessageError, "", "OFX Host gave image with wrong scale or field properties");
566             throwSuiteStatusException(kOfxStatFailed);
567         }
568         BitDepthEnum srcBitDepth      = src->getPixelDepth();
569         PixelComponentEnum srcComponents = src->getPixelComponents();
570         if ( (srcBitDepth != dstBitDepth) || (srcComponents != dstComponents) ) {
571             throwSuiteStatusException(kOfxStatErrImageFormat);
572         }
573     }
574 
575     processor.setDstImg( dst.get() );
576     processor.setSrcImg( src.get() );
577     processor.setRenderWindow(args.renderWindow);
578 
579     bool premult = false;
580     if (_premult) {
581         _premult->getValueAtTime(args.time, premult);
582     }
583     int premultChannel = 3;
584     if (_premultChannel) {
585         _premultChannel->getValueAtTime(args.time, premultChannel);
586     }
587 
588     processor.setValues(premult, premultChannel);
589     processor.process();
590 } // >::setupAndProcess
591 
592 // the overridden render function
593 template <ColorTransformEnum transform>
594 void
render(const RenderArguments & args)595 ColorTransformPlugin<transform>::render(const RenderArguments &args)
596 {
597     // instantiate the render code based on the pixel depth of the dst clip
598     BitDepthEnum dstBitDepth    = _dstClip->getPixelDepth();
599     PixelComponentEnum dstComponents  = _dstClip->getPixelComponents();
600 
601     assert( kSupportsMultipleClipPARs   || !_srcClip || _srcClip->getPixelAspectRatio() == _dstClip->getPixelAspectRatio() );
602     assert( kSupportsMultipleClipDepths || !_srcClip || _srcClip->getPixelDepth()       == _dstClip->getPixelDepth() );
603     assert(dstComponents == ePixelComponentRGB || dstComponents == ePixelComponentRGBA);
604     if (dstComponents == ePixelComponentRGBA) {
605         switch (dstBitDepth) {
606         case eBitDepthUByte: {
607             ColorTransformProcessor<unsigned char, 4, 255, transform> fred(*this);
608             setupAndProcess(fred, args);
609             break;
610         }
611         case eBitDepthUShort: {
612             ColorTransformProcessor<unsigned short, 4, 65535, transform> fred(*this);
613             setupAndProcess(fred, args);
614             break;
615         }
616         case eBitDepthFloat: {
617             ColorTransformProcessor<float, 4, 1, transform> fred(*this);
618             setupAndProcess(fred, args);
619             break;
620         }
621         default:
622             throwSuiteStatusException(kOfxStatErrUnsupported);
623         }
624     } else {
625         assert(dstComponents == ePixelComponentRGB);
626         switch (dstBitDepth) {
627         case eBitDepthUByte: {
628             ColorTransformProcessor<unsigned char, 3, 255, transform> fred(*this);
629             setupAndProcess(fred, args);
630             break;
631         }
632         case eBitDepthUShort: {
633             ColorTransformProcessor<unsigned short, 3, 65535, transform> fred(*this);
634             setupAndProcess(fred, args);
635             break;
636         }
637         case eBitDepthFloat: {
638             ColorTransformProcessor<float, 3, 1, transform> fred(*this);
639             setupAndProcess(fred, args);
640             break;
641         }
642         default:
643             throwSuiteStatusException(kOfxStatErrUnsupported);
644         }
645     }
646 } // >::render
647 
648 /* Override the clip preferences */
649 template <ColorTransformEnum transform>
650 void
getClipPreferences(ClipPreferencesSetter & clipPreferences)651 ColorTransformPlugin<transform>::getClipPreferences(ClipPreferencesSetter &clipPreferences)
652 {
653     if ( ( fromRGB(transform) || toRGB(transform) ) &&
654          _srcClip &&
655          ( !_srcClip->isConnected() || (_srcClip->getPixelComponents() ==  ePixelComponentRGBA) ) ) {
656         bool premult;
657         _premult->getValue(premult);
658         // set the premultiplication of _dstClip
659         if ( fromRGB(transform) ) {
660             // HSV is always unpremultiplied
661             clipPreferences.setOutputPremultiplication(eImageUnPreMultiplied);
662         } else {
663             // RGB
664             clipPreferences.setOutputPremultiplication(premult ? eImagePreMultiplied : eImageUnPreMultiplied);
665         }
666     }
667 }
668 
669 template <ColorTransformEnum transform>
670 void
changedClip(const InstanceChangedArgs & args,const std::string & clipName)671 ColorTransformPlugin<transform>::changedClip(const InstanceChangedArgs &args,
672                                              const std::string &clipName)
673 {
674     if ( ( fromRGB(transform) || toRGB(transform) ) &&
675          (clipName == kOfxImageEffectSimpleSourceClipName) &&
676          _srcClip && _srcClip->isConnected() &&
677          !_premultChanged->getValue() &&
678          ( args.reason == eChangeUserEdit) ) {
679         if (_srcClip->getPixelComponents() != ePixelComponentRGBA) {
680             _premult->setValue(false);
681         } else {
682             switch ( _srcClip->getPreMultiplication() ) {
683             case eImageOpaque:
684                 _premult->setValue(false);
685                 break;
686             case eImagePreMultiplied:
687                 _premult->setValue(true);
688                 break;
689             case eImageUnPreMultiplied:
690                 _premult->setValue(false);
691                 break;
692             }
693         }
694     }
695 }
696 
697 template <ColorTransformEnum transform>
698 void
changedParam(const InstanceChangedArgs & args,const std::string & paramName)699 ColorTransformPlugin<transform>::changedParam(const InstanceChangedArgs &args,
700                                               const std::string &paramName)
701 {
702     if ( ( fromRGB(transform) || toRGB(transform) ) && (paramName == kParamPremult) && (args.reason == eChangeUserEdit) ) {
703         _premultChanged->setValue(true);
704     }
705 }
706 
707 //mDeclarePluginFactory(ColorTransformPluginFactory, {ofxsThreadSuiteCheck();}, {});
708 template <ColorTransformEnum transform>
709 class ColorTransformPluginFactory
710     : public PluginFactoryHelper<ColorTransformPluginFactory<transform> >
711 {
712 public:
ColorTransformPluginFactory(const std::string & id,unsigned int verMaj,unsigned int verMin)713     ColorTransformPluginFactory(const std::string& id,
714                                 unsigned int verMaj,
715                                 unsigned int verMin) : PluginFactoryHelper<ColorTransformPluginFactory<transform> >(id, verMaj, verMin) {}
716 
load()717     virtual void load() OVERRIDE FINAL {ofxsThreadSuiteCheck();};
718     //virtual void unload() OVERRIDE FINAL {};
719     virtual void describe(ImageEffectDescriptor &desc) OVERRIDE FINAL;
720     virtual void describeInContext(ImageEffectDescriptor &desc, ContextEnum context) OVERRIDE FINAL;
721     virtual ImageEffect* createInstance(OfxImageEffectHandle handle, ContextEnum context) OVERRIDE FINAL;
722 };
723 
724 template <ColorTransformEnum transform>
725 void
describe(ImageEffectDescriptor & desc)726 ColorTransformPluginFactory<transform>::describe(ImageEffectDescriptor &desc)
727 {
728     // basic labels
729     switch (transform) {
730     case eColorTransformRGBToHSV:
731         desc.setLabel(kPluginRGBToHSVName);
732         desc.setPluginDescription(kPluginRGBToHSVDescription);
733         break;
734 
735     case eColorTransformHSVToRGB:
736         desc.setLabel(kPluginHSVToRGBName);
737         desc.setPluginDescription(kPluginHSVToRGBDescription);
738         break;
739 
740     case eColorTransformRGBToHSL:
741         desc.setLabel(kPluginRGBToHSLName);
742         desc.setPluginDescription(kPluginRGBToHSLDescription);
743         break;
744 
745     case eColorTransformHSLToRGB:
746         desc.setLabel(kPluginHSLToRGBName);
747         desc.setPluginDescription(kPluginHSLToRGBDescription);
748         break;
749 
750     case eColorTransformRGBToHSI:
751         desc.setLabel(kPluginRGBToHSIName);
752         desc.setPluginDescription(kPluginRGBToHSIDescription);
753         break;
754 
755     case eColorTransformHSIToRGB:
756         desc.setLabel(kPluginHSIToRGBName);
757         desc.setPluginDescription(kPluginHSIToRGBDescription);
758         break;
759 
760     case eColorTransformRGBToYCbCr601:
761         desc.setLabel(kPluginRGBToYCbCr601Name);
762         desc.setPluginDescription(kPluginRGBToYCbCr601Description);
763         break;
764 
765     case eColorTransformYCbCrToRGB601:
766         desc.setLabel(kPluginYCbCrToRGB601Name);
767         desc.setPluginDescription(kPluginYCbCrToRGB601Description);
768         break;
769 
770     case eColorTransformRGBToYCbCr709:
771         desc.setLabel(kPluginRGBToYCbCr709Name);
772         desc.setPluginDescription(kPluginRGBToYCbCr709Description);
773         break;
774 
775     case eColorTransformYCbCrToRGB709:
776         desc.setLabel(kPluginYCbCrToRGB709Name);
777         desc.setPluginDescription(kPluginYCbCrToRGB709Description);
778         break;
779 
780     case eColorTransformRGBToYPbPr601:
781         desc.setLabel(kPluginRGBToYPbPr601Name);
782         desc.setPluginDescription(kPluginRGBToYPbPr601Description);
783         break;
784 
785     case eColorTransformYPbPrToRGB601:
786         desc.setLabel(kPluginYPbPrToRGB601Name);
787         desc.setPluginDescription(kPluginYPbPrToRGB601Description);
788         break;
789 
790     case eColorTransformRGBToYPbPr709:
791         desc.setLabel(kPluginRGBToYPbPr709Name);
792         desc.setPluginDescription(kPluginRGBToYPbPr709Description);
793         break;
794 
795     case eColorTransformYPbPrToRGB709:
796         desc.setLabel(kPluginYPbPrToRGB709Name);
797         desc.setPluginDescription(kPluginYPbPrToRGB709Description);
798         break;
799 
800     case eColorTransformRGBToYUV601:
801         desc.setLabel(kPluginRGBToYUV601Name);
802         desc.setPluginDescription(kPluginRGBToYUV601Description);
803         break;
804 
805     case eColorTransformYUVToRGB601:
806         desc.setLabel(kPluginYUVToRGB601Name);
807         desc.setPluginDescription(kPluginYUVToRGB601Description);
808         break;
809 
810     case eColorTransformRGBToYUV709:
811         desc.setLabel(kPluginRGBToYUV709Name);
812         desc.setPluginDescription(kPluginRGBToYUV709Description);
813         break;
814 
815     case eColorTransformYUVToRGB709:
816         desc.setLabel(kPluginYUVToRGB709Name);
817         desc.setPluginDescription(kPluginYUVToRGB709Description);
818         break;
819 
820     case eColorTransformRGB709ToXYZ:
821         desc.setLabel(kPluginRGB709ToXYZName);
822         desc.setPluginDescription(kPluginRGB709ToXYZDescription);
823         break;
824 
825     case eColorTransformXYZToRGB709:
826         desc.setLabel(kPluginXYZToRGB709Name);
827         desc.setPluginDescription(kPluginXYZToRGB709Description);
828         break;
829 
830     case eColorTransformRGB709ToLab:
831         desc.setLabel(kPluginRGB709ToLabName);
832         desc.setPluginDescription(kPluginRGB709ToLabDescription);
833         break;
834 
835     case eColorTransformLabToRGB709:
836         desc.setLabel(kPluginLabToRGB709Name);
837         desc.setPluginDescription(kPluginLabToRGB709Description);
838         break;
839 
840     case eColorTransformXYZToLab:
841         desc.setLabel(kPluginXYZToLabName);
842         desc.setPluginDescription(kPluginXYZToLabDescription);
843         break;
844 
845     case eColorTransformLabToXYZ:
846         desc.setLabel(kPluginLabToXYZName);
847         desc.setPluginDescription(kPluginLabToXYZDescription);
848         break;
849 
850     case eColorTransformXYZToxyY:
851         desc.setLabel(kPluginXYZToxyYName);
852         desc.setPluginDescription(kPluginXYZToxyYDescription);
853         break;
854 
855     case eColorTransformxyYToXYZ:
856         desc.setLabel(kPluginxyYToXYZName);
857         desc.setPluginDescription(kPluginxyYToXYZDescription);
858         break;
859     } // switch
860     desc.setPluginGrouping(kPluginGrouping);
861 
862     desc.addSupportedContext(eContextFilter);
863     desc.addSupportedContext(eContextGeneral);
864     //desc.addSupportedContext(eContextPaint);
865     desc.addSupportedBitDepth(eBitDepthUByte);
866     desc.addSupportedBitDepth(eBitDepthUShort);
867     desc.addSupportedBitDepth(eBitDepthFloat);
868 
869     // set a few flags
870     desc.setSingleInstance(false);
871     desc.setHostFrameThreading(false);
872     desc.setSupportsMultiResolution(kSupportsMultiResolution);
873     desc.setSupportsTiles(kSupportsTiles);
874     desc.setTemporalClipAccess(false);
875     desc.setRenderTwiceAlways(false);
876     desc.setSupportsMultipleClipPARs(kSupportsMultipleClipPARs);
877     desc.setSupportsMultipleClipDepths(kSupportsMultipleClipDepths);
878     desc.setRenderThreadSafety(kRenderThreadSafety);
879 #ifdef OFX_EXTENSIONS_NATRON
880     desc.setChannelSelector(ePixelComponentRGB);
881 #endif
882 } // >::describe
883 
884 template <ColorTransformEnum transform>
885 void
describeInContext(ImageEffectDescriptor & desc,ContextEnum)886 ColorTransformPluginFactory<transform>::describeInContext(ImageEffectDescriptor &desc,
887                                                           ContextEnum /*context*/)
888 {
889     // Source clip only in the filter context
890     // create the mandated source clip
891     ClipDescriptor *srcClip = desc.defineClip(kOfxImageEffectSimpleSourceClipName);
892 
893     srcClip->addSupportedComponent(ePixelComponentRGBA);
894     srcClip->addSupportedComponent(ePixelComponentRGB);
895     srcClip->setTemporalClipAccess(false);
896     srcClip->setSupportsTiles(kSupportsTiles);
897     srcClip->setIsMask(false);
898 
899     // create the mandated output clip
900     ClipDescriptor *dstClip = desc.defineClip(kOfxImageEffectOutputClipName);
901     dstClip->addSupportedComponent(ePixelComponentRGBA);
902     dstClip->addSupportedComponent(ePixelComponentRGB);
903     dstClip->setSupportsTiles(kSupportsTiles);
904 
905     // make some pages and to things in
906     if ( fromRGB(transform) || toRGB(transform) ) {
907         PageParamDescriptor *page = desc.definePageParam("Controls");
908         {
909             BooleanParamDescriptor* param = desc.defineBooleanParam(kParamPremult);
910             if ( fromRGB(transform) ) {
911                 param->setLabel(kParamPremultRGBToXXXLabel);
912                 param->setHint(kParamPremultRGBToXXXHint);
913             } else {
914                 param->setLabel(kParamPremultXXXToRGBLabel);
915                 param->setHint(kParamPremultXXXToRGBHint);
916             }
917             param->setLayoutHint(eLayoutHintNoNewLine, 1);
918             param->setAnimates(false);
919             desc.addClipPreferencesSlaveParam(*param);
920             if (page) {
921                 page->addChild(*param);
922             }
923         }
924         {
925             // not yet implemented, for future use (whenever deep compositing is supported)
926             ChoiceParamDescriptor* param = desc.defineChoiceParam(kParamPremultChannel);
927             param->setLabel(kParamPremultChannelLabel);
928             param->setHint(kParamPremultChannelHint);
929             param->appendOption(kParamPremultChannelR);
930             param->appendOption(kParamPremultChannelG);
931             param->appendOption(kParamPremultChannelB);
932             param->appendOption(kParamPremultChannelA);
933             param->setDefault(3); // alpha
934             param->setIsSecretAndDisabled(true); // not yet implemented
935             if (page) {
936                 page->addChild(*param);
937             }
938         }
939 
940         {
941             BooleanParamDescriptor* param = desc.defineBooleanParam(kParamPremultChanged);
942             param->setDefault(false);
943             param->setIsSecretAndDisabled(true);
944             param->setAnimates(false);
945             param->setEvaluateOnChange(false);
946             if (page) {
947                 page->addChild(*param);
948             }
949         }
950     }
951 } // >::describeInContext
952 
953 template <ColorTransformEnum transform>
954 ImageEffect*
createInstance(OfxImageEffectHandle handle,ContextEnum)955 ColorTransformPluginFactory<transform>::createInstance(OfxImageEffectHandle handle,
956                                                        ContextEnum /*context*/)
957 {
958     return new ColorTransformPlugin<transform>(handle);
959 }
960 
961 // RGBtoHSV
962 static ColorTransformPluginFactory<eColorTransformRGBToHSV> p1(kPluginRGBToHSVIdentifier, kPluginVersionMajor, kPluginVersionMinor);
963 // HSVtoRGB
964 static ColorTransformPluginFactory<eColorTransformHSVToRGB> p2(kPluginHSVToRGBIdentifier, kPluginVersionMajor, kPluginVersionMinor);
965 // RGBtoHSL
966 static ColorTransformPluginFactory<eColorTransformRGBToHSL> p3(kPluginRGBToHSLIdentifier, kPluginVersionMajor, kPluginVersionMinor);
967 // HSLtoRGB
968 static ColorTransformPluginFactory<eColorTransformHSLToRGB> p4(kPluginHSLToRGBIdentifier, kPluginVersionMajor, kPluginVersionMinor);
969 // RGBtoHSI
970 static ColorTransformPluginFactory<eColorTransformRGBToHSI> p5(kPluginRGBToHSIIdentifier, kPluginVersionMajor, kPluginVersionMinor);
971 // HSItoRGB
972 static ColorTransformPluginFactory<eColorTransformHSIToRGB> p6(kPluginHSIToRGBIdentifier, kPluginVersionMajor, kPluginVersionMinor);
973 // RGBToYCbCr601
974 static ColorTransformPluginFactory<eColorTransformRGBToYCbCr601> p7(kPluginRGBToYCbCr601Identifier, kPluginVersionMajor, kPluginVersionMinor);
975 // YCbCrToRGB601
976 static ColorTransformPluginFactory<eColorTransformYCbCrToRGB601> p8(kPluginYCbCrToRGB601Identifier, kPluginVersionMajor, kPluginVersionMinor);
977 // RGBToYCbCr709
978 static ColorTransformPluginFactory<eColorTransformRGBToYCbCr709> p17(kPluginRGBToYCbCr709Identifier, kPluginVersionMajor, kPluginVersionMinor);
979 // YCbCrToRGB709
980 static ColorTransformPluginFactory<eColorTransformYCbCrToRGB709> p18(kPluginYCbCrToRGB709Identifier, kPluginVersionMajor, kPluginVersionMinor);
981 // RGBToYPbPr601
982 static ColorTransformPluginFactory<eColorTransformRGBToYPbPr601> p9(kPluginRGBToYPbPr601Identifier, kPluginVersionMajor, kPluginVersionMinor);
983 // YPbPrToRGB601
984 static ColorTransformPluginFactory<eColorTransformYPbPrToRGB601> p10(kPluginYPbPrToRGB601Identifier, kPluginVersionMajor, kPluginVersionMinor);
985 // RGBToYPbPr709
986 static ColorTransformPluginFactory<eColorTransformRGBToYPbPr709> p15(kPluginRGBToYPbPr709Identifier, kPluginVersionMajor, kPluginVersionMinor);
987 // YPbPrToRGB709
988 static ColorTransformPluginFactory<eColorTransformYPbPrToRGB709> p16(kPluginYPbPrToRGB709Identifier, kPluginVersionMajor, kPluginVersionMinor);
989 // RGBToYUV601
990 static ColorTransformPluginFactory<eColorTransformRGBToYUV601> p19(kPluginRGBToYUV601Identifier, kPluginVersionMajor, kPluginVersionMinor);
991 // YUVToRGB601
992 static ColorTransformPluginFactory<eColorTransformYUVToRGB601> p20(kPluginYUVToRGB601Identifier, kPluginVersionMajor, kPluginVersionMinor);
993 // RGBToYUV709
994 static ColorTransformPluginFactory<eColorTransformRGBToYUV709> p21(kPluginRGBToYUV709Identifier, kPluginVersionMajor, kPluginVersionMinor);
995 // YUVToRGB709
996 static ColorTransformPluginFactory<eColorTransformYUVToRGB709> p22(kPluginYUVToRGB709Identifier, kPluginVersionMajor, kPluginVersionMinor);
997 // RGB709ToXYZ
998 static ColorTransformPluginFactory<eColorTransformRGB709ToXYZ> p11(kPluginRGB709ToXYZIdentifier, kPluginVersionMajor, kPluginVersionMinor);
999 // XYZToRGB709
1000 static ColorTransformPluginFactory<eColorTransformXYZToRGB709> p12(kPluginXYZToRGB709Identifier, kPluginVersionMajor, kPluginVersionMinor);
1001 // RGB709ToLab
1002 static ColorTransformPluginFactory<eColorTransformRGB709ToLab> p13(kPluginRGB709ToLabIdentifier, kPluginVersionMajor, kPluginVersionMinor);
1003 // LabToRGB709
1004 static ColorTransformPluginFactory<eColorTransformLabToRGB709> p14(kPluginLabToRGB709Identifier, kPluginVersionMajor, kPluginVersionMinor);
1005 // XYZToLab
1006 static ColorTransformPluginFactory<eColorTransformXYZToLab> p23(kPluginXYZToLabIdentifier, kPluginVersionMajor, kPluginVersionMinor);
1007 // LabToXYZ
1008 static ColorTransformPluginFactory<eColorTransformLabToXYZ> p24(kPluginLabToXYZIdentifier, kPluginVersionMajor, kPluginVersionMinor);
1009 // XYZToxyY
1010 static ColorTransformPluginFactory<eColorTransformXYZToxyY> p25(kPluginXYZToxyYIdentifier, kPluginVersionMajor, kPluginVersionMinor);
1011 // xyYToXYZ
1012 static ColorTransformPluginFactory<eColorTransformxyYToXYZ> p26(kPluginxyYToXYZIdentifier, kPluginVersionMajor, kPluginVersionMinor);
1013 
1014 mRegisterPluginFactoryInstance(p1)
1015 mRegisterPluginFactoryInstance(p2)
1016 mRegisterPluginFactoryInstance(p3)
1017 mRegisterPluginFactoryInstance(p4)
1018 mRegisterPluginFactoryInstance(p5)
1019 mRegisterPluginFactoryInstance(p6)
1020 mRegisterPluginFactoryInstance(p7)
1021 mRegisterPluginFactoryInstance(p8)
1022 mRegisterPluginFactoryInstance(p9)
1023 mRegisterPluginFactoryInstance(p10)
1024 mRegisterPluginFactoryInstance(p11)
1025 mRegisterPluginFactoryInstance(p12)
1026 mRegisterPluginFactoryInstance(p13)
1027 mRegisterPluginFactoryInstance(p14)
1028 mRegisterPluginFactoryInstance(p15)
1029 mRegisterPluginFactoryInstance(p16)
1030 mRegisterPluginFactoryInstance(p17)
1031 mRegisterPluginFactoryInstance(p18)
1032 mRegisterPluginFactoryInstance(p19)
1033 mRegisterPluginFactoryInstance(p20)
1034 mRegisterPluginFactoryInstance(p21)
1035 mRegisterPluginFactoryInstance(p22)
1036 mRegisterPluginFactoryInstance(p23)
1037 mRegisterPluginFactoryInstance(p24)
1038 mRegisterPluginFactoryInstance(p25)
1039 mRegisterPluginFactoryInstance(p26)
1040 
1041 OFXS_NAMESPACE_ANONYMOUS_EXIT
1042