[RFC PATCH v2] docs-rst: automatically convert Graphviz and SVG images

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Replacement for the sphinx ``figure`` and ``images`` directive.

A image (or figure) directive which make use of the *glob* notation::

  .. figure::  hello.*

will be converted automatically with the tool chains listed below.:

* DOT to SVG: ``DOT(1)`` (http://www.graphviz.org) If graphviz is not
  available, the DOT language is inserted as literal-include.

* SVG to PDF:

  * CairoSVG (http://cairosvg.org) if installed or alternatively
  * ``convert(1)``: ImageMagick (https://www.imagemagick.org)

Signed-off-by: Markus Heiser <markus.heiser@xxxxxxxxxxx>
---
 Documentation/conf.py              |   2 +-
 Documentation/doc-guide/hello.dot  |   3 +
 Documentation/doc-guide/sphinx.rst |  18 ++++++
 Documentation/sphinx/figure.py     | 123 +++++++++++++++++++++++++++++++++++++
 4 files changed, 145 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/doc-guide/hello.dot
 create mode 100644 Documentation/sphinx/figure.py

diff --git a/Documentation/conf.py b/Documentation/conf.py
index 1ac958c..386d792 100644
--- a/Documentation/conf.py
+++ b/Documentation/conf.py
@@ -34,7 +34,7 @@ from load_config import loadConfig
 # Add any Sphinx extension module names here, as strings. They can be
 # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
 # ones.
-extensions = ['kerneldoc', 'rstFlatTable', 'kernel_include', 'cdomain']
+extensions = ['kerneldoc', 'rstFlatTable', 'kernel_include', 'cdomain', 'figure']
 
 # The name of the math extension changed on Sphinx 1.4
 if major == 1 and minor > 3:
diff --git a/Documentation/doc-guide/hello.dot b/Documentation/doc-guide/hello.dot
new file mode 100644
index 0000000..504621d
--- /dev/null
+++ b/Documentation/doc-guide/hello.dot
@@ -0,0 +1,3 @@
+graph G {
+      Hello -- World
+}
diff --git a/Documentation/doc-guide/sphinx.rst b/Documentation/doc-guide/sphinx.rst
index 96fe7ccb..6f8fdd1 100644
--- a/Documentation/doc-guide/sphinx.rst
+++ b/Documentation/doc-guide/sphinx.rst
@@ -217,3 +217,21 @@ Rendered as:
       * .. _`last row`:
 
         - column 3
+
+Figures
+=======
+
+If you want to add an image on either Graphviz or SVG format, you should
+use Sphinx ``figure``, where the name of the image file should end with
+``.*``, like::
+
+  .. figure::  hello.*
+     :alt:    hello world
+
+     DOT's hello world example
+
+
+.. figure::  hello.*
+   :alt:    hello world
+
+   DOT's hello world example
diff --git a/Documentation/sphinx/figure.py b/Documentation/sphinx/figure.py
new file mode 100644
index 0000000..50d63bd
--- /dev/null
+++ b/Documentation/sphinx/figure.py
@@ -0,0 +1,123 @@
+# -*- coding: utf-8; mode: python -*-
+# pylint: disable=W0141,C0113,C0103,C0325
+u"""
+    images
+    ~~~~~~
+
+    Replacement for the sphinx ``figure`` and ``images`` directive.
+
+    :copyright:  Copyright (C) 2016  Markus Heiser
+    :license:    GPL Version 2, June 1991 see Linux/COPYING for details.
+
+    List of customizations:
+
+    * generate PDF from SVG
+
+    * generate SVG / PDF from DOT files, see
+      http://www.graphviz.org/content/dot-language
+
+    A image (or figure) directive which make use of the *glob* notation will be
+    converted automatically with the tool chains listed below.:
+
+    * DOT to SVG: ``DOT(1)`` (http://www.graphviz.org) If graphviz is not
+      available, the DOT language is inserted as literal-include.
+
+    * SVG to PDF:
+
+      * CairoSVG (http://cairosvg.org) if installed or alternatively
+      * ``convert(1)``: ImageMagick (https://www.imagemagick.org)
+"""
+
+import os
+from glob import glob
+import subprocess
+
+from docutils import nodes
+from docutils.parsers.rst import directives
+from docutils.parsers.rst.directives import images
+
+from sphinx.directives import patches
+
+try:
+    import cairosvg
+except ImportError:
+    cairosvg = None
+
+def cmd_exists(cmd):
+    exit_code = subprocess.call(
+        "type " + cmd, shell = True,
+        stdout = subprocess.PIPE, stderr = subprocess.PIPE )
+    return bool(exit_code == 0)
+
+convert_exists = cmd_exists('convert')
+dot_exists = cmd_exists('dot')
+
+def setup(app):  # pylint: disable=W0613
+    directives.register_directive('figure', Figure)
+    directives.register_directive('image', Image)
+
+def asterix_conversions(folder, node):
+    if not node['uri'].endswith('.*'):
+        return node
+    name = folder + os.path.sep + os.path.splitext(node['uri'])[0]
+
+    fnames = glob(name + '.*')
+    if (name + '.dot' in fnames):
+        if not dot_exists:
+            with open(name + '.dot', "r") as dot:
+                data = dot.read()
+                node = nodes.literal_block(data, data)
+        else:
+            dot2svg(name)
+
+    fnames = glob(name + '.*')
+    if (name + '.svg' in fnames):
+        svg2pdf(name)
+    return node
+
+
+def dot2svg(fname):
+    cmd = "dot -Tsvg %s.dot" % fname
+    with open(fname + '.svg', "w") as svg:
+        exit_code = subprocess.call(
+            cmd, shell = True,
+            stdout = svg,
+            stderr = subprocess.PIPE )
+        svg.flush()
+    return bool(exit_code == 0)
+
+def svg2pdf(fname):
+
+    if cairosvg:
+        cairosvg.svg2pdf(url = fname + '.svg', write_to = fname + '.pdf')
+        return True
+
+    if convert_exists:
+        cmd = "convert %s.svg %s.pdf" % (fname, fname)
+        exit_code = subprocess.call(
+            cmd, shell = True,
+            stdout = subprocess.PIPE, stderr = subprocess.PIPE )
+        return bool(exit_code == 0)
+
+    return False
+
+class Image(images.Image):
+
+    def run(self):
+        result = images.Image.run(self)
+        if len(result) == 2 or isinstance(result[0], nodes.system_message):
+            return result
+        folder = os.path.dirname(self.state.document.current_source)
+        result[0] = asterix_conversions(folder, result[0])
+        return result
+
+class Figure(patches.Figure):
+
+    def run(self):
+        result = patches.Figure.run(self)
+        if len(result) == 2 or isinstance(result[0], nodes.system_message):
+            return result
+        folder = os.path.dirname(self.state.document.current_source)
+        result[0][0] = asterix_conversions(folder, result[0][0])
+        return result
+
-- 
2.7.4

--
To unsubscribe from this list: send the line "unsubscribe linux-doc" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Linux FS]     [Yosemite Forum]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]     [Linux Resources]

  Powered by Linux