我正在尝试通过 Python 3.x 缓冲区接口公开图像像素信息的缓冲区(32 位 RGBA)。经过相当多的玩耍,我能够像这样工作:
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”毕竟),但我可以处理。但是,如果第 2 和第 3 种情况变得非常奇怪:两种情况都给我一个 TypeError 读数(显然,我的图像类型mismatching item sizes for "my.Image" and "bytes"
在哪里)my.Image
这让我很困惑,因为我传入的数据显然与我从该元素中得到的数据大小相同。如果 itemsize 大于 1,似乎缓冲区只是停止允许分配。当然,此接口的文档非常稀疏,并且仔细阅读 python 代码并没有真正给出任何使用示例,所以我相当卡住。我是否遗漏了一些说明“当 itemsize > 1 时缓冲区基本上无用”的文档片段,我是否做错了我看不到的事情,或者这是 Python 中的错误?(针对 3.1.1 进行测试)
感谢您对这个(公认的高级)问题提供的任何见解!