The frame is following: PySide2 QImage gives me access to the internal pixel data with the bits()
- call. The call returns memoryview - object that i would like to pass C-library function that does processing on the image pixel data (say it does super-fancy-blur for an example).
Problem is that i have not found a way to get memoryview underlaying data as ctypes call parameter.
That is: how can i get from memoryview object ctypes.c_void_p
(or similar) -- without making copy of the buffer. The memoryview tobytes()
returns bytes, but its copy from the memory, and so modifying that will not modify the original image (pixel data).
Now the minimal example python silly.py
side is:
import ctypes
from PySide2.QtGui import QImage
img = QImage(500,100, QImage.Format.Format_RGB32 )
data = img.bits()
print(data)
dll = ctypes.CDLL( "./silly.o" )
dll_set_image = getattr( dll, "set_image" )
dll_set_image.argtypes = [ ctypes.c_void_p, ctypes.c_uint32, ctypes.c_uint32 ]
# Next line gives: ctypes.ArgumentError: argument 1: <class 'TypeError'>: wrong type
dll_set_image( data, img.width(), img.height() )
C-"dll": silly.c
#include <stdint.h>
#include <stdio.h>
void set_image( void* data, uint32_t xsize, uint32_t ysize )
{
printf("Data set %lx %d %d", (uint64_t)data, xsize, ysize );
}
Compiling and testing:
% gcc -shared -o silly.o silly.c
% python3 silly.py
<memory at 0x7f2f9806a700>
Traceback (most recent call last):
File "silly.py", line 13, in <module>
dll_set_image( data, img.width(), img.height() )
ctypes.ArgumentError: argument 1: <class 'TypeError'>: wrong type
A memoryview
supports the Python buffer protocol, so create a ctypes
array of the appropriate size using its from_buffer
method, which won't make a copy but reference the same memory.
Modifying your example slightly to see the buffer change:
silly.c:
#include <stdint.h>
#include <stdio.h>
#ifdef _WIN32
# define API __declspec(dllexport)
#else
# define API
#endif
API void set_image(unsigned char* data, uint32_t xsize, uint32_t ysize)
{
printf("%p %u %u\n",data,xsize,ysize);
*data = 123;
}
test.py:
import ctypes
from PySide2.QtGui import QImage
img = QImage(500,100, QImage.Format.Format_RGB32 )
data = img.bits()
print('original:',data[0])
dll = ctypes.CDLL('./silly')
dll_set_image = dll.set_image
dll_set_image.argtypes = ctypes.c_void_p, ctypes.c_uint32, ctypes.c_uint32
buffer = (ctypes.c_ubyte * len(data)).from_buffer(data)
dll_set_image(buffer, img.width(), img.height())
print('final:',data[0])
Output:
original: 80
00000213CCF3C080 500 100
final: 123