/*
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;
}