summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorg Brandl <georg@python.org>2010-01-02 21:38:27 +0100
committerGeorg Brandl <georg@python.org>2010-01-02 21:38:27 +0100
commitb2ef99b6c2bc791466083ae05e38a22e0636b24e (patch)
treebef8759f86a3309cdbab87bec6705426222c85d4
parent33caddde6badc35681275902ac3e563e38e8b485 (diff)
downloadsphinx-b2ef99b6c2bc791466083ae05e38a22e0636b24e.tar.gz
#309: The ``graphviz`` extension can now output SVG instead of PNG
images, controlled by the ``graphviz_output_format`` config value. Patch by Henrique Bastos.
-rw-r--r--AUTHORS1
-rw-r--r--CHANGES3
-rw-r--r--doc/ext/graphviz.rst13
-rw-r--r--sphinx/ext/graphviz.py77
4 files changed, 75 insertions, 19 deletions
diff --git a/AUTHORS b/AUTHORS
index ebda4307..54f53db2 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -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
diff --git a/CHANGES b/CHANGES
index 3c03e89b..b56b6294 100644
--- a/CHANGES
+++ b/CHANGES
@@ -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.
diff --git a/doc/ext/graphviz.rst b/doc/ext/graphviz.rst
index d007bf25..64d2023b 100644
--- a/doc/ext/graphviz.rst
+++ b/doc/ext/graphviz.rst
@@ -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.
diff --git a/sphinx/ext/graphviz.py b/sphinx/ext/graphviz.py
index 05ec4ec1..509ea64a 100644
--- a/sphinx/ext/graphviz.py
+++ b/sphinx/ext/graphviz.py
@@ -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 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:
+ 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:
- fname, outfn = render_dot(self, code, options, 'png', prefix)
+ 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
@@ -139,23 +176,28 @@ def render_dot_html(self, node, code, options, prefix='graphviz', imgcls=None):
if fname is None:
self.body.append(self.encode(code))
else:
- mapfile = open(outfn + '.map', 'rb')
- try:
- imgmap = mapfile.readlines()
- finally:
- mapfile.close()
- imgcss = imgcls and 'class="%s"' % imgcls or ''
- if len(imgmap) == 2:
- # nothing in image map (the lines are <map> and </map>)
- self.body.append('<img src="%s" alt="%s" %s/>\n' %
- (fname, self.encode(code).strip(), imgcss))
+ if format == 'svg':
+ svgtag = get_svg_tag(fname, outfn, imgcls)
+ self.body.append(svgtag)
else:
- # has a map: get the name of the map and connect the parts
- mapname = mapname_re.match(imgmap[0]).group(1)
- self.body.append('<img src="%s" alt="%s" usemap="#%s" %s/>\n' %
- (fname, self.encode(code).strip(),
- mapname, imgcss))
- self.body.extend(imgmap)
+ mapfile = open(outfn + '.map', 'rb')
+ try:
+ imgmap = mapfile.readlines()
+ finally:
+ mapfile.close()
+ imgcss = imgcls and 'class="%s"' % imgcls or ''
+ if len(imgmap) == 2:
+ # nothing in image map (the lines are <map> and </map>)
+ self.body.append('<img src="%s" alt="%s" %s/>\n' %
+ (fname, self.encode(code).strip(), imgcss))
+ else:
+ # has a map: get the name of the map and connect the parts
+ mapname = mapname_re.match(imgmap[0]).group(1)
+ self.body.append('<img src="%s" alt="%s" usemap="#%s" %s/>\n' %
+ (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')