2011-05-26 39 views
4

我试图用ctypes为Python包装librsvg的基本功能,但我得到一个段错误。错误与Python ctypes和librsvg

C:

// pycairo excerpt 
typedef struct { 
    PyObject_HEAD 
    cairo_t *ctx; 
    PyObject *base; /* base object used to create context, or NULL */ 
} PycairoContext; 

// librsvg excerpt 
RsvgHandle * rsvg_handle_new_from_file (const gchar * file_name, GError ** error); 
// ... 
gboolean rsvg_handle_render_cairo (RsvgHandle * handle, cairo_t * cr); 

的Python的ctypes:

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_handle_render_cairo(self.handle, z.ctx)

什么不对的任何想法?

+1

作为OSX的直接解决方案,在32位以下运行代码应该“解决”问题。 'arch -i386 python x.py' – mmgp 2013-02-18 04:26:37

回答

3

librsvg.rsvg_handle_render_cairo需要指针,而不是整数。不知道整个故事在这里,但这种修改至少不会segfault。

试试这个

librsvg.rsvg_handle_render_cairo(c_void_p(self.handle), c_void_p(z.ctx)) 

通知我裹在c_void_p两个参数,使它们成为void *指针。不理想,但它似乎工作。

+0

hm,我仍然收到段错误... – 2011-07-08 14:02:28

+0

它对我来说非常合适。它只是一个段错误消息,或者你真的获得了印在控制台上的任何有用信息吗?我怀疑你使用的librsvg C库版本有问题。 – 2011-07-08 23:45:01

+1

我正在使用librsvg-2.so.2.34.0和libgobject-2.0.so.0.2800.8 – 2011-07-08 23:59:26

5

问题是没有定义返回类型的规范;仅仅使用c_void_p就不足以解决这种情况下的问题。你需要把

librsvg.rsvg_handle_new_from_file.restype = c_void_p 

在一个适当的地方。然后它也(也)在32位或64位OSX中工作。

但我发现更多有用的补充基本包装,以处理从文件创建句柄时可能出现的错误。以下是一个基本的包装,这样做。它也以基本相同的方式复制标准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, 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) 

示例用法请参见https://stackoverflow.com/a/14928770/1832154

+0

我会尽快听到有人使用这种方法成功了,否则我不能验证这一点,不是一个OSX用户 – 2013-02-18 21:50:38

+0

@JamesHurford这有点矛盾,因为我自己使用它。所以你已经“听到”有人说它成功了。 – mmgp 2013-02-19 00:38:21

+0

是的,你可能是对的。当我读到答案时,我的时间很短,所以我很抱歉。对我赞不绝口。很高兴听到有人解决了这个问题,正如我前面所说 – 2013-02-19 06:01:19