Question

I am trying to convert a C++ buffer to a python::boost::list, my C++ class is:

#include "boost/python/list.hpp"

using namespace boost::python;

class Buffer {
public:
    unsigned char* m_pBuff;
    int m_iWidth;
    int m_iHeight;


    Buffer( cont int p_iWidth, const int p_iHeight ) {
        m_pBuff = new unsigned char[p_iWidth * p_iHeight];

        m_iWidth  = p_iWidth;
        m_iHeight = p_iHeight;
    }

    ~Buffer() { delete[] m_pBuff; }

    /* Class Functions */

    list getList ( void ) {
        list l;
        l.append(m_iWidth);
        l.append(m_iHeight);

        std::string data(m_iWidth * m_iHeight, ' ');

        unsigned char* pBuff = m_pBuff;
        for ( int i = 0; i < m_iWidth * m_iHeight; ++i, ++pBuff ) {
            data[i] = (char*) *pBuff;
        }

        l.append(data);

        return l;
    }
};

And the python boost module is defined as:

using namespace boost::python;

BOOST_PYTHON_MODULE(BufferMethods)
{

    class_<Buffer>("Buffer", init<const int, const int>()) 
        .add_property("width", &Buffer::m_iWidth)
        .add_property("height", &Buffer::m_iHeight)
        /* Other functions */
        .def("getList", &Buffer::getList)
    ;
}

But when I run the module in python it return this error:

>>> from BufferMethods import *
>>> Buff = Buffer(800, 600)
>>> dataList = Buff.getList()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe0 in position 0: invalid continuation byte
>>>

What I am doing wrong?? I am using python 3.3.

Was it helpful?

Solution

When you're trying to append items into a boost::python::list instance, the python type of the appended item is determined from the type of the C++ object given as the argument. Since your data is of type std::string, this append operation is attempting to create a Python string. Speculation: I guess python strings need to adhere to some layout, and since you're simply feeding it some random data, it fails to interpret it as a valid string, that's why you get a UnicodeDecodeError. I don't know what exactly you intend to do with the list, and how you would like to expose your buffer to Python, but the following seems to work (using a std::vector<char> as the type of data instead of std::string):

#include <boost/python.hpp>
#include <boost/python/list.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
#include <vector>

using namespace boost::python;

class Buffer {
public:
    unsigned char* m_pBuff;
    int m_iWidth;
    int m_iHeight;


    Buffer( const int p_iWidth, const int p_iHeight ) {
        m_pBuff = new unsigned char[p_iWidth * p_iHeight];

        m_iWidth  = p_iWidth;
        m_iHeight = p_iHeight;
    }

    ~Buffer() { delete[] m_pBuff; }

    /* Class Functions */

    list getList ( void ) {
        list l;
        l.append(m_iWidth);
        l.append(m_iHeight);

        std::vector<char> data(m_iWidth*m_iHeight);

        unsigned char* pBuff = m_pBuff;
        for ( int i = 0; i < m_iWidth * m_iHeight; ++i, ++pBuff ) {
            data[i] = (char) *pBuff;
        }

        l.append(data);

        return l;
    }
};

BOOST_PYTHON_MODULE(BufferMethods)
{

    class_<std::vector<char> >("CharVec")
            .def(vector_indexing_suite<std::vector<char> >());


    class_<Buffer>("Buffer", init<const int, const int>()) 
        .add_property("width", &Buffer::m_iWidth)
        .add_property("height", &Buffer::m_iHeight)
        /* Other functions */
        .def("getList", &Buffer::getList)
    ;
}

So in python (3.2):

In [1]: from BufferMethods import *

In [2]: Buff = Buffer(800,600)

In [3]: dataList = Buff.getList()

In [4]: dataList[2]
Out[4]: <BufferMethods.CharVec at 0x18172d0>

In [5]: dataList[2][2]
Out[5]: '\x00'

OTHER TIPS

The problem is solved using Python 2.7 ... maybe the error is caused because I am using the unofficial build python.boost from here.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top