/* Make the extension with: python setup.py build_ext --inplace Test the extension: python test_libtt.py */ #include "wrapper_libtt.h" // =================================================================================== // =================================================================================== // === Tools // =================================================================================== // =================================================================================== /// /// Extract argc, **argv from a char* cmd. Use free_argv after using this function. /// /// The input string to extract words /// The pointer of **argv /// argc /// /// int argc; /// char **argv = NULL; /// argc = get_argv(cmd, &argv); /// int get_argv(char *cmd, char ***pargv) { int argc = 0; char str[1024]; // === Compute argc strcpy(str, cmd); char* token = strtok(str, " "); while (token != NULL) { token = strtok(NULL, " "); argc++; } // === Alloc argv char **argv = NULL; argv = (char **)malloc(argc * sizeof(char)); *pargv = (char **)argv; argc = 0; // === Compute argv strcpy(str, cmd); token = strtok(str, " "); while (token != NULL) { argv[argc] = (char *)malloc((strlen(token)+2) * sizeof(char)); //printf("STEP 220-%d argv = %p\n", argc, argv[argc]); strcpy(argv[argc], token); token = strtok(NULL, " "); argc++; } return argc; } /// /// Free memory of the **argv array. /// /// The number of elements of pargv /// The pointer of **argv /// /// free_argv(argc, &argv); /// void free_argv(int argc, char ***pargv) { char **argv; argv = *pargv; for (int k=0 ; k argv[%d] = %s\n", k, argv[k]); free(argv[k]); } free(argv); } PyObject *set_np_array2d(int nd, int w, int h, int typenum, void *p) { npy_intp dims[2]; dims[0] = w; dims[1] = h; return PyArray_SimpleNewFromData(nd, dims, typenum, p); } int npy_tool_npytype_2_datatype(int type) { int datatype = -1; if (type == NPY_NOTYPE) datatype = -1; else if (type == NPY_BOOL) datatype = TLOGICAL; //else if (type == NPY_BYTE) datatype = ; //else if (type == NPY_UBYTE) datatype = ; else if (type == NPY_SHORT) datatype = TSHORT; else if (type == NPY_USHORT) datatype = TUSHORT; else if (type == NPY_INT32) datatype = TLONG; else if (type == NPY_UINT32) datatype = TULONG; else if (type == NPY_FLOAT) datatype = TFLOAT; else if (type == NPY_DOUBLE) datatype = TDOUBLE; return datatype; } int npy_tool_datatype_2_npytype(int type) { int npytype = -1; if (type == NPY_NOTYPE) npytype = -1; else if (type == TLOGICAL) npytype = NPY_BOOL; //else if (type == NPY_BYTE) datatype = ; //else if (type == NPY_UBYTE) datatype = ; else if (type == TSHORT) npytype = NPY_SHORT; else if (type == TUSHORT) npytype = NPY_USHORT; else if (type == TLONG) npytype = NPY_INT32; else if (type == TULONG) npytype = NPY_UINT32; else if (type == TFLOAT) npytype = NPY_FLOAT; else if (type == TDOUBLE) npytype = NPY_DOUBLE; return npytype; } /// /// Return the numpy array element type. /// /// The numpy array to evaluate /// /// Returns the NPY _* type of the array elements. /// Returns -2 if the the nparray is not a numpy.ndarray. /// Returns -1 if the element type is not int, float or double. /// /// /// npy_tool_get_type_array(my_np_array); /// int npy_tool_get_type_array(PyObject *nparray) { // --- Get the numpy array dtype --- const char *array_type = Py_TYPE(nparray)->tp_name; //printf("array_type = %s\n", array_type); // response should be "numpy.ndarray" int type_inp = -2; if (strcmp(array_type, "numpy.ndarray") == 0) { // --- Get the type of the array elements PyObject *py_dtype = PyObject_GetAttrString(nparray, "dtype"); PyObject *repr = PyObject_Repr(py_dtype); PyObject *str = PyUnicode_AsEncodedString(repr, "utf-8", "~E~"); const char *char_dtype = PyBytes_AS_STRING(str); // response should e.g. "dtype('float32')" Py_DECREF(py_dtype); Py_DECREF(repr); Py_DECREF(str); // --- Compute only char_dtype_small = 'float32' char char_dtype_small[MSG]; int k1=-1, k2=-1, k; int n = (int)strlen(char_dtype); for (k = 0 ; k < n ; k++) { if (k1 >= 0) { char_dtype_small[k-k1-1] = char_dtype[k]; } if ((k1 == -1) && (char_dtype[k] == '(')) { k1 = k; } if ((k2 == -1) && (char_dtype[k] == ')')) { char_dtype_small[k-k1-1] = '\0'; break; } } //printf("char_dtype_small=%s\n",char_dtype_small); // response should e.g. "float32" 5 6 7 8 9 10 //printf("NPY_ = %d %d %d %d %d %d\n",NPY_INT, NPY_UINT, NPY_INT32, NPY_UINT32, NPY_INT64, NPY_UINT64); // --- Set the input type type_inp = NPY_NOTYPE; if (strcmp(char_dtype_small, "'bool'") == 0) { type_inp = NPY_BOOL; } // 0 = NPY_BOOL else if (strcmp(char_dtype_small, "'int8'") == 0) { type_inp = NPY_INT8; } // 1 = NPY_BYTE else if (strcmp(char_dtype_small, "'byte'") == 0) { type_inp = NPY_INT8; } // 1 else if (strcmp(char_dtype_small, "'uint8'") == 0) { type_inp = NPY_UINT8; } // 2 = NPY_UBYTE else if (strcmp(char_dtype_small, "'ubyte'") == 0) { type_inp = NPY_UINT8; } // 2 else if (strcmp(char_dtype_small, "'int16'") == 0) { type_inp = NPY_INT16; } // 3 = NPY_SHORT else if (strcmp(char_dtype_small, "'short'") == 0) { type_inp = NPY_INT16; } // 3 else if (strcmp(char_dtype_small, "'uint16'") == 0) { type_inp = NPY_UINT16; } // 4 = NPY_USHORT else if (strcmp(char_dtype_small, "'ushort'") == 0) { type_inp = NPY_UINT16; } // 4 //else if (strcmp(char_dtype_small, "'?'") == 0) { type_inp = NPY_INT; } // 5 = NPY_INT //else if (strcmp(char_dtype_small, "'?'") == 0) { type_inp = NPY_UINT; } // 6 = NPY_UINT else if (strcmp(char_dtype_small, "'int32'") == 0) { type_inp = NPY_INT32; } // 7 = NPY_INT32 else if (strcmp(char_dtype_small, "'uint32'") == 0) { type_inp = NPY_UINT32; } // 8 = NPY_UINT32 else if (strcmp(char_dtype_small, "'uint'") == 0) { type_inp = NPY_UINT32; } // 8 else if (strcmp(char_dtype_small, "'int64'") == 0) { type_inp = NPY_INT64; } // 9 = NPY_INT64 else if (strcmp(char_dtype_small, "'uint64'") == 0) { type_inp = NPY_UINT64; } // 10 = NPY_ULONGLONG else if (strcmp(char_dtype_small, "'float32'") == 0) { type_inp = NPY_FLOAT32; } // 11 = NPY_FLOAT else if (strcmp(char_dtype_small, "'float'") == 0) { type_inp = NPY_FLOAT32; } // 11 else if (strcmp(char_dtype_small, "'float64'") == 0) { type_inp = NPY_FLOAT64; } // 12 = NPY_DOUBLE else if (strcmp(char_dtype_small, "'double'") == 0) { type_inp = NPY_FLOAT64; } // 12 } return type_inp; } char *char_type_pg(int type) { static char msg[PG_MSG_ERR]; if (type == NPY_NOTYPE) strcpy(msg, "unknown"); else if (type == NPY_BOOL) strcpy(msg, "bool"); else if (type == NPY_BYTE) strcpy(msg, "byte"); else if (type == NPY_UBYTE) strcpy(msg, "ubyte"); else if (type == NPY_SHORT) strcpy(msg, "short"); else if (type == NPY_USHORT) strcpy(msg, "ushort"); else if (type == NPY_INT32) strcpy(msg, "int32"); else if (type == NPY_UINT32) strcpy(msg, "uint32"); else if (type == NPY_ULONGLONG) strcpy(msg, "uint64"); else if (type == NPY_FLOAT) strcpy(msg, "float"); else if (type == NPY_DOUBLE) strcpy(msg, "double"); else sprintf(msg, "type #%d not recognized", type); return msg; } /// /// Manage memory of the global array for image pointer. /// This pointer must be global to exchange data safely with a numpy array. /// /// The number of elements of pg /// Integer corresponding to the type pointer pg. /// /// calloc_pg(12345, NPY_FLOAT); /// void *calloc_pg(size_t nelem, int type) { // --- Free the current already allocated memory //printf("STEP 100 pg_type=%d pg=%p pgi=%p pgf=%p pgd=%p type=%d\n", pg_type, pg, pgi, pgf, pgd, type); if (pg_type == NPY_INT32) { if (pgi != NULL) free(pgi); pgi = NULL; pg = NULL; } else if (pg_type == NPY_UINT32) { if (pgui != NULL) free(pgui); pgui = NULL; pg = NULL; } else if (pg_type == NPY_SHORT) { if (pgs != NULL) free(pgs); pgs = NULL; pg = NULL; } else if (pg_type == NPY_USHORT) { if (pgus != NULL) free(pgus); pgus = NULL; pg = NULL; } else if (pg_type == NPY_FLOAT) { if (pgf != NULL) free(pgf); pgf = NULL; pg = NULL; } else if (pg_type == NPY_DOUBLE) { if (pgd != NULL) free(pgd); pgd = NULL; pg = NULL; } //printf("STEP 200 pg_type=%d pg=%p pgi=%p pgf=%p pgd=%p type=%d nelem=%zd\n", pg_type, pg, pgi, pgf, pgd, type, nelem); if (pg == NULL) { if (type == NPY_INT32) { pgi = (int*)calloc(nelem, sizeof(int)); pg = (void*)pgi; } else if (type == NPY_UINT32) { pgui = (unsigned int*)calloc(nelem, sizeof(unsigned int)); pg = (void*)pgui; } else if (type == NPY_SHORT) { pgs = (short*)calloc(nelem, sizeof(short)); pg = (void*)pgs; } else if (type == NPY_USHORT) { pgus = (unsigned short*)calloc(nelem, sizeof(unsigned short)); pg = (void*)pgus; } else if (type == NPY_FLOAT) { pgf = (float*)calloc(nelem, sizeof(float)); pg = (void*)pgf; } else if (type == NPY_DOUBLE) { pgd = (double*)calloc(nelem, sizeof(double)); pg = (void*)pgd; } } if (pg == NULL) { char msg[PG_MSG_ERR]; sprintf(msg,"Pointer pg of type %s not allocated (NULL)", char_type_pg(pg_type)); PyErr_SetString(exampleException, msg); return NULL; } pg_type = type; //printf("STEP 300 pg_type=%d pg=%p pgi=%p pgf=%p pgd=%p type=%d nelem=%zd\n", pg_type, pg, pgi, pgf, pgd, type, nelem); return pg; } /// /// Copy all pointer values (pointer p) in the global array (pointer pg) for image pointer. /// The values of the input pointer p are not changed. /// If 'force_pg' is false, the use of copy_p_to_pg must be applied after calloc_pg. The parameter nelem must be the same. /// If 'force_pg' is true, the use of copy_p_to_pg calls calloc_pg with the same type and nelem parameters. /// /// Input pointer to copy values in the pointer pg. /// The number of elements of p /// Integer corresponding to the type pointer p. /// Boolean false true to force pg to have the same type than p /// /// copy_p_to_pg(data, 12345, NPY_DOUBLE, true); /// void *copy_p_to_pg(void *p, size_t nelem, int p_type, bool force_pg) { char msg[PG_MSG_ERR]; short *ps; unsigned short *pus; int *pi; unsigned int *pui; float *pf; double *pd; //printf("STEP 310\n"); if (p == NULL) { strcpy(msg,"Pointer p is not allocated (NULL)"); PyErr_SetString(exampleException, msg); return NULL; } //printf("STEP 330\n"); if (force_pg) { // case of a copy p to pg with alloc of pg with the parameters of p calloc_pg(nelem, p_type); } //printf("STEP 350\n"); if (pg == NULL) { strcpy(msg,"Pointer pg is not allocated (NULL)"); PyErr_SetString(exampleException, msg); return NULL; } if ((p_type < NPY_SHORT) || (p_type > NPY_DOUBLE)) { sprintf(msg,"Type of Pointer p not allowed. p_type=%d (%s)", p_type, char_type_pg(p_type)); PyErr_SetString(exampleException, msg); return NULL; } if ((pg_type < NPY_SHORT) || (pg_type > NPY_DOUBLE)) { sprintf(msg,"Type of Pointer pg not allowed. pg_type=%d (%s)", pg_type, char_type_pg(pg_type)); PyErr_SetString(exampleException, msg); return NULL; } // copy values //printf("STEP 400 pg_type=%d pg=%p pgi=%p pgf=%p pgd=%p p_type=%d nelem=%zd\n", pg_type, pg, pgi, pgf, pgd, p_type, nelem); if (p_type == NPY_INT32) { pi = (int*)p; if (pg_type == NPY_INT32) { PG_LOOP {pgi[k] = (int)pi[k];} } else if (pg_type == NPY_UINT32) { PG_LOOP {pgui[k] = (unsigned int)pi[k];} } else if (pg_type == NPY_SHORT) { PG_LOOP {pgs[k] = (short)pi[k];} } else if (pg_type == NPY_USHORT) { PG_LOOP {pgus[k] = (unsigned short)pi[k];} } else if (pg_type == NPY_FLOAT) { PG_LOOP {pgf[k] = (float)pi[k];} } else if (pg_type == NPY_DOUBLE) { PG_LOOP {pgd[k] = (double)pi[k];} } } else if (p_type == NPY_UINT32) { pui = (unsigned int*)p; if (pg_type == NPY_INT32) { PG_LOOP {pgi[k] = (int)pui[k];} } else if (pg_type == NPY_UINT32) { PG_LOOP {pgui[k] = (unsigned int)pui[k];} } else if (pg_type == NPY_SHORT) { PG_LOOP {pgs[k] = (short)pui[k];} } else if (pg_type == NPY_USHORT) { PG_LOOP {pgus[k] = (unsigned short)pui[k];} } else if (pg_type == NPY_FLOAT) { PG_LOOP {pgf[k] = (float)pui[k];} } else if (pg_type == NPY_DOUBLE) { PG_LOOP {pgd[k] = (double)pui[k];} } } else if (p_type == NPY_SHORT) { ps = (short*)p; if (pg_type == NPY_INT32) { PG_LOOP {pgi[k] = (int)ps[k];} } else if (pg_type == NPY_UINT32) { PG_LOOP {pgui[k] = (unsigned int)ps[k];} } else if (pg_type == NPY_SHORT) { PG_LOOP {pgs[k] = (short)ps[k];} } else if (pg_type == NPY_USHORT) { PG_LOOP {pgus[k] = (unsigned short)ps[k];} } else if (pg_type == NPY_FLOAT) { PG_LOOP {pgf[k] = (float)ps[k];} } else if (pg_type == NPY_DOUBLE) { PG_LOOP {pgd[k] = (double)ps[k];} } } else if (p_type == NPY_USHORT) { pus = (unsigned short*)p; if (pg_type == NPY_INT32) { PG_LOOP {pgi[k] = (int)pus[k];} } else if (pg_type == NPY_UINT32) { PG_LOOP {pgui[k] = (unsigned int)pus[k];} } else if (pg_type == NPY_SHORT) { PG_LOOP {pgs[k] = (short)pus[k];} } else if (pg_type == NPY_USHORT) { PG_LOOP {pgus[k] = (unsigned short)pus[k];} } else if (pg_type == NPY_FLOAT) { PG_LOOP {pgf[k] = (float)pus[k];} } else if (pg_type == NPY_DOUBLE) { PG_LOOP {pgd[k] = (double)pus[k];} } } else if (p_type == NPY_FLOAT) { pf = (float*)p; if (pg_type == NPY_INT32) { PG_LOOP {pgi[k] = (int)pf[k];} } else if (pg_type == NPY_UINT32) { PG_LOOP {pgui[k] = (unsigned int)pf[k];} } else if (pg_type == NPY_SHORT) { PG_LOOP {pgs[k] = (short)pf[k];} } else if (pg_type == NPY_USHORT) { PG_LOOP {pgus[k] = (unsigned short)pf[k];} } else if (pg_type == NPY_FLOAT) { PG_LOOP {pgf[k] = (float)pf[k];} } else if (pg_type == NPY_DOUBLE) { PG_LOOP {pgd[k] = (double)pf[k];} } } else if (p_type == NPY_DOUBLE) { pd = (double*)p; if (pg_type == NPY_INT32) { PG_LOOP {pgi[k] = (int)pd[k];} } else if (pg_type == NPY_UINT32) { PG_LOOP {pgui[k] = (unsigned int)pd[k];} } else if (pg_type == NPY_SHORT) { PG_LOOP {pgs[k] = (short)pd[k];} } else if (pg_type == NPY_USHORT) { PG_LOOP {pgus[k] = (unsigned short)pd[k];} } else if (pg_type == NPY_FLOAT) { PG_LOOP {pgf[k] = (float)pd[k];} } else if (pg_type == NPY_DOUBLE) { PG_LOOP {pgd[k] = (double)pd[k];} } } //printf("STEP 700 pg_type=%d pg=%p pgi=%p pgf=%p pgd=%p p_type=%d nelem=%zd\n", pg_type, pg, pgi, pgf, pgd, p_type, nelem); return pg; } void *copy_pyarray_to_pg(PyArrayObject *py_array, size_t nelem, bool force_pg) { // --- Fill the global pointer pg (=pointer p_in) by the input array (=pointer p) PyArray_Descr *descr = PyArray_DESCR(py_array); int type_num = descr->type_num; //printf("STEP 301 type_num=%d\n",type_num); if (type_num == NPY_INT32) { int *p = (int *)PyArray_DATA(py_array); return copy_p_to_pg(p, nelem, NPY_INT32, force_pg); } else if (type_num == NPY_UINT32) { unsigned int *p = (unsigned int *)PyArray_DATA(py_array); return copy_p_to_pg(p, nelem, NPY_UINT32, force_pg); } else if (type_num == NPY_SHORT) { short *p = (short *)PyArray_DATA(py_array); return copy_p_to_pg(p, nelem, NPY_SHORT, force_pg); } else if (type_num == NPY_USHORT) { unsigned short *p = (unsigned short *)PyArray_DATA(py_array); return copy_p_to_pg(p, nelem, NPY_USHORT, force_pg); } else if (type_num == NPY_FLOAT) { float *p = (float *)PyArray_DATA(py_array); return copy_p_to_pg(p, nelem, NPY_FLOAT, force_pg); } else if (type_num == NPY_DOUBLE) { double *p = (double *)PyArray_DATA(py_array); return copy_p_to_pg(p, nelem, NPY_DOUBLE, force_pg); } return NULL; } void dict_append_d(PyObject* dico, const char* key, int value, const char* comment) { PyObject *mylist; mylist = PyList_New(2); PyList_SetItem(mylist, 0, Py_BuildValue("i", value)); PyList_SetItem(mylist, 1, Py_BuildValue("s", comment)); PyDict_SetItemString(dico, key, mylist); Py_DECREF(mylist); } void dict_append_f(PyObject* dico, const char* key, double value, const char* comment) { PyObject *mylist; mylist = PyList_New(2); PyList_SetItem(mylist, 0, Py_BuildValue("d", value)); PyList_SetItem(mylist, 1, Py_BuildValue("s", comment)); PyDict_SetItemString(dico, key, mylist); Py_DECREF(mylist); } void dict_append_w(PyObject* dico, const char* key, wchar_t *value, const char* comment) { int nline = 10000; char line[10000]; wcstombs(line, value, nline); PyObject *mylist; mylist = PyList_New(2); PyList_SetItem(mylist, 0, Py_BuildValue("s", line)); PyList_SetItem(mylist, 1, Py_BuildValue("s", comment)); PyDict_SetItemString(dico, key, mylist); Py_DECREF(mylist); } void dict_append_s(PyObject* dico, const char* key, char *value, const char* comment) { PyObject *mylist; mylist = PyList_New(2); PyList_SetItem(mylist, 0, Py_BuildValue("s", value)); PyList_SetItem(mylist, 1, Py_BuildValue("s", comment)); PyDict_SetItemString(dico, key, mylist); Py_DECREF(mylist); } // ===================================================================== // ===================================================================== // Internal functions // ===================================================================== // ===================================================================== void isotime(char *iso) { char iso0[BUFFER_TIME_SIZE]; struct timespec now; timespec_get( &now, TIME_UTC ); strftime( iso0, BUFFER_TIME_SIZE, "%FT%T", gmtime( &now.tv_sec ) ); sprintf(iso, "%s.%09ld", iso0, now.tv_nsec); iso[23] = '\0'; // ms } // ===================================================================== // ===================================================================== // Python extension - Common functions // ===================================================================== // ===================================================================== static PyObject* imaseries(PyObject* self, PyObject* args) { //char **argv; //argc = get_argv(cmd, &argv); //int res = 0; //int res = cam_init(&cam, argc, (const char **)argv); //if (res != 0) { // PyErr_SetString(exampleException, cam.msg); // return NULL; //} //free_argv(argc, &argv); // --- Decode input parameters int msg=3; const char *imaseries_command; int argc = (int)PyTuple_GET_SIZE(args); if (argc >= 1) { if ( ! PyArg_ParseTuple(args, "s", &imaseries_command) ) return NULL; } if (strcmp(imaseries_command, "toto") == 0) { printf("YES\n"); } printf("imaseries_command=%s\n",imaseries_command); #if defined WITH_LIBTT msg=libtt_main(TT_SCRIPT_2,1,imaseries_command); #endif if (msg !=0 ) { printf("ERROR TT_SCRIPT_2 %d\n",msg); } PyObject *res = Py_BuildValue("s", imaseries_command); return res; } static PyObject* pimaseries(PyObject* self, PyObject* args) { // libtt.pimaseries(ima, "OFFSET offset=1000") // PyObject *add_module = PyImport_ImportModule("add_module") // // https://stuff.mit.edu/afs/sipb/project/python/src/python-numeric-22.0/doc/www.pfdubois.com/numpy/html2/numpy-13.html char msg[MSG]; // --- libtt allocation of the header --- int datatype,bitpix; int nbkeys; #if defined WITH_LIBTT int errcode; int *datatypes; char **keynames,**values,**comments,**units; #endif // --- Decode input parameters const char *imaseries_command; int argc = (int)PyTuple_GET_SIZE(args); PyObject *ima = NULL; if (argc > 1) { if ( ! PyArg_ParseTuple(args, "Os", &ima, &imaseries_command) ) return NULL; } // --- Get the numpy array from the Ima object --- PyObject *np_array_in = NULL; np_array_in = PyObject_GetAttrString(ima, "_array"); printf("np_array_in=%p\n",np_array_in); // --- Check if the np_array_in id a type of numpy.ndarray --- // If true, returns the NPY_* type of the elements // If false, returns -1 int type_inp = npy_tool_get_type_array(np_array_in); //printf("np_array_in=%p type=%d\n",np_array_in, type_inp); if (type_inp == -2) { sprintf(msg,"1st parameter if not a numpy.ndarray"); PyErr_SetString(exampleException, msg); return NULL; } if (type_inp == NPY_NOTYPE) { sprintf(msg,"1st parameter is a numpy.ndarray but element type is not valid"); PyErr_SetString(exampleException, msg); return NULL; } // --- Convert numpy array from PyObject into PyArrayObject --- PyArrayObject *py_array = NULL; py_array = (PyArrayObject *)PyArray_ContiguousFromAny(np_array_in, type_inp, 0, 2); // --- Check if the py_array has two dimensions --- int nd = PyArray_NDIM(py_array); if (nd != 2) { sprintf(msg,"The numpy.ndarray has %d dimensions (must be 2)", nd); PyErr_SetString(exampleException, msg); return NULL; } // --- Get the dimensions of the array npy_intp *dimensions = PyArray_DIMS(py_array); int naxis1,naxis2; naxis1 = (int)dimensions[1]; naxis2 = (int)dimensions[0]; int nelem = naxis1*naxis2; // --- Alloc the global pointer pg to type float void *p_in; /* if (type_inp == NPY_DOUBLE) { p_in = calloc_pg(nelem, NPY_DOUBLE); datatype = npy_tool_npytype_2_datatype(NPY_DOUBLE); } else { p_in = calloc_pg(nelem, NPY_FLOAT); datatype = npy_tool_npytype_2_datatype(NPY_FLOAT); } */ p_in = calloc_pg(nelem, type_inp); datatype = npy_tool_npytype_2_datatype(type_inp); // --- Fill the global pointer pg (=pointer p_in) by the input py_array copy_pyarray_to_pg(py_array, nelem, false); // false because we ever made a calloc_pg before //printf("p_in=%p type_inp=%d\n", p_in, type_inp); // --- convert Ima cards into the PyObject py_list_cards --- PyObject *py_list_cards = NULL; PyObject *ima_method = PyObject_GetAttrString(ima, "cards"); PyObject *ima_args = PyTuple_New(0); PyObject *ima_kwargs = PyDict_New(); // return a list of header (key, val, comment) py_list_cards = PyObject_Call(ima_method, ima_args, ima_kwargs); //Py_DECREF(ima_method); // ??? Do not dereference ima_method else it kills the method itself Py_DECREF(ima_args); Py_DECREF(ima_kwargs); printf("py_list_cards=%p\n", py_list_cards); //Py_DECREF(ima); // Do not dereference py_array else it kills the object ima itself // --- libtt allocation of the header keys --- nbkeys = (int)PyObject_Length(py_list_cards); printf("nbkeys=%d\n",nbkeys); #if defined WITH_LIBTT errcode = libtt_main(TT_PTR_ALLOKEYS,6,&nbkeys,&keynames,&values,&comments,&units,&datatypes); #endif // --- libtt assignation of the header keys from header cards --- const char *pl = Py_TYPE(py_list_cards)->tp_name; printf("Object type pl = %s\n", pl); PyObject *it = PyObject_GetIter(py_list_cards); PyObject *item; int kcard = -1; if (it) { while ((item = PyIter_Next(it))) { //printf("PyList_Check(item) = %d\n", PyList_Check(item)); //printf("PyTuple_Check(item) = %d\n", PyTuple_Check(item)); //const char *pp = Py_TYPE(item)->tp_name; //printf("Object type = %s\n", pp); //printf("PyObject_size() = %d\n", (int)PyObject_Size(item)); //printf("PyTuple_Size(item) = %d\n", (int)PyTuple_Size(item)); if (PyTuple_Size(item) >=3) { // convert item into (key, val, comment) const char *keyname; PyObject *py_val; const char *comment; if ( ! PyArg_ParseTuple(item, "sOs", &keyname, &py_val, &comment) ) return NULL; kcard++; // assign keynames, comments, units #if defined WITH_LIBTT strcpy(keynames[kcard],keyname); strcpy(comments[kcard],comment); strcpy(units[kcard],""); #endif // assign values, datatypes if (PyBool_Check(py_val)) { int val_int = (int)(PyLong_AsLong(py_val)); #if defined WITH_LIBTT sprintf(values[kcard],"%d", val_int); datatypes[kcard]=TLOGICAL; #endif } else if (PyLong_Check(py_val)) { int val_int = (int)(PyLong_AsLong(py_val)); #if defined WITH_LIBTT sprintf(values[kcard],"%d", val_int); datatypes[kcard]=TINT; #endif if (strcmp(keyname, "BITPIX")==0) { bitpix = val_int; } } else if (PyFloat_Check(py_val)) { #if defined WITH_LIBTT sprintf(values[kcard],"%f",(float)PyFloat_AsDouble(py_val)); datatypes[kcard]=TFLOAT; #endif // TBD double } else { #if defined WITH_LIBTT sprintf(values[kcard], "%s", PyBytes_AsString(py_val)); datatypes[kcard]=TSTRING; #endif } #if defined WITH_LIBTT printf("card %d : %s %s %d (%s)\n",kcard, keynames[kcard], values[kcard], datatypes[kcard], comments[kcard]); #else printf("card %d : %s %d (%s)\n",kcard, keyname, datatype, comment); #endif Py_DECREF(py_val); } Py_DECREF(item); } } Py_DECREF(it); // Py_DECREF(py_list_cards); // ??? do not dereference py_list_cards else Python crashes (after few calls of the method) printf("STEP 1000 datatype=%d naxis1=%d naxis2=%d\n",datatype,naxis1,naxis2); printf("STEP 1005 type_inp=%d pg_type=%d\n", type_inp, pg_type); if (type_inp == NPY_DOUBLE) { printf("STEP 1010 p_in=%p &pgd[0]=%p p_in[%d]=%f\n", p_in, &pgd[0], 0, pgd[0]); } else if (type_inp == NPY_FLOAT) { printf("STEP 1010 p_in=%p &pgf[0]=%p p_in[%d]=%f\n", p_in, &pgf[0], 0, pgf[0]); } else { printf("STEP 1010 p_in=%p\n", p_in); } // --- Call the libtt function 'imaseries_command' #if defined WITH_LIBTT errcode=libtt_main(TT_PTR_IMASERIES,13,&p_in,&datatype,&naxis1,&naxis2,&p_in,&datatype,imaseries_command,&nbkeys,&keynames,&values,&comments,&units,&datatypes); if (errcode !=0 ) { printf("ERROR TT_PTR_IMASERIES %d\n",errcode); } #endif printf("STEP 2000 datatype=%d naxis1=%d naxis2=%d \n",datatype,naxis1,naxis2); printf("STEP 2005 type_inp=%d pg_type=%d\n", type_inp, pg_type); if (type_inp == NPY_DOUBLE) { printf("STEP 2010 p_in=%p &pgd[0]=%p p_in[%d]=%f\n", p_in, &pgd[0], 0, pgd[0]); } else if (type_inp == NPY_FLOAT) { printf("STEP 2010 p_in=%p &pgf[0]=%p p_in[%d]=%f\n", p_in, &pgf[0], 0, pgf[0]); } else { printf("STEP 2010 p_in=%p\n", p_in); } // --- Convert C pointer p_in -> numpy.array (p_in dimension can be changed) // Force the output type to be the same as the input nd = 2; npy_intp dims[2]; dims[0] = naxis2; dims[1] = naxis1; int type_out = npy_tool_datatype_2_npytype(datatype); printf("STEP 2100 type_out=%d\n", type_out); PyObject *np_array_out = PyArray_SimpleNewFromData(nd, dims, type_out, p_in); // --- Prepare the output of the numpy.array PyObject *res = Py_BuildValue("O", np_array_out); Py_DECREF(np_array_out); Py_DECREF(py_array); #if defined WITH_LIBTT errcode = libtt_main(TT_PTR_FREEKEYS,5,&keynames,&values,&comments,&units,&datatypes); #endif // --- Returns the result return res; } // ===================================================================== // ===================================================================== // Python extension - Test functions // ===================================================================== // ===================================================================== static PyObject* matrix(PyObject* self, PyObject* args) { int w, h; double v; printf("PyTuple_GET_SIZE(args)=%d\n", (int)PyTuple_GET_SIZE(args)); if (PyTuple_GET_SIZE(args) >=3) { if ( ! PyArg_ParseTuple(args, "iid", &w, &h, &v) ) return NULL; } printf("w=%d h=%d v=%f\n", w, h, v); // --- C pointer float * p = (float*)calloc(h*w, sizeof(float)); for (int i=0; i numpy.array int nd = 2; npy_intp dims[2]; dims[0] = w; dims[1] = h; int typenum = NPY_FLOAT; PyObject *aout; aout = PyArray_SimpleNewFromData(nd, dims, typenum, (void*)p); // --- Return the numpy.array PyObject* res = Py_BuildValue("O", aout); Py_DECREF(aout); return res; } static PyObject* matrixio(PyObject* self, PyObject* args) { int argc = (int)PyTuple_GET_SIZE(args); PyObject *np_array_in = NULL; if (argc > 0) { if ( ! PyArg_ParseTuple(args, "O", &np_array_in) ) return NULL; } char msg[MSG_ERR]; // --- Check if the np_array_in id a type of numpy.ndarray --- // If true, returns the NPY_* type of the elements // If false, returns -1 int type_inp = npy_tool_get_type_array(np_array_in); //printf("np_array_in=%p type=%d\n",np_array_in, type_inp); if (type_inp == -2) { sprintf(msg,"1st parameter if not a numpy.ndarray"); PyErr_SetString(exampleException, msg); return NULL; } if (type_inp == NPY_NOTYPE) { sprintf(msg,"1st parameter is a numpy.ndarray but element type is not valid"); PyErr_SetString(exampleException, msg); return NULL; } // --- Convert numpy array from PyObject into PyArrayObject --- PyArrayObject *py_array = NULL; py_array = (PyArrayObject *)PyArray_ContiguousFromAny(np_array_in, type_inp, 0, 2); // --- Check if the py_array has two dimensions --- int nd = PyArray_NDIM(py_array); if (nd != 2) { sprintf(msg,"The numpy.ndarray has %d dimensions (must be 2)", nd); PyErr_SetString(exampleException, msg); return NULL; } // --- Get the dimensions of the array npy_intp *dimensions = PyArray_DIMS(py_array); int naxis1,naxis2; naxis1 = (int)dimensions[1]; naxis2 = (int)dimensions[0]; int nelem = naxis1*naxis2; // --- Alloc the global pointer pg to type float void *p_in; if (type_inp == NPY_DOUBLE) { p_in = calloc_pg(nelem, NPY_DOUBLE); } else { p_in = calloc_pg(nelem, NPY_FLOAT); } // --- Fill the global pointer pg (=pointer p_in) by the input py_array copy_pyarray_to_pg(py_array, nelem, false); // false because we ever made a calloc_pg before //printf("p_in=%p type_inp=%d\n", p_in, type_inp); // --- Convert C pointer p_in -> numpy.array (p_in dimension can be changed) // Force the output type to be the same as the input nd = 2; npy_intp dims[2]; dims[0] = naxis2; dims[1] = naxis1; int type_out = type_inp; PyObject *np_array_out = PyArray_SimpleNewFromData(nd, dims, type_out, p_in); // --- Prepare the output of the numpy.array PyObject *res = Py_BuildValue("O", np_array_out); Py_DECREF(np_array_out); Py_DECREF(py_array); // --- Returns the result return res; } static PyObject* example2(PyObject* self, PyObject* args) { printf( "C/C++ code fire an exception\n" ); // Levée d'une exception Python : elle sera rattrapée en Python. PyErr_SetString(exampleException, "Exemple de levée d'erreur en C"); // On ne renvoie donc pas de valeur de retour particulière. return NULL; } // ===================================================================== // ===================================================================== // Python extension - Method definitions // ===================================================================== // ===================================================================== static PyMethodDef functions[] = { // --- Common for devices {"pimaseries", pimaseries, METH_VARARGS, "Call libtt imaseries for one image"}, {"imaseries", imaseries, METH_VARARGS, "Call libtt imaseries for TT_SCRIPT2"}, // --- Tests {"example2", example2, METH_VARARGS, "Une fonction levant une exception"}, {"matrix", matrix, METH_VARARGS, "Create a matrix and returns a numpy array"}, {"matrixio", matrixio, METH_VARARGS, "Read a numpy array and returns it"}, {NULL, NULL, 0, NULL} }; // ===================================================================== // ===================================================================== // Python extension - Module definition // ===================================================================== // ===================================================================== static struct PyModuleDef myModule = { PyModuleDef_HEAD_INIT, "libtt", /* nom du module */ "Image processing library", /* documentation du module, ou NULL si non proposée */ -1, /* -1 => état du module stocké en global */ functions /* Tableau des fonctions exposées */ }; // ===================================================================== // ===================================================================== // Python extension - Module initialisation // ===================================================================== // ===================================================================== PyMODINIT_FUNC PyInit_libtt(void) { // Création du module PyObject * module = PyModule_Create( &myModule ); if ( module == NULL ) return NULL; // Création d'une instance d'exception exampleException = PyErr_NewException( "libtt.error", NULL, NULL ); Py_INCREF( exampleException ); PyModule_AddObject( module, "error", exampleException ); numpy = PyImport_ImportModule("numpy"); import_array(); // for numpy pgs = NULL; // global array of short pgus = NULL; // global array of unsigned short pgi = NULL; // global array of int pgui = NULL; // global array of unsigned int pgf = NULL; // global array of float pgd = NULL; // global array of double pg_type = NPY_NOTYPE; // On doit renvoyer le module nouvellement créé return module; }