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