我正在为使用SWIG公开其C ++ API的程序编写python脚本。 SWIG公开的函数有如下界面:
void writePixelsRect(JoxColor* colors, int left, int top, int width, int height);
JoxColor是一个POD结构,如下所示:
struct JoxColor {
float r, g, b, a;
};
我可以在Python中轻松创建一个JoxColor并调用writePixelsRect调用,如下所示:
c = JoxApi.JoxColor()
c.r = r
c.g = g
c.b = b
c.a = a
JoxApi.writePixelsRect(c, x, y, 1, 1)
反复调用带有1x1像素矩形的writePixelsRect非常慢,所以我想从python创建一个JoxColor数组,这样我就可以编写更大的矩形了。 SWIG类型可以实现吗?
请注意,我无法访问暴露JoxColor和writePixelsRect的C ++库的源代码,因此无法为此添加帮助功能。我也不想在系统中引入新的C ++代码,因为它会强制我的python脚本的用户在他们运行的任何平台上编译C ++代码。我可以在python环境中访问ctypes,所以如果我能以某种方式将在ctypes中创建的float数组类型转换为适用于SWIG的JoxColor *类型,那么它对我有用。
答案 0 :(得分:2)
这有点棘手,但至少对于这部分代码,您是否可以使用纯ctypes解决方案?基本上手动查看共享库文件导出的符号,以查找writePixelsRect函数导出的名称。 C ++确实命名为mangling,因为如果库作者选择使它writePixelsRect
,它可能只是extern "C"
,它可能会更加混乱,比如_Z15writePixelsRectP8JoxColoriiii
(这就是它的导出方式)我刚刚在我的系统上创建的虚拟C ++库。
在Linux上,此命令应该告诉您符号名称:
nm libjox.so | grep writePixel | cut -d " " -f 3
然后,保存该字符串并将其插入到Python代码中,如下所示:
from ctypes import *
LIBRARY_NAME = 'libjox.so'
c = cdll.LoadLibrary(LIBRARY_NAME)
WIDTH = 20
HEIGHT = 20
class JoxColor(Structure):
_fields_ = [("r", c_float), ("g", c_float), ("b", c_float), ("a", c_float)]
ColorBlock = JoxColor * (WIDTH * HEIGHT)
data_array = ColorBlock()
color = JoxColor(0, 0, 1, 0)
for i in range(WIDTH * HEIGHT):
data_array[i] = color
c._Z15writePixelsRectP8JoxColoriiii(data_array, 0, 0, WIDTH, HEIGHT)
假设_Z15writePixelsRectP8JoxColoriiii
是可以在共享库中访问该函数的符号。运行此代码只是在我的系统上使用虚拟库,如下所示:
#include <stdio.h>
struct JoxColor {
float r, g, b, a;
};
void writePixelsRect(JoxColor *colors, int left, int top, int width, int height) {
int p = 0;
printf("size: %i, %i\n", width, height);
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
JoxColor color = colors[p];
printf("pixel: %f, %f, %f, %f\n", color.r, color.g, color.b, color.a);
}
}
}
所以我希望它与您环境中的代码相差不远。
答案 1 :(得分:0)
禁止使用特殊的类型图,这个SWIG原型
void writePixelsRect(JoxColor* colors, int left, int top, int width, int height);
表示colors
是JoxColor
类型的单个对象,而不是数组。只用一个对象进行调用(尽管速度很慢)这一事实表明这是正确的。因此,传递数组可能只是从SWIG包装器代码中给出类型不匹配错误。
但老实说,这看起来像是一个写一个任意大矩形的函数。因此,如果你想绘制一个更大的矩形(一种颜色),只需要传递更大的宽度和/或高度:
JoxApi.writePixelsRect(c, x, y, 10, 20)
修改强>
我没有意识到你正在编写SWIG封装器,我认为这是提供给你的。在这种情况下,您可以编写一个类型映射,将Python列表(或元组,或任何您想要的)转换为JoxColor *。
SWIG文档展示了如何将Python字符串列表变为char **的示例:http://www.swig.org/Doc1.3/Python.html#Python_nn59
typemap使用Python C API进行转换,您可以使用Python文档所说的任何内容。基本上你分配一个JoxColor数组然后迭代Python列表对象并使用PyList_GetItem
来获取每个单独的对象。这将返回SWIG包装的PyObject,您可以使用SWIG_ConvertPtr(list_item_py_object, (void**)&joxcolor_ptr, $descriptor(JoxColor *), 0)
将其转换为指向实际JoxColor元素的指针。然后你可以将它复制到你的数组中。
请注意,JoxColor*
的类型地图将适用于所有JoxColor*
出现的地方,您可以说JoxColor* colors
专门针对这种情况。
FYI,默认情况下,SWIG以完全相同的方式包装JoxColor *,JoxColor&amp;,JoxColor和JoxColor []作为单个对象。 Python只有对象,它不知道指针/引用/数组(Python列表也是对象)。 http://www.swig.org/Doc1.3/Python.html#Python_nn22