3

我使用 Cairo、OpenGL 和 rsvg 渲染了一个包含大量元素的巨大 SVG 文件。我通过 rsvg 在 cairo 表面绘制 svg 并创建一个 OpenGL 纹理来绘制它。一切都很好。现在我必须与来自 SVG 的元素进行交互。例如,我想通过坐标猜测一个元素。我想改变SVG中一些路径的背景。我认为在改变背景的情况下,我可以改变 SVG DOM 并以某种方式重新渲染 SVG 的一部分。但是在命中测试元素的情况下,我完全感到尴尬。

那么,是否有一些 python 库可以与 SVG 交互?是否可以继续使用 cairo 和 rsvg,我该如何自己实施?或者有没有更好的方法在 OpenGL 中渲染 SVG 并在 python 中与之交互?我想要的只是加载 SVG,操作它的 DOM 并渲染它

4

3 回答 3

2

我对 librsvg 了解不多,但它似乎自 2005 年以来没有更新,因此我倾向于推荐使用不同的实现。

如果您不依赖标准库之外的任何 Python 库,那么您可以将 Jython 与 Batik 一起使用。这允许您添加事件处理程序,以及在渲染后更改 DOM。

有关如何使用 Java 执行此操作的示例,请参阅此链接

这是 Jython 2.2.1 的快速移植(运行,但未经彻底测试):

from java.awt.event import WindowAdapter;
from java.awt.event import WindowEvent;

from javax.swing import JFrame;

from org.apache.batik.swing import JSVGCanvas;
from org.apache.batik.swing.svg import SVGLoadEventDispatcherAdapter;
from org.apache.batik.swing.svg import SVGLoadEventDispatcherEvent;
from org.apache.batik.script import Window;

from org.w3c.dom import Document;
from org.w3c.dom import Element;
from org.w3c.dom.events import Event;
from org.w3c.dom.events import EventListener;
from org.w3c.dom.events import EventTarget;

class SVGApplication :

    def __init__(self) :

        class MySVGLoadEventDispatcherAdapter(SVGLoadEventDispatcherAdapter):
            def svgLoadEventDispatcherListener(e):
                # At this time the document is available...
                self.document = self.canvas.getSVGDocument();
                # ...and the window object too.
                self.window = self.canvas.getUpdateManager().getScriptingEnvironment().createWindow();
                # Registers the listeners on the document
                # just before the SVGLoad event is
                # dispatched.
                registerListeners();
                # It is time to pack the frame.
                self.frame.pack();

        def windowAdapter(e): 
            # The canvas is ready to load the base document
            # now, from the AWT thread.
            self.canvas.setURI("doc.svg");

        self.frame = JFrame(windowOpened = windowAdapter, size=(800, 600));

        self.canvas = JSVGCanvas();
        # Forces the canvas to always be dynamic even if the current
        # document does not contain scripting or animation.
        self.canvas.setDocumentState(JSVGCanvas.ALWAYS_DYNAMIC);
        self.canvas.addSVGLoadEventDispatcherListener(MySVGLoadEventDispatcherAdapter()) ;

        self.frame.getContentPane().add(self.canvas);

        self.frame.show()

    def registerListeners(self) :
        # Gets an element from the loaded document.
        elt = self.document.getElementById("elt-id");
        t = elt;

        def eventHandler(e):
            print e, type(e)

            self.window.setTimeout(500,run = lambda : self.window.alert("Delayed Action invoked!"));
            #window.setInterval(Animation(), 50);

        # Adds a 'onload' listener
        t.addEventListener("SVGLoad", false, handleEvent = eventHandler );

        # Adds a 'onclick' listener
        t.addEventListener("click", false, handleEvent = eventHandler );



if __name__ == "__main__":
    SVGApplication();

运行:

jython -Dpython.path=/usr/share/java/batik-all.jar:/home/jacob/apps/batik-1.7/lib/xml-apis-ext.jar test.py
于 2010-08-17T19:49:11.217 回答
1

另一种方法是使用blender。它支持 svg 导入和使用 python 交互。我认为它不允许您在导入后编辑 dom。

于 2010-08-17T15:56:28.283 回答
0

我必须这样做(例如更改元素颜色),并且必须修改 rsvg 库,因为所有这些不错的功能都存在但它们被隐藏了。您必须创建一个新界面来链接到不错的功能。

于 2016-06-08T13:26:01.983 回答