Can't use image() with SVG library

Processing throws a NullPointerException when I try to output an image to SVG while using image(). Looks like this is a known issue from 2017. There’s an answer there but like the poster, I don’t know how to implement it in the context of Processing.

Here’s a python sketch you can use to see the bug for yourself. If you remove beginRecord() and endRecord() it works fine:

add_library('svg')

def setup():
    size(1000,1000)

def draw():
    beginRecord(SVG, "svgtest.svg")
    
    thisPGraphicsObject = createGraphics(width, height)

    thisPGraphicsObject.beginDraw()
    thisPGraphicsObject.fill(50)
    thisPGraphicsObject.stroke(80)
    thisPGraphicsObject.ellipse(width/2, height/2, 500, 500)
    thisPGraphicsObject.endDraw()
    image(thisPGraphicsObject, 0, 0)
    
    endRecord()

NullPointerException
at org.apache.batik.svggen.ImageHandlerBase64Encoder.encodeImage(Unknown Source)
at org.apache.batik.svggen.ImageHandlerBase64Encoder.handleHREF(Unknown Source)
at org.apache.batik.svggen.ImageHandlerBase64Encoder.handleHREF(Unknown Source)
at org.apache.batik.svggen.DefaultImageHandler.handleImage(Unknown Source)
at org.apache.batik.svggen.SimpleImageHandler.handleImage(Unknown Source)
at org.apache.batik.svggen.SVGGraphics2D.drawImage(Unknown Source)
at org.apache.batik.ext.awt.g2d.AbstractGraphics2D.drawImage(Unknown Source)
at processing.awt.PGraphicsJava2D.imageImpl(PGraphicsJava2D.java:1622)
at processing.core.PGraphics.image(PGraphics.java:3817)
at processing.core.PApplet.image(PApplet.java:12805)
at sun.reflect.GeneratedMethodAccessor57.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.python.core.PyReflectedFunction.call(PyReflectedFunction.java:188)
at org.python.core.PyReflectedFunction.call(PyReflectedFunction.java:206)
at org.python.core.PyObject.call(PyObject.java:534)
at org.python.core.PyObject.call(PyObject.java:540)
at org.python.core.PyMethod.call(PyMethod.java:171)
at org.python.pycode._pyx251.draw$2(star_generator_2.pyde:129)
at org.python.pycode._pyx251.call_function(star_generator_2.pyde)
at org.python.core.PyTableCode.call(PyTableCode.java:171)
at org.python.core.PyBaseCode.call(PyBaseCode.java:125)
at org.python.core.PyFunction.call(PyFunction.java:403)
at org.python.core.PyFunction.call(PyFunction.java:398)
at jycessing.PAppletJythonDriver.draw(PAppletJythonDriver.java:1370)
at processing.core.PApplet.handleDraw(PApplet.java:2475)
at processing.opengl.PSurfaceJOGL$DrawListener.display(PSurfaceJOGL.java:866)
at jogamp.opengl.GLDrawableHelper.displayImpl(GLDrawableHelper.java:692)
at jogamp.opengl.GLDrawableHelper.display(GLDrawableHelper.java:674)
at jogamp.opengl.GLAutoDrawableBase$2.run(GLAutoDrawableBase.java:443)
at jogamp.opengl.GLDrawableHelper.invokeGLImpl(GLDrawableHelper.java:1293)
at jogamp.opengl.GLDrawableHelper.invokeGL(GLDrawableHelper.java:1147)
at com.jogamp.newt.opengl.GLWindow.display(GLWindow.java:759)
at com.jogamp.opengl.util.AWTAnimatorImpl.display(AWTAnimatorImpl.java:81)
at com.jogamp.opengl.util.AnimatorBase.display(AnimatorBase.java:452)
at com.jogamp.opengl.util.FPSAnimator$MainTask.run(FPSAnimator.java:178)
at java.util.TimerThread.mainLoop(Timer.java:555)
at java.util.TimerThread.run(Timer.java:505)

Okay, this solution is kinda hacky –

SVG is a markup-based language, so perhaps you put in some sort of ‘placeholder’ shape, then open the SVG with any code/text editor and replace the placeholder code with an <image> tag?

For example, run this code, then open the SVG and follow the Console output instructions:

add_library('svg')

size(1000,1000)

beginRecord(SVG, 'svgtest.svg')
fill(50)
stroke(80)
ellipse(width/2, height/2, 500, 500)

fill('#FF0000')
noStroke()
x=10; y=10; w=200; h=200
rect(x, y, w, h)

print('open the svg in a code editor and replace this:')
print('<rect x="%s" y="%s" width="%s" style="fill:red; stroke:none;" height="%s"' % (x,y,w,h) )
print('with is:')
print('<image xlink:href="img.png" x="%s" y="%s" width="%s" height="%s"' % (x,y,w,h) )

endRecord()

Of course, you’ll need to replace the xlink:href="img.png" attribute with the relevant image path/filename.

You could even take this a step further and include some Python code – after the endRecord() – that does the find-replace job automatically. Somebody else may have a better solution, but hopefully, that helps you for now.