PageRenderTime 61ms CodeModel.GetById 10ms app.highlight 47ms RepoModel.GetById 1ms app.codeStats 0ms

/src/pyglue/PyProcessor.cpp

http://github.com/imageworks/OpenColorIO
C++ | 405 lines | 319 code | 37 blank | 49 comment | 31 complexity | 90f7349ad476a13be5b8c8acb50ead16 MD5 | raw file
  1/*
  2Copyright (c) 2003-2010 Sony Pictures Imageworks Inc., et al.
  3All Rights Reserved.
  4
  5Redistribution and use in source and binary forms, with or without
  6modification, are permitted provided that the following conditions are
  7met:
  8* Redistributions of source code must retain the above copyright
  9  notice, this list of conditions and the following disclaimer.
 10* Redistributions in binary form must reproduce the above copyright
 11  notice, this list of conditions and the following disclaimer in the
 12  documentation and/or other materials provided with the distribution.
 13* Neither the name of Sony Pictures Imageworks nor the names of its
 14  contributors may be used to endorse or promote products derived from
 15  this software without specific prior written permission.
 16THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 17"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 18LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 19A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 20OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 21SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 22LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 23DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 24THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 25(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 26OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 27*/
 28
 29#include <Python.h>
 30#include <sstream>
 31#include <OpenColorIO/OpenColorIO.h>
 32
 33#include "PyUtil.h"
 34#include "PyDoc.h"
 35
 36OCIO_NAMESPACE_ENTER
 37{
 38    
 39    PyObject * BuildConstPyProcessor(ConstProcessorRcPtr processor)
 40    {
 41        return BuildConstPyOCIO<PyOCIO_Processor, ProcessorRcPtr,
 42            ConstProcessorRcPtr>(processor, PyOCIO_ProcessorType);
 43    }
 44    
 45    bool IsPyProcessor(PyObject * pyobject)
 46    {
 47        return IsPyOCIOType(pyobject, PyOCIO_ProcessorType);
 48    }
 49    
 50    ConstProcessorRcPtr GetConstProcessor(PyObject * pyobject)
 51    {
 52        return GetConstPyOCIO<PyOCIO_Processor, ConstProcessorRcPtr>(pyobject,
 53            PyOCIO_ProcessorType);
 54    }
 55    
 56    namespace
 57    {
 58        
 59        ///////////////////////////////////////////////////////////////////////
 60        ///
 61        
 62        int PyOCIO_Processor_init(PyOCIO_Processor * self, PyObject * args, PyObject * kwds);
 63        void PyOCIO_Processor_delete(PyOCIO_Processor * self, PyObject * args);
 64        PyObject * PyOCIO_Processor_isNoOp(PyObject * self);
 65        PyObject * PyOCIO_Processor_hasChannelCrosstalk(PyObject * self);
 66        PyObject * PyOCIO_Processor_getMetadata(PyObject * self);
 67        PyObject * PyOCIO_Processor_applyRGB(PyObject * self, PyObject * args);
 68        PyObject * PyOCIO_Processor_applyRGBA(PyObject * self, PyObject * args);
 69        PyObject * PyOCIO_Processor_getCpuCacheID(PyObject * self);
 70        PyObject * PyOCIO_Processor_getGpuShaderText(PyObject * self, PyObject * args);
 71        PyObject * PyOCIO_Processor_getGpuShaderTextCacheID(PyObject * self, PyObject * args);
 72        PyObject * PyOCIO_Processor_getGpuLut3D(PyObject * self, PyObject * args);
 73        PyObject * PyOCIO_Processor_getGpuLut3DCacheID(PyObject * self, PyObject * args);
 74        
 75        ///////////////////////////////////////////////////////////////////////
 76        ///
 77        
 78        PyMethodDef PyOCIO_Processor_methods[] = {
 79            { "isNoOp",
 80            (PyCFunction) PyOCIO_Processor_isNoOp, METH_NOARGS, PROCESSOR_ISNOOP__DOC__ },
 81            { "hasChannelCrosstalk",
 82            (PyCFunction) PyOCIO_Processor_hasChannelCrosstalk, METH_NOARGS, PROCESSOR_HASCHANNELCROSSTALK__DOC__ },
 83            { "getMetadata",
 84            (PyCFunction) PyOCIO_Processor_getMetadata, METH_NOARGS, PROCESSOR_GETMETADATA__DOC__ },
 85            { "applyRGB",
 86            PyOCIO_Processor_applyRGB, METH_VARARGS, PROCESSOR_APPLYRGB__DOC__ },
 87            { "applyRGBA",
 88            PyOCIO_Processor_applyRGBA, METH_VARARGS, PROCESSOR_APPLYRGBA__DOC__ },
 89            { "getCpuCacheID",
 90            (PyCFunction) PyOCIO_Processor_getCpuCacheID, METH_NOARGS, PROCESSOR_GETCPUCACHEID__DOC__ },
 91            { "getGpuShaderText",
 92            PyOCIO_Processor_getGpuShaderText, METH_VARARGS, PROCESSOR_GETGPUSHADERTEXT__DOC__ },
 93            { "getGpuShaderTextCacheID",
 94            PyOCIO_Processor_getGpuShaderTextCacheID, METH_VARARGS, PROCESSOR_GETGPUSHADERTEXTCACHEID__DOC__ },
 95            { "getGpuLut3D",
 96            PyOCIO_Processor_getGpuLut3D, METH_VARARGS, PROCESSOR_GETGPULUT3D__DOC__ },
 97            { "getGpuLut3DCacheID",
 98            PyOCIO_Processor_getGpuLut3DCacheID, METH_VARARGS, PROCESSOR_GETGPULUT3DCACHEID__DOC__ },
 99            { NULL, NULL, 0, NULL }
100        };
101        
102        const char initMessage[] =
103            "Processor objects cannot be instantiated directly. "
104            "Please use config.getProcessor() instead.";
105        
106    }
107    
108    ///////////////////////////////////////////////////////////////////////////
109    ///
110    
111    PyTypeObject PyOCIO_ProcessorType = {
112        PyVarObject_HEAD_INIT(NULL, 0)              //ob_size
113        "OCIO.Processor",                           //tp_name
114        sizeof(PyOCIO_Processor),                   //tp_basicsize
115        0,                                          //tp_itemsize
116        (destructor)PyOCIO_Processor_delete,        //tp_dealloc
117        0,                                          //tp_print
118        0,                                          //tp_getattr
119        0,                                          //tp_setattr
120        0,                                          //tp_compare
121        0,                                          //tp_repr
122        0,                                          //tp_as_number
123        0,                                          //tp_as_sequence
124        0,                                          //tp_as_mapping
125        0,                                          //tp_hash 
126        0,                                          //tp_call
127        0,                                          //tp_str
128        0,                                          //tp_getattro
129        0,                                          //tp_setattro
130        0,                                          //tp_as_buffer
131        Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,   //tp_flags
132        PROCESSOR__DOC__,                           //tp_doc 
133        0,                                          //tp_traverse 
134        0,                                          //tp_clear 
135        0,                                          //tp_richcompare 
136        0,                                          //tp_weaklistoffset 
137        0,                                          //tp_iter 
138        0,                                          //tp_iternext 
139        PyOCIO_Processor_methods,                   //tp_methods 
140        0,                                          //tp_members 
141        0,                                          //tp_getset 
142        0,                                          //tp_base 
143        0,                                          //tp_dict 
144        0,                                          //tp_descr_get 
145        0,                                          //tp_descr_set 
146        0,                                          //tp_dictoffset 
147        (initproc) PyOCIO_Processor_init,           //tp_init 
148        0,                                          //tp_alloc 
149        0,                                          //tp_new 
150        0,                                          //tp_free
151        0,                                          //tp_is_gc
152    };
153    
154    ///////////////////////////////////////////////////////////////////////////
155    ///
156    
157    namespace
158    {
159        // TODO: The use of a dict, rather than a native class is not ideal
160        // in the next API revision, use a native type.
161        
162        void FillShaderDescFromPyDict(GpuShaderDesc & shaderDesc,
163                                      PyObject * dict)
164        {
165            if(!PyDict_Check(dict))
166            {
167                throw Exception("GpuShaderDesc must be a dict type.");
168            }
169            
170            PyObject *key, *value;
171            Py_ssize_t pos = 0;
172            
173            while (PyDict_Next(dict, &pos, &key, &value))
174            {
175                std::string keystr;
176                if(!GetStringFromPyObject(key, &keystr))
177                    throw Exception("GpuShaderDesc keys must be strings.");
178                
179                if(keystr == "language")
180                {
181                    GpuLanguage language = GPU_LANGUAGE_UNKNOWN; 
182                    if(ConvertPyObjectToGpuLanguage(value, &language) == 0)
183                        throw Exception("GpuShaderDesc language must be a GpuLanguage.");
184                    shaderDesc.setLanguage(language);
185                }
186                else if(keystr == "functionName")
187                {
188                    std::string functionName;
189                    if(!GetStringFromPyObject(value, &functionName))
190                        throw Exception("GpuShaderDesc functionName must be a string.");
191                    shaderDesc.setFunctionName(functionName.c_str());
192                }
193                else if(keystr == "lut3DEdgeLen")
194                {
195                    int lut3DEdgeLen = 0;
196                    if(!GetIntFromPyObject(value, &lut3DEdgeLen))
197                        throw Exception("GpuShaderDesc lut3DEdgeLen must be an integer.");
198                    shaderDesc.setLut3DEdgeLen(lut3DEdgeLen);
199                }
200                else
201                {
202                    std::ostringstream os;
203                    os << "Unknown GpuShaderDesc key, '";
204                    os << keystr << "'. ";
205                    os << "Allowed keys: (";
206                    os << "'language', 'functionName', 'lut3DEdgeLen').";
207                    throw Exception(os.str().c_str());
208                }
209            }
210        }
211    }
212    
213    namespace
214    {
215        
216        ///////////////////////////////////////////////////////////////////////
217        ///
218        
219        int PyOCIO_Processor_init(PyOCIO_Processor * /*self*/, PyObject * /*args*/, PyObject * /*kwds*/)
220        {
221            PyErr_SetString( PyExc_RuntimeError, initMessage);
222            return -1;
223        }
224        
225        void PyOCIO_Processor_delete(PyOCIO_Processor *self, PyObject * /*args*/)
226        {
227            DeletePyObject<PyOCIO_Processor>(self);
228        }
229        
230        PyObject * PyOCIO_Processor_isNoOp(PyObject * self)
231        {
232            OCIO_PYTRY_ENTER()
233            ConstProcessorRcPtr processor = GetConstProcessor(self);
234            return PyBool_FromLong(processor->isNoOp());
235            OCIO_PYTRY_EXIT(NULL)
236        }
237        
238        PyObject * PyOCIO_Processor_hasChannelCrosstalk(PyObject * self)
239        {
240            OCIO_PYTRY_ENTER()
241            ConstProcessorRcPtr processor = GetConstProcessor(self);
242            return PyBool_FromLong(processor->hasChannelCrosstalk());
243            OCIO_PYTRY_EXIT(NULL)
244        }
245        
246        PyObject * PyOCIO_Processor_getMetadata(PyObject * self)
247        {
248            OCIO_PYTRY_ENTER()
249            ConstProcessorRcPtr processor = GetConstProcessor(self);
250            return BuildConstPyProcessorMetadata(processor->getMetadata());
251            OCIO_PYTRY_EXIT(NULL)
252        }
253        
254        PyObject * PyOCIO_Processor_applyRGB(PyObject * self, PyObject * args)
255        {
256            OCIO_PYTRY_ENTER()
257            PyObject* pyData = 0;
258            if (!PyArg_ParseTuple(args, "O:applyRGB",
259                &pyData)) return NULL;
260            ConstProcessorRcPtr processor = GetConstProcessor(self);
261            if(processor->isNoOp())
262            {
263                Py_INCREF(pyData);
264                return pyData;
265            }
266            std::vector<float> data;
267            if(!FillFloatVectorFromPySequence(pyData, data) ||
268                ((data.size() % 3) != 0))
269            {
270                std::ostringstream os;
271                os << "First argument must be a float array, size multiple of 3. ";
272                os << "Size: " << data.size() << ".";
273                PyErr_SetString(PyExc_TypeError, os.str().c_str());
274                return 0;
275            }
276            PackedImageDesc img(&data[0], data.size()/3, 1, 3);
277            processor->apply(img);
278            return CreatePyListFromFloatVector(data);
279            OCIO_PYTRY_EXIT(NULL)
280        }
281        
282        PyObject * PyOCIO_Processor_applyRGBA(PyObject * self, PyObject * args)
283        {
284            OCIO_PYTRY_ENTER()
285            PyObject* pyData = 0;
286            if (!PyArg_ParseTuple(args, "O:applyRGBA",
287                &pyData)) return NULL;
288            ConstProcessorRcPtr processor = GetConstProcessor(self);
289            if(processor->isNoOp())
290            {
291                Py_INCREF(pyData);
292                return pyData;
293            }
294            std::vector<float> data;
295            if(!FillFloatVectorFromPySequence(pyData, data) ||
296                ((data.size() % 4) != 0))
297            {
298                std::ostringstream os;
299                os << "First argument must be a float array, size multiple of 4. ";
300                os << "Size: " << data.size() << ".";
301                PyErr_SetString(PyExc_TypeError, os.str().c_str());
302                return 0;
303            }
304            PackedImageDesc img(&data[0], data.size()/4, 1, 4);
305            processor->apply(img);
306            return CreatePyListFromFloatVector(data);
307            OCIO_PYTRY_EXIT(NULL)
308        }
309        
310        PyObject * PyOCIO_Processor_getCpuCacheID(PyObject * self)
311        {
312            OCIO_PYTRY_ENTER()
313            ConstProcessorRcPtr processor = GetConstProcessor(self);
314            return PyString_FromString(processor->getCpuCacheID());
315            OCIO_PYTRY_EXIT(NULL)
316        }
317        
318        PyObject * PyOCIO_Processor_getGpuShaderText(PyObject * self, PyObject * args)
319        {
320            OCIO_PYTRY_ENTER()
321            PyObject* pyobject = 0;
322            if (!PyArg_ParseTuple(args, "O:getGpuShaderText",
323                &pyobject)) return NULL;
324            ConstProcessorRcPtr processor = GetConstProcessor(self);
325            if(IsPyOCIOType(pyobject, PyOCIO_GpuShaderDescType)) {
326                ConstGpuShaderDescRcPtr desc = GetConstGpuShaderDesc(pyobject);
327                return PyString_FromString(processor->getGpuShaderText(*desc.get()));
328            }
329            // DEPRECIATED GpuShaderDesc dict support TODO: remove
330            GpuShaderDesc shaderDesc;
331            FillShaderDescFromPyDict(shaderDesc, pyobject);
332            return PyString_FromString(processor->getGpuShaderText(shaderDesc));
333            // DEPRECIATED
334            OCIO_PYTRY_EXIT(NULL)
335        }
336        
337        PyObject * PyOCIO_Processor_getGpuShaderTextCacheID(PyObject * self, PyObject * args)
338        {
339            OCIO_PYTRY_ENTER()
340            PyObject* pyobject = 0;
341            if (!PyArg_ParseTuple(args, "O:getGpuShaderTextCacheID",
342                &pyobject)) return NULL;
343            ConstProcessorRcPtr processor = GetConstProcessor(self);
344            if(IsPyOCIOType(pyobject, PyOCIO_GpuShaderDescType)) {
345                ConstGpuShaderDescRcPtr desc = GetConstGpuShaderDesc(pyobject);
346                return PyString_FromString(processor->getGpuShaderTextCacheID(*desc.get()));
347            }
348            // DEPRECIATED GpuShaderDesc dict support TODO: remove
349            GpuShaderDesc shaderDesc;
350            FillShaderDescFromPyDict(shaderDesc, pyobject);
351            return PyString_FromString(processor->getGpuShaderTextCacheID(shaderDesc));
352            // DEPRECIATED
353            OCIO_PYTRY_EXIT(NULL)
354        }
355        
356        PyObject * PyOCIO_Processor_getGpuLut3D(PyObject * self, PyObject * args)
357        {
358            OCIO_PYTRY_ENTER()
359            PyObject* pyobject = 0;
360            if (!PyArg_ParseTuple(args, "O:getGpuLut3D",
361                &pyobject)) return NULL;
362            ConstProcessorRcPtr processor = GetConstProcessor(self);
363            if(IsPyOCIOType(pyobject, PyOCIO_GpuShaderDescType)) {
364                ConstGpuShaderDescRcPtr desc = GetConstGpuShaderDesc(pyobject);
365                int len = desc->getLut3DEdgeLen();
366                std::vector<float> lut3d(3*len*len*len);    
367                // TODO: return more compact binary data? (ex array, ...)
368                processor->getGpuLut3D(&lut3d[0], *desc.get());
369                return CreatePyListFromFloatVector(lut3d);
370            }
371            // DEPRECIATED GpuShaderDesc dict support TODO: remove
372            GpuShaderDesc shaderDesc;
373            FillShaderDescFromPyDict(shaderDesc, pyobject);
374            int len = shaderDesc.getLut3DEdgeLen();
375            std::vector<float> lut3d(3*len*len*len);    
376            // TODO: return more compact binary data? (ex array, ...)
377            processor->getGpuLut3D(&lut3d[0], shaderDesc);
378            return CreatePyListFromFloatVector(lut3d);
379            // DEPRECIATED
380            OCIO_PYTRY_EXIT(NULL)
381        }
382        
383        PyObject * PyOCIO_Processor_getGpuLut3DCacheID(PyObject * self, PyObject * args)
384        {
385            OCIO_PYTRY_ENTER()
386            PyObject* pyobject = 0;
387            if (!PyArg_ParseTuple(args,"O:getGpuLut3DCacheID",
388                &pyobject)) return NULL;
389            ConstProcessorRcPtr processor = GetConstProcessor(self);
390            if(IsPyOCIOType(pyobject, PyOCIO_GpuShaderDescType)) {
391                ConstGpuShaderDescRcPtr desc = GetConstGpuShaderDesc(pyobject);
392                return PyString_FromString(processor->getGpuLut3DCacheID(*desc.get()));
393            }
394            // DEPRECIATED GpuShaderDesc dict support TODO: remove
395            GpuShaderDesc shaderDesc;
396            FillShaderDescFromPyDict(shaderDesc, pyobject);
397            return PyString_FromString(processor->getGpuLut3DCacheID(shaderDesc));
398            // DEPRECIATED
399            OCIO_PYTRY_EXIT(NULL)
400        }
401        
402    }
403    
404}
405OCIO_NAMESPACE_EXIT