1 """
2 Module to convert a numpy array to a ctypes struct.
3 This struct can then be passed to a native C library.
4
5 Author: Joris De Ridder
6 """
7
8 import numpy as np
9 import ctypes as C
10
11
12
13 ctypesDict = {'d' : C.c_double,
14 'b' : C.c_char,
15 'h' : C.c_short,
16 'i' : C.c_int,
17 'l' : C.c_long,
18 'q' : C.c_longlong,
19 'B' : C.c_ubyte,
20 'H' : C.c_ushort,
21 'I' : C.c_uint,
22 'L' : C.c_ulong,
23 'Q' : C.c_ulonglong}
24
25
26
27
28
29
30 -def c_ndarray(a, dtype = None, ndim = None, shape = None, requirements = None):
31
32 """
33 Returns a ctypes structure of the array 'a'
34 containing the arrays info (data, shape, strides, ndim).
35 A check is made to ensure that the array has the specified dtype
36 and requirements.
37
38 Example:
39
40 >>> myArray = np.arange(10.0)
41 >>> myCstruct = c_ndarray(myArray, dtype=np.double, ndim = 3, shape = (4,3,2),
42 ... requirements = ['c_contiguous'])
43
44 @param a: the numpy array to be converted
45 @type a: ndarray
46 @param dtype: the required dtype of the array, convert if it doesn't match
47 @type dtype: numpy dtype
48 @param ndim: the required number of axes of the array,
49 complain if it doesn't match
50 @type ndim: integer
51 @param shape: required shape of the array, complain if it doesn't match
52 @type shape: tuple
53 @param requirements: "ensurearray", "aligned", "fortran", "f_contiguous",
54 or "c_contiguous". Convert if it doesn't match.
55 @type requirements: list
56 @return: ctypes structure with the fields:
57 - data: pointer to the data : the type is determined with the
58 dtype of the array, and with ctypesDict.
59 - shape: pointer to long array : size of each of the dimensions
60 - strides: pointer to long array : strides in elements (not bytes)
61 @rtype: ctypes structure
62
63 """
64
65 if not requirements:
66
67
68
69 array = np.asanyarray(a, dtype=dtype)
70
71 else:
72
73
74
75
76
77
78 requirements = [x[0].upper() for x in requirements]
79 subok = (0 if 'E' in requirements else 1)
80
81
82
83
84 array = np.array(a, dtype=dtype, copy=False, subok=subok)
85
86
87
88
89 copychar = 'A'
90 if 'F' in requirements:
91 copychar = 'F'
92 elif 'C' in requirements:
93 copychar = 'C'
94
95 for req in requirements:
96 if not array.flags[req]:
97 array = array.copy(copychar)
98 break
99
100
101
102
103 if ndim is not None:
104 if array.ndim != ndim:
105 raise TypeError, "Array has wrong number of axes"
106
107 if shape is not None:
108 if array.shape != shape:
109 raise TypeError, "Array has wrong shape"
110
111
112
113
114 class ndarrayInterfaceToCtypes(C.Structure):
115 pass
116
117 typechar = array.dtype.char
118
119 if typechar in ctypesDict:
120 ndarrayInterfaceToCtypes._fields_ = \
121 [("data", C.POINTER(ctypesDict[typechar])),
122 ("shape" , C.POINTER(C.c_long)),
123 ("strides", C.POINTER(C.c_long))]
124 else:
125 raise TypeError, "dtype of input ndarray not supported"
126
127
128
129
130 ndarrayInterface = ndarrayInterfaceToCtypes()
131 ndarrayInterface.data = array.ctypes.data_as(C.POINTER(ctypesDict[typechar]))
132 ndarrayInterface.shape = (C.c_long * array.ndim)(*array.shape)
133 ndarrayInterface.strides = (C.c_long * array.ndim)(*array.strides)
134 for n in range(array.ndim):
135 ndarrayInterface.strides[n] /= array.dtype.itemsize
136
137 return ndarrayInterface
138