Распределение массива типа SWIG C ++ из Python - PullRequest
5 голосов
/ 03 мая 2011

Я пишу скрипт на python для программы, которая представила свой C ++ API с использованием SWIG. Открытая функция SWIG имеет такой интерфейс:

void writePixelsRect(JoxColor* colors, int left, int top, int width, int height);

JoxColor - это структура POD, похожая на эту:

struct JoxColor {
    float r, g, b, a;
};

Я могу легко создать один JoxColor в Python и вызвать вызов writePixelsRect следующим образом:

c = JoxApi.JoxColor()
c.r = r
c.g = g
c.b = b
c.a = a
JoxApi.writePixelsRect(c, x, y, 1, 1)

Повторный вызов writePixelsRect с прямоугольником размером 1x1 очень медленный, поэтому я хочу создать массив JoxColor из python, чтобы я мог писать большие прямоугольники в то время. Это возможно с типами SWIG?

Обратите внимание, что у меня нет доступа к исходному коду для библиотеки C ++, выставляющего JoxColor и writePixelsRect, поэтому я не могу добавить функцию справки для этого. Я также не хочу вводить новый код C ++ в систему, поскольку это заставит пользователей моего скрипта на python компилировать код C ++ на любой платформе, на которой они работают. У меня есть доступ к ctypes в среде python, поэтому, если бы я мог как-то типизировать массив float, созданный в ctypes, к типу JoxColor * для SWIG, это бы сработало для меня.

Ответы [ 2 ]

2 голосов
/ 05 мая 2011

Это довольно сложно, но не могли бы вы, по крайней мере для этой части кода, использовать решение с чистым типом? В основном, вручную просмотрите символы, экспортируемые из общего файла библиотеки, чтобы найти имя, под которым была экспортирована функция writePixelsRect. В C ++ происходит искажение имен, поэтому, хотя авторы библиотек решили сделать это extern "C", это может быть просто writePixelsRect, но это может быть что-то намного более запутанное, например _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);
        }
    }
}

Так что я надеюсь, что это не слишком далеко от рабочего кода в вашей среде.

0 голосов
/ 10 мая 2011

За исключением специальных карт типов, этот прототип 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 Карта типов использует для преобразования API-интерфейсы Python C, вы можете использовать все, что говорят документы 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 &, JoxColor и JoxColor [] точно так же, как один объект.Python имеет только объекты, он не знает указателей / ссылок / массивов (списки Python также являются объектами).http://www.swig.org/Doc1.3/Python.html#Python_nn22

...