gpt4 book ai didi

python - 将 bytearray 传递给 C++ 扩展时出现 TypeError

转载 作者:行者123 更新时间:2023-11-28 02:58:09 49 4
gpt4 key购买 nike

Python代码:

image = urllib2.urlopen('http://localhost/test.png').read()
bytes = bytearray(image)
print [myext.do_stuff(bytes, mode=1)]

C++代码:

static PyObject * 
do_stuff(PyObject *self, PyObject *args, PyObject *kwargs)
{
PyByteArrayObject *imgdata;
char *image;
int mode;
char *keywords[] = { "image", "mode", NULL };

if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|i", keywords, &imgdata, &mode))
return NULL;

image = PyByteArray_AsString((PyObject*) imgdata);
char *result = do_something_more(image, mode);
return Py_BuildValue("s", result);
}

添加:

char * do_something_more(char imagebuffer[], int mode)
{
vector<char> vec(imagebuffer, imagebuffer + sizeof(imagebuffer));
Mat input = imdecode(vec, 1);
}

最佳答案

类型错误仅仅是因为 Y 格式说明符存在于 python2 而只存在于 python3。如果要在 python2 中传递 bytearray,则必须使用 O 格式说明符。

结果字符串只是实际内容的前几个字节这一事实非常简单:

  • strlen 是一个处理 C null 终止 字符串的 C 函数。您的图像数据包含一些空字节,因此函数 返回实际 大小。
  • PyBuild_Values 格式说明符采用 C null 终止 字符串并返回 python 字符串对象。由于您的数据包含空字节,因此并非所有内容都放在结果中。

在您的 C++ 代码中,char *image 指针确实指向所有数据,但您不应该> 如果您的字符串包含空字节,则依赖 C 的字符串函数。您必须始终跟踪字符串的长度。


为了更清楚地表达我的意思。这是一个独立的 C 扩展,可用于演示您的问题:

#include <Python.h>


static PyObject *
do_stuff(PyObject *self, PyObject *args, PyObject *kwargs)
{
PyByteArrayObject *imgdata;
char *image;
int mode;
char *keywords[] = { "image", "mode", NULL };

if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|i", keywords, &imgdata, &mode))
return NULL;

image = PyByteArray_AsString((PyObject*) imgdata);
return Py_BuildValue("s", image);
}

static PyMethodDef noddy_methods[] = {
{"do_stuff", do_stuff, METH_VARARGS | METH_KEYWORDS, "Does stuff"},
{NULL, NULL, 0, NULL} /* Sentinel */
};

void
initdemo(void)
{
(void) Py_InitModule("demo", noddy_methods);
}

使用setup.py:

from distutils.core import setup, Extension

module1 = Extension('demo',
sources = ['demo_ext.c'])

setup (name = 'Demo',
version = '1.0',
description = 'This is a demo package',
ext_modules = [module1])

用作:

>>> import demo
>>> with open('/Path/to/A/PNG/Image.png', 'rb') as f:
... contents = f.read()
...
>>> byt = bytearray(contents)
>>> byt[:20]
bytearray(b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x02V')
>>> demo.do_stuff(byt) # "truncates" the data
'\x89PNG\r\n\x1a\n'

现在,如果您将 do_stuff 函数更改为:

static PyObject * 
do_stuff(PyObject *self, PyObject *args, PyObject *kwargs)
{
PyObject *imgdata;
char *image;
int mode;
Py_ssize_t length;
char *keywords[] = { "image", "mode", NULL };

if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|i", keywords, &imgdata, &mode))
return NULL;

image = PyByteArray_AsString(imgdata);
length = PyObject_Length(imgdata);
PyObject *res = PyString_FromStringAndSize(image, length);
return res;
}

你得到:

>>> import demo
>>> with open('/home/giacomo/Immagini/bad_grouping.png', 'rb') as f:
... contents = f.read()
...
>>> byt = bytearray(contents)
>>> byt[:20]
bytearray(b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x02V')
>>> demo.do_stuff(byt)[:20]
'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x02V'

如您所见,do_stuff 不再截断数据。

strlen 等所有函数都假定字符串中不存在空字节,如果不是这样(如本例),则会出现错误行为。此外,一些 python 的 API 调用采用 C 字符串,例如 Py_BuildValue。如您所见,char *image 确实 包含所有 数据。问题是您使用的函数无法正确处理它。

关于python - 将 bytearray 传递给 C++ 扩展时出现 TypeError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21522810/

49 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com