2011-05-02 15 views
5

Estoy escribiendo una secuencia de comandos python para un programa que ha expuesto su API de C++ utilizando SWIG. un trago expuesta función tiene un interfaz de la siguiente manera:Asignación de matriz de tipo SWIG C++ desde Python

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

JoxColor es una estructura POD con este aspecto:

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

puedo crear fácilmente una sola JoxColor en Python e invocar una llamada a writePixelsRect como esto:

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

writePixelsRect repetidamente llamar con un rectángulo de 1x1 píxeles es muy lento, así que quiero crear una matriz de JoxColor del pitón por lo que ca n escribir rectángulos más grandes en el momento. ¿Es esto posible con los tipos de SWIG?

Tenga en cuenta que no tengo acceso al código fuente de la biblioteca de C++ y exponer JoxColor writePixelsRect así que no puedo agregar una función de ayuda para esto. Tampoco quiero introducir un nuevo código C++ en el sistema, ya que obligaría a los usuarios de mi script python a compilar el código C++ en la plataforma que estén ejecutando. Tengo acceso a ctypes en el entorno python, así que si pudiera convertir de alguna manera una matriz flotante creada en tipos al tipo de JoxColor * para SWIG, funcionaría para mí.

+0

¿Es posible modificar la pieza de envoltura SWIG? – Martin

+0

¿Tiene acceso al archivo * .swig? ¿Podría verificar si incluye funcionalidades de las bibliotecas de SWIG como cpointer.i, carrays.i o cmalloc.i - http://www.swig.org/Doc1.3/Library.html. Tal vez alguien que preparó este contenedor SWIG ya incluía la funcionalidad de manejar el arreglo de JoxColor? También puede consultar el archivo JoxAPImodule.py para ver una lista de todas las funciones y clases disponibles. – Zuljin

+0

No tengo acceso a los archivos swig y no puedo modificar la parte SWIG wrapping. – Laserallan

Respuesta

2

Esto es un poco complicado, pero puede que, al menos para esta parte del código, utilice una solución de ctypes puros? Básicamente, mire manualmente los símbolos exportados por el archivo de biblioteca compartida para encontrar el nombre con el que se exportó la función writePixelsRect. C++ hace renombrado de nombres, así que mientras que sólo podría ser writePixelsRect si los autores de la biblioteca eligieron para que sea extern "C", podría ser algo mucho más desordenado, como _Z15writePixelsRectP8JoxColoriiii (eso es lo que se exporta en un maniquí biblioteca de C++ que acaba de crear en mi sistema).

En Linux, este comando debe decirle el nombre del símbolo:

nm libjox.so | grep writePixel | cut -d " " -f 3 

A continuación, guardar esa cadena y la inserta en el código Python un poco como esto:

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) 

Suponiendo que _Z15writePixelsRectP8JoxColoriiii es el símbolo de que la función es accesible como en la biblioteca compartida. La ejecución de este código justo trabajado en mi sistema con una biblioteca ficticia como esto:

#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); 
     } 
    } 
} 

Así que tengo la esperanza de que no está demasiado lejos del código de trabajo en su entorno.

+0

Además, si desea ejecutar esta prueba, el código de la biblioteca anterior debe tratarse como C++, no como C, para replicar el nombre de creación de engranajes (detesto escribir C++). En otras palabras, guarde en un archivo ".cpp" y compile con g ++. – gsteff

+0

No estoy seguro de cómo es en Linux, pero en Windows, creo que el módulo no exporta todas las funciones/métodos que proporciona a Python. Solo exporta una función llamada PyInit_modulename o initmodulename y a través de esta función llama a todo lo demás. Creo que no puedes importar writePixelsRect directamente usando ctypes, porque no está allí. – Zuljin

+0

Gracias. De hecho, tengo acceso a las funciones originales de C++ api, pero no las consideré debido al cambio. Sin embargo, puedo mantener el código basado en swig como una alternativa para plataformas donde no logro descifrar el nombre del símbolo destrozado :) – Laserallan

0

Salvo typemaps especiales, este SWIG prototipo

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

significa que colors es un solo objeto de tipo JoxColor, no una matriz. El hecho de que su llamada con un solo objeto funcione (aunque lentamente) sugiere que eso es cierto. Por lo tanto, pasar una matriz es probable que solo le dé un error de coincidencia de tipo del código SWIG wrapper.

Pero, sinceramente, esto parece una función que escribe un rectángulo arbitrariamente grande.Así que si quieres dibujar un rectángulo de mayor tamaño (de un color) sólo tiene que pasar en una anchura y/o altura mayor:

JoxApi.writePixelsRect(c, x, y, 10, 20) 

Editar: no me daba cuenta que estaba escribiendo la envoltura TRAGO, me pensé que se te había proporcionado. En ese caso, puede escribir un mapa de tipos que convertirá una lista de Python (o tupla, o lo que quiera) en JoxColor *. Los documentos SWIG muestran un ejemplo de cómo convertir una lista de cadenas de Python en caracteres **: http://www.swig.org/Doc1.3/Python.html#Python_nn59 El mapa de tipos utiliza las API de Python C para realizar la conversión, puede usar cualquier cosa que digan los documentos de Python. Esencialmente asigna una matriz de JoxColor y luego itera sobre el objeto de la lista de Python y usa PyList_GetItem para obtener cada objeto individual. Eso devolverá un PyObject envuelto en SWIG, puede usar SWIG_ConvertPtr(list_item_py_object, (void**)&joxcolor_ptr, $descriptor(JoxColor *), 0) para convertirlo en un puntero a su elemento JoxColor real. Entonces puedes copiar eso en tu matriz.

Recuerde que se aplicará un mapa de tipos para JoxColor* donde aparezca JoxColor*, puede decir JoxColor* colors para especializarlo en este caso.

FYI, de forma predeterminada SWIG ajusta JoxColor *, JoxColor &, JoxColor y JoxColor [] exactamente de la misma manera, como un solo objeto. Python solo tiene objetos, no sabe de punteros/referencias/matrices (las listas de Python también son objetos). http://www.swig.org/Doc1.3/Python.html#Python_nn22

+0

Es una forma de interpretar la API, pero no lo que hace. Toma un puntero a un conjunto de píxeles y los copia en la imagen de destino en el rectángulo especificado. La razón más probable por la que no se asignó correctamente a SWIG es que es una API enorme y gran parte de la SWIG: ing se realizó automáticamente y esta función parece necesitar más atención para funcionar todo el tiempo. – Laserallan

+0

No me di cuenta de que estabas escribiendo el envoltorio SWIG tú mismo. Ver mi edición – Adam

+0

No escribo mi propia envoltura SWIG. Es una gran API de C++ que ha sido expuesta más o menos automáticamente como para los programadores de python que usan SWIG. Tengo acceso a los dll de C++ pero no a los archivos SWIG y no es una opción cambiar el código de ajuste real. – Laserallan

Cuestiones relacionadas