#309: The `graphviz` extension can now output SVG instead of PNG

images, controlled by the ``graphviz_output_format`` config value.
Patch by Henrique Bastos.
This commit is contained in:
Georg Brandl 2010-01-02 21:38:27 +01:00
parent 82fa1f3cfe
commit d32bd22ae7
4 changed files with 76 additions and 20 deletions

View File

@ -5,6 +5,7 @@ Substantial parts of the templates were written by Armin Ronacher
Other contributors, listed alphabetically, are:
* Henrique Bastos -- SVG support for graphviz extension
* Daniel Bültmann -- todo extension
* Michael Droettboom -- inheritance_diagram extension
* Charles Duffy -- original graphviz extension

View File

@ -3,6 +3,9 @@ Release 1.0 (in development)
* Added Epub builder.
* #309: The ``graphviz`` extension can now output SVG instead of PNG
images, controlled by the ``graphviz_output_format`` config value.
* #284: All docinfo metadata is now put into the document metadata, not
just the author.

View File

@ -25,8 +25,9 @@ It adds these directives:
"bar" -> "baz";
}
In HTML output, the code will be rendered to a PNG image. In LaTeX output,
the code will be rendered to an embeddable PDF file.
In HTML output, the code will be rendered to a PNG or SVG image (see
:confval:`graphviz_output_format`). In LaTeX output, the code will be
rendered to an embeddable PDF file.
.. directive:: graph
@ -75,3 +76,11 @@ There are also these new config values:
Additional command-line arguments to give to dot, as a list. The default is
an empty list. This is the right place to set global graph, node or edge
attributes via dot's ``-G``, ``-N`` and ``-E`` options.
.. confval:: graphviz_output_format
The output format for Graphviz when building HTML files. This must be either
``'png'`` or ``'svg'``; the default is ``'png'``.
.. versionadded:: 1.0
Previously, output always was PNG.

View File

@ -13,6 +13,7 @@
import re
import posixpath
from os import path
from math import ceil
from subprocess import Popen, PIPE
try:
from hashlib import sha1 as sha
@ -27,6 +28,7 @@ from sphinx.util.compat import Directive
mapname_re = re.compile(r'<map id="(.*?)"')
svg_dim_re = re.compile(r'<svg\swidth="(\d+)pt"\sheight="(\d+)pt"', re.M)
class GraphvizError(SphinxError):
@ -128,9 +130,44 @@ def render_dot(self, code, options, format, prefix='graphviz'):
return relfn, outfn
def render_dot_html(self, node, code, options, prefix='graphviz', imgcls=None):
def get_svg_tag(svgref, svgfile, imgcls=None):
# Webkit can't figure out svg dimensions when using object tag
# so we need to get it from the svg file
fp = open(svgfile, 'r')
try:
fname, outfn = render_dot(self, code, options, 'png', prefix)
for line in fp:
match = svg_dim_re.match(line)
if match:
dimensions = match.groups()
break
else:
dimensions = None
finally:
fp.close()
# We need this hack to make WebKit show our object tag properly
def pt2px(x):
return int(ceil((96.0/72.0) * float(x)))
if dimensions:
style = ' width="%s" height="%s"' % tuple(map(pt2px, dimensions))
else:
style = ''
# The object tag works fine on Firefox and WebKit
# Besides it's a hack, this strategy does not mess with templates.
imgcss = imgcls and ' class="%s"' % imgcls or ''
return '<object type="image/svg+xml" data="%s"%s%s/>\n' % \
(svgref, imgcss, style)
def render_dot_html(self, node, code, options, prefix='graphviz', imgcls=None):
format = self.builder.config.graphviz_output_format
try:
if format not in ('png', 'svg'):
raise GraphvizError("graphviz_output_format must be one of 'png', "
"'svg', but is %r" % format)
fname, outfn = render_dot(self, code, options, format, prefix)
except GraphvizError, exc:
self.builder.warn('dot code %r: ' % code + str(exc))
raise nodes.SkipNode
@ -138,6 +175,10 @@ def render_dot_html(self, node, code, options, prefix='graphviz', imgcls=None):
self.body.append(self.starttag(node, 'p', CLASS='graphviz'))
if fname is None:
self.body.append(self.encode(code))
else:
if format == 'svg':
svgtag = get_svg_tag(fname, outfn, imgcls)
self.body.append(svgtag)
else:
mapfile = open(outfn + '.map', 'rb')
try:
@ -156,6 +197,7 @@ def render_dot_html(self, node, code, options, prefix='graphviz', imgcls=None):
(fname, self.encode(code).strip(),
mapname, imgcss))
self.body.extend(imgmap)
self.body.append('</p>\n')
raise nodes.SkipNode
@ -188,3 +230,4 @@ def setup(app):
app.add_directive('digraph', GraphvizSimple)
app.add_config_value('graphviz_dot', 'dot', 'html')
app.add_config_value('graphviz_dot_args', [], 'html')
app.add_config_value('graphviz_output_format', 'png', 'html')