4

librsvg の基本機能を Python の ctypes でラップしようとしていますが、segfault が発生します。

子:

// 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)

これの何が問題なのか、何か考えはありますか?

4

2 に答える 2

6

問題は、戻り値の型の仕様が定義されていないことです。その場合、結果だけを使用c_void_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)

使用例はhttps://stackoverflow.com/a/14928770/1832154で確認できます。

于 2013-02-18T18:36:42.787 に答える
3

librsvg.rsvg_handle_render_cairo はポインターを想定しており、代わりに整数を取得しています。ここでの話全体はわかりませんが、この変更は少なくとも segfault を起こしません。

これを試して

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

2 つのパラメーターを c_void_p でラップして、それらを void * ポインターにしたことに注意してください。理想的ではありませんが、うまくいくようです。

于 2011-07-08T12:00:58.797 に答える