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.
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
One last note is that this very approach is suitable for generating arbitrary XML with a truly universal tool that is CL-WHO.