分配成Python 3.x中缓冲器,具有itemsize> 1
-
21-09-2019 - |
题
我试图通过Python以暴露的图象的象素信息(32位RGBA)的缓冲3.X缓冲器接口。相当多的玩耍后,我能得到这个工作,像这样:
int Image_get_buffer(PyObject* self, Py_buffer* view, int flags)
{
int img_len;
void* img_bytes;
// Do my image fetch magic
get_image_pixel_data(self, &img_bytes, &img_len);
// Let python fill my buffer
PyBuffer_FillInfo(view, self, img_bytes, img_len, 0, flags);
}
和在python我可以发挥它像这样:
mv = memoryview(image)
print(mv[0]) # prints b'\x00'
mv[0] = b'\xFF' # set the first pixels red component to full
mx[0:4] = b'\xFF\xFF\xFF\xFF' # set the first pixel to white
和该作品出色。然而,这将是巨大的,如果我能与全像素值(INT,4字节),而不是单个字节工作,所以我改性缓冲器取像这样:
int Image_get_buffer(PyObject* self, Py_buffer* view, int flags)
{
int img_len;
void* img_bytes;
// Do my image fetch magic
get_image_pixel_data(self, &img_bytes, &img_len);
// Fill my buffer manually (derived from the PyBuffer_FillInfo source)
Py_INCREF(self);
view->readonly = 0;
view->obj = self;
view->buf = img_bytes;
view->itemsize = 4;
view->ndim = 1;
view->len = img_len;
view->suboffsets = NULL;
view->format = NULL;
if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT)
view->format = "I";
view->shape = NULL;
if ((flags & PyBUF_ND) == PyBUF_ND)
{
Py_ssize_t shape[] = { (int)(img_len/4) };
view->shape = shape;
}
view->strides = NULL;
if((flags & PyBUF_STRIDED) == PyBUF_STRIDED)
{
Py_ssize_t strides[] = { 4 };
view->strides = strides;
}
return 0;
}
这实际上返回的数据,我可以正确读取,但任何试图赋值到现在失败!
mv = memoryview(image)
print(mv[0]) # prints b'\x00\x00\x00\x00'
mv[0] = 0xFFFFFFFF # ERROR (1)
mv[0] = b'\xFF\xFF\xFF\xFF' # ERROR! (2)
mv[0] = mv[0] # ERROR?!? (3)
在壳体1的错误通知我'int' does not support the buffer interface
,这是一种耻辱和有点混乱(I没有指定该缓冲区格式是“I”毕竟),但我可以处理这一点。在情况2件3事情变得很古怪,但:这两种情况吉美我一个类型错误读数mismatching item sizes for "my.Image" and "bytes"
(其中my.Image
是,很明显,我的形象型)
这是非常混乱给我,因为我传递的数据是明显的大小与我所得到的该元素的出来一样。它好像缓冲区简单地停止允许转让,如果itemsize比1。当然更大,此接口的文档非常稀疏,并通过Python代码细读并没有真正放弃任何的使用例子,让我相当坚持。我错过了文档中的某些SNIPPIT各国“缓冲区变成基本上是无用的,当itemsize> 1”,我是不是做错了什么,我看不出来,或者这是Python中的错误吗? (针对3.1.1测试)
感谢您能在这个(公认先进的)问题给予任何见解!
解决方案
我在函数memory_ass_sub(在对象中memoryobject.c)发现此在Python代码:
/* XXX should we allow assignment of different item sizes
as long as the byte length is the same?
(e.g. assign 2 shorts to a 4-byte slice) */
if (srcview.itemsize != view->itemsize) {
PyErr_Format(PyExc_TypeError,
"mismatching item sizes for \"%.200s\" and \"%.200s\"",
view->obj->ob_type->tp_name, srcview.obj->ob_type->tp_name);
goto _error;
}
这是后者两个错误的来源。它看起来像itemsize即使MV [0]是仍然不等于本身。
更新
这是我觉得是怎么回事。当您尝试在MV分配的东西,它调用的对象/ memoryobject.c memory_ass_sub,但该功能只需要的PyObject作为输入。这个对象然后变成一个缓冲区内的MV的情况下,使用PyObject_GetBuffer功能即使[0]这已经是一个缓冲区(和你想要的缓冲!)。我的猜测是,这个函数接受对象,使得它成为一个简单的缓冲不管它是否已经是一个缓冲与否itemsize = 1。这就是为什么你得到的不匹配项,甚至尺寸为
mv[0] = mv[0]
与所述第一分配的问题,
MV [0] = 0xFFFFFFFF的
从检查所述int是能够被用作缓冲,目前它不建立从我明白茎(我想)。
在换句话说,缓冲系统目前不能够处理的商品尺寸更大,从1。它看起来并不像它是那么遥远,但还需要在你的最终更多的工作。如果你得到它的工作,你或许应该提交更改回主Python发行。
另一个更新
从第一次尝试分配MV错误代码[0]从INT失败的PyObject_CheckBuffer时PyObject_CheckBuffer上调用它茎。显然,系统只处理来自缓冲的对象拷贝。这似乎是它也应该被改变。
<强>结论强>
目前Python的缓冲系统不能与itemsize如你猜处理项目> 1。另外,它不能处理分配到从不可缓冲的缓冲器对象,如整数。