There are libraries dedicated to the task of generating SVG (Simple Vector Graphics) from Lisp. Namely the cl-svg. But they might offer a limited subset of the SVG standard.

Since SVG is an application of XML and XML is closely related to both SGML and HTML/XHTML one could suggest that it might be possible to use standard full-featured HTML-generators. Indeed, it is, and here is how.

CL-WHO of Edi Weitz actually transforms a tree of S-exp into a sequence of commands that ouput the corresponding XML/SGML into the given stream. And this is exactly what is needed to produce SVG from Lisp!

Let’s define a stream where the SVG data will be serialized:

(defparameter *svg* *standard-output*)

Now let’s define a macro that will tune CL-WHO to do the job we want it to do:

( defmacro with-svg ( &body body) `( progn (format *svg* "<?xml version=\"1.0\" standalone=\"yes\"? > ~%~%" ) ( who:with-html-output (*svg* nil :prologue "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">" :indent T) ,@body)))

Here we print an XML declaration because CL-WHO does not and we ask it to use prologue that is required by SVG. Indentation is optional and is useful for debugging purposes.

The with-svg macro is designed to envelope chunks of SVG code. Let’s translate this example for this macro:

( with-open-file (*svg* "out.svg" :direction :output :if-exists :supersede :if-does-not-exist :create ) ( with-svg ( :svg :width "4in" :height "3in" :version "1.1" :xmlns "http://www.w3.org/2000/svg" :|xmlns:xlink| "http://www.w3.org/1999/xlink" ( :desc "This graphic links to an external image" ) ( :image :x "200" :y "200" :width "100px" :height "100px" :|xlink:href| "myimage.png" ( :title "My image" )))))

And don’t forget that empty tags are defined by the who:*html-empty-tags* list.

One last note is that this very approach is suitable for generating arbitrary XML with a truly universal tool that is CL-WHO.