TypeError: initializer for ctype 'unsigned int *' must be a cdata pointer, not bytes
TypeError: initializer for ctype 'unsigned int *' must be a cdata pointer, not bytes
我尝试将 PIL 图像转换为 leptonica PIX。这是我的代码 python 3.6:
import os, cffi
from PIL import Image
# initialize leptonica
ffi = cffi.FFI()
ffi.cdef("""
typedef int l_int32;
typedef unsigned int l_uint32;
struct Pix;
typedef struct Pix PIX;
PIX * pixCreate (int width, int height, int depth);
l_int32 pixSetData (PIX *pix, l_uint32 *data);
""")
leptonica = ffi.dlopen(os.path.join(os.getcwd(), "leptonica-1.78.0.dll"))
# convert PIL to PIX
im = Image.open("test.png").convert("RGBA")
depth = 32
width, height = im.size
data = im.tobytes("raw", "RGBA")
pixs = leptonica.pixCreate(width, height, depth)
leptonica.pixSetData(pixs, data)
pixSetData
失败并显示消息:TypeError: initializer for ctype 'unsigned int *' must be a cdata pointer, not bytes
。
如何将 bytes 对象 (data
) 转换为 cdata 指针?
我从Armin Rigo at python-cffi forum那里得到了答案:
Assuming you have the recent cffi 1.12, you can do:
leptonica.pixSetData(pixs, ffi.from_buffer("l_uint32[]", data))
The backward-compatible way is more complicated because we need to
make sure an intermediate object stays alive:
p = ffi.from_buffer(data)
leptonica.pixSetData(pixs, ffi.cast("l_uint32 *", p))
# 'p' must still be alive here after the call, so put it in a variable above!
PIL 和 Leptonica 似乎不共享完全相同的原始格式。最后是 RGBA vs. ABGR。对我有用的是使用未压缩的 TIFF 作为快速可靠的数据交换格式。
# Add these to ffi.cdef():
#
# typedef unsigned char l_uint8;
# PIX * pixReadMem(const l_uint8 *data, size_t size);
# l_ok pixWriteMem(l_uint8 **pdata, size_t *psize, PIX *pix, l_int32 format);
from io import BytesIO
import PIL.Image
IFF_TIFF = 4
def img_pil_to_lepto(pilimage):
with BytesIO() as bytesio:
pilimage.save(bytesio, 'TIFF')
tiff_bytes = bytesio.getvalue()
cdata = ffi.from_buffer('l_uint8[]', tiff_bytes)
pix = leptonica.pixReadMem(cdata, len(tiff_bytes))
return pix
def img_lepto_to_pil(pix):
cdata_ptr = ffi.new('l_uint8**')
size_ptr = ffi.new('size_t*')
leptonica.pixWriteMem(cdata_ptr, size_ptr, pix, IFF_TIFF)
cdata = cdata_ptr[0]
size = size_ptr[0]
tiff_bytes = bytes(ffi.buffer(cdata, size))
with BytesIO(tiff_bytes) as bytesio:
pilimage = PIL.Image.open(bytesio).copy()
return pilimage
我尝试将 PIL 图像转换为 leptonica PIX。这是我的代码 python 3.6:
import os, cffi
from PIL import Image
# initialize leptonica
ffi = cffi.FFI()
ffi.cdef("""
typedef int l_int32;
typedef unsigned int l_uint32;
struct Pix;
typedef struct Pix PIX;
PIX * pixCreate (int width, int height, int depth);
l_int32 pixSetData (PIX *pix, l_uint32 *data);
""")
leptonica = ffi.dlopen(os.path.join(os.getcwd(), "leptonica-1.78.0.dll"))
# convert PIL to PIX
im = Image.open("test.png").convert("RGBA")
depth = 32
width, height = im.size
data = im.tobytes("raw", "RGBA")
pixs = leptonica.pixCreate(width, height, depth)
leptonica.pixSetData(pixs, data)
pixSetData
失败并显示消息:TypeError: initializer for ctype 'unsigned int *' must be a cdata pointer, not bytes
。
如何将 bytes 对象 (data
) 转换为 cdata 指针?
我从Armin Rigo at python-cffi forum那里得到了答案:
Assuming you have the recent cffi 1.12, you can do:
leptonica.pixSetData(pixs, ffi.from_buffer("l_uint32[]", data))
The backward-compatible way is more complicated because we need to make sure an intermediate object stays alive:
p = ffi.from_buffer(data) leptonica.pixSetData(pixs, ffi.cast("l_uint32 *", p)) # 'p' must still be alive here after the call, so put it in a variable above!
PIL 和 Leptonica 似乎不共享完全相同的原始格式。最后是 RGBA vs. ABGR。对我有用的是使用未压缩的 TIFF 作为快速可靠的数据交换格式。
# Add these to ffi.cdef():
#
# typedef unsigned char l_uint8;
# PIX * pixReadMem(const l_uint8 *data, size_t size);
# l_ok pixWriteMem(l_uint8 **pdata, size_t *psize, PIX *pix, l_int32 format);
from io import BytesIO
import PIL.Image
IFF_TIFF = 4
def img_pil_to_lepto(pilimage):
with BytesIO() as bytesio:
pilimage.save(bytesio, 'TIFF')
tiff_bytes = bytesio.getvalue()
cdata = ffi.from_buffer('l_uint8[]', tiff_bytes)
pix = leptonica.pixReadMem(cdata, len(tiff_bytes))
return pix
def img_lepto_to_pil(pix):
cdata_ptr = ffi.new('l_uint8**')
size_ptr = ffi.new('size_t*')
leptonica.pixWriteMem(cdata_ptr, size_ptr, pix, IFF_TIFF)
cdata = cdata_ptr[0]
size = size_ptr[0]
tiff_bytes = bytes(ffi.buffer(cdata, size))
with BytesIO(tiff_bytes) as bytesio:
pilimage = PIL.Image.open(bytesio).copy()
return pilimage