我试图通过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。另外,它不能处理分配到从不可缓冲的缓冲器对象,如整数。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top