Python ctypes和librsvg出错
我试图用Python的ctypes包装librsvg的基本函数,但我遇到了一个错误 C: Python类型:Python ctypes和librsvg出错,python,ctypes,cairo,pycairo,librsvg,Python,Ctypes,Cairo,Pycairo,Librsvg,我试图用Python的ctypes包装librsvg的基本函数,但我遇到了一个错误 C: Python类型: from ctypes import * from ctypes import util librsvg = cdll.LoadLibrary('/brew/lib/librsvg-2.2.dylib') libgobject = cdll.LoadLibrary('/brew/lib/libgobject-2.0.dylib') libgobject.g_type_init()
from ctypes import *
from ctypes import util
librsvg = cdll.LoadLibrary('/brew/lib/librsvg-2.2.dylib')
libgobject = cdll.LoadLibrary('/brew/lib/libgobject-2.0.dylib')
libgobject.g_type_init()
class RSVGDimensionData(Structure):
_fields_ = (
('width', c_int),
('height', c_int),
('em', c_double),
('ex', c_double)
)
class PycairoContext(Structure):
_fields_ = (
('PyObject_HEAD', c_byte * object.__basicsize__),
('ctx', c_void_p),
('base', c_void_p)
)
class RSVGHandle(object):
def __init__(self, path):
self.path = path
self.error = ''
self.handle = librsvg.rsvg_handle_new_from_file(self.path, self.error)
def render_cairo(self, context):
context.save()
z = PycairoContext.from_address(id(context))
librsvg.rsvg_handle_render_cairo(self.handle, z.ctx)
context.restore()
import cairo
h = RSVGHandle('bank.svg')
s = cairo.ImageSurface(cairo.FORMAT_ARGB32, 100, 100)
ctx = cairo.Context(s)
# segmentation fault....
h.render_cairo(ctx)
此行中出现错误:librsvg.rsvg\u handle\u render\u cairo(self.handle,z.ctx)
你知道这有什么问题吗?librsvg.rsvg\u handle\u render\u cairo需要指针,而需要整数。不确定这里的整个故事,但这个修改至少没有错 试试这个
librsvg.rsvg_handle_render_cairo(c_void_p(self.handle), c_void_p(z.ctx))
注意,我将这两个参数包装在c_void_p中,使它们成为void*指针。不理想,但它似乎有效。问题是返回类型的规范没有定义;仅对结果使用
c\u void\u p
不足以解决这种情况下的问题。你需要把
librsvg.rsvg_handle_new_from_file.restype = c_void_p
在适当的地方。然后它(也)在OSX中以32位或64位工作
但我发现,为了处理从文件创建句柄时可能出现的错误,增加基本包装更有帮助。下面是一个基本的包装器。它还以几乎相同的方式复制了标准rsvg
绑定的基本用法
from ctypes import CDLL, POINTER, Structure, byref, util
from ctypes import c_bool, c_byte, c_void_p, c_int, c_double, c_uint32, c_char_p
class _PycairoContext(Structure):
_fields_ = [("PyObject_HEAD", c_byte * object.__basicsize__),
("ctx", c_void_p),
("base", c_void_p)]
class _RsvgProps(Structure):
_fields_ = [("width", c_int), ("height", c_int),
("em", c_double), ("ex", c_double)]
class _GError(Structure):
_fields_ = [("domain", c_uint32), ("code", c_int), ("message", c_char_p)]
def _load_rsvg(rsvg_lib_path=None, gobject_lib_path=None):
if rsvg_lib_path is None:
rsvg_lib_path = util.find_library('rsvg-2')
if gobject_lib_path is None:
gobject_lib_path = util.find_library('gobject-2.0')
l = CDLL(rsvg_lib_path)
g = CDLL(gobject_lib_path)
g.g_type_init()
l.rsvg_handle_new_from_file.argtypes = [c_char_p, POINTER(POINTER(_GError))]
l.rsvg_handle_new_from_file.restype = c_void_p
l.rsvg_handle_render_cairo.argtypes = [c_void_p, c_void_p]
l.rsvg_handle_render_cairo.restype = c_bool
l.rsvg_handle_get_dimensions.argtypes = [c_void_p, POINTER(_RsvgProps)]
return l
_librsvg = _load_rsvg()
class Handle(object):
def __init__(self, path):
lib = _librsvg
err = POINTER(_GError)()
self.handle = lib.rsvg_handle_new_from_file(path.encode(), byref(err))
if self.handle is None:
gerr = err.contents
raise Exception(gerr.message)
self.props = _RsvgProps()
lib.rsvg_handle_get_dimensions(self.handle, byref(self.props))
def render_cairo(self, ctx):
"""Returns True is drawing succeeded."""
z = _PycairoContext.from_address(id(ctx))
return _librsvg.rsvg_handle_render_cairo(self.handle, z.ctx)
示例用法见。它非常适合我。这仅仅是一条SEGFULT消息,还是您实际上在控制台上打印了任何有用的信息?我怀疑您使用的librsvg C库版本有问题。我正在使用librsvg-2.so.2.34.0和libgobject-2.0.so.0.2800.8我还注意到您似乎在使用苹果Mac,我正在运行Gentoo linux amd64。这可能会给我们一个线索,到底发生了什么?这可能是Mac特有的问题。您可以尝试更新到librsvg-2.34.0或更高版本,看看是否有效。如果更高版本不适合您,请提交一个特定于Mac的bug,然后尝试使用早期版本。如果这些都不起作用,那么您可以尝试从开发人员librsvg使用的存储库中获取最新版本。@ahojnnes这不是一个bug,包装只是不小心完成的。需要指定
restype
,仅对结果使用c\u void\u p
是不够的。请参阅另一个答案(如果您碰巧在某个时候再次访问过),作为OSX的即时解决方案,在32位以下运行代码应该可以“解决”这个问题arch-i386 python x.py
我会在听到有人成功使用此方法后立即对此进行更新,否则我无法验证这一点,因为我不是OSXuser@JamesHurford这有点矛盾,因为我自己也用过。所以你已经“听到”有人说它成功了。是的,你可能是对的。当我读到答案时,我的时间不够,所以我向你道歉。请投我一票。很高兴听到有人解决了这个问题,正如我之前所说,我试图在OS X上运行一个依赖于pyrsvg的脚本(),首先我尝试安装gnome python desktop或类似的东西,只是为了得到它,但我很快发现这是一件非常困难的事情。使用代码要简单得多。非常感谢。我刚刚用Python3.5在OSX10.11上测试了这段代码,效果非常好。问题确实是在rsvg\u handle\u new\u from\u file
和rsvg\u handle\u render\u cairo
函数上都缺少正确的类型声明。谢谢@mmgp。省去了我很多麻烦。
from ctypes import CDLL, POINTER, Structure, byref, util
from ctypes import c_bool, c_byte, c_void_p, c_int, c_double, c_uint32, c_char_p
class _PycairoContext(Structure):
_fields_ = [("PyObject_HEAD", c_byte * object.__basicsize__),
("ctx", c_void_p),
("base", c_void_p)]
class _RsvgProps(Structure):
_fields_ = [("width", c_int), ("height", c_int),
("em", c_double), ("ex", c_double)]
class _GError(Structure):
_fields_ = [("domain", c_uint32), ("code", c_int), ("message", c_char_p)]
def _load_rsvg(rsvg_lib_path=None, gobject_lib_path=None):
if rsvg_lib_path is None:
rsvg_lib_path = util.find_library('rsvg-2')
if gobject_lib_path is None:
gobject_lib_path = util.find_library('gobject-2.0')
l = CDLL(rsvg_lib_path)
g = CDLL(gobject_lib_path)
g.g_type_init()
l.rsvg_handle_new_from_file.argtypes = [c_char_p, POINTER(POINTER(_GError))]
l.rsvg_handle_new_from_file.restype = c_void_p
l.rsvg_handle_render_cairo.argtypes = [c_void_p, c_void_p]
l.rsvg_handle_render_cairo.restype = c_bool
l.rsvg_handle_get_dimensions.argtypes = [c_void_p, POINTER(_RsvgProps)]
return l
_librsvg = _load_rsvg()
class Handle(object):
def __init__(self, path):
lib = _librsvg
err = POINTER(_GError)()
self.handle = lib.rsvg_handle_new_from_file(path.encode(), byref(err))
if self.handle is None:
gerr = err.contents
raise Exception(gerr.message)
self.props = _RsvgProps()
lib.rsvg_handle_get_dimensions(self.handle, byref(self.props))
def render_cairo(self, ctx):
"""Returns True is drawing succeeded."""
z = _PycairoContext.from_address(id(ctx))
return _librsvg.rsvg_handle_render_cairo(self.handle, z.ctx)