Commits

Kirill Simonov committed 28c6cec

Converted from sphinxcontrib.texdiag extension in HTSQL repository.

Comments (0)

Files changed (14)

+syntax: glob
+*.pyc
+*.pyo
+*.orig
+.*.sw?
+*.html
+*.egg-info
+_build
+build
+dist
+sandbox
+Copyright (c) 2013, Prometheus Research, LLC
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+include README NEWS LICENSE demo/Makefile demo/conf.py demo/*.rst demo/*.tex
+
+List of Changes
+===============
+
+
+0.1 (2013-XX-XX)
+----------------
+
+* Initial release.
+
+
+****************************************************************
+  ``sphinxcontrib-teximage`` -- TeX Image extension for Sphinx
+****************************************************************
+
+Overview
+========
+
+``sphinxcontrib-teximage`` is an extension for generating diagrams
+from TeX documents and embedding them into Sphinx_ documents.
+
+For an example of a diagram this extension could produce, please see
+http://htsql.org/doc/overview.html#htsql-in-a-nutshell
+
+This extension is similar in scope to `sphinxcontrib-tikz`_ extension,
+but with different approach to input and options.
+
+This software is written by Kirill Simonov (`Prometheus Research, LLC`_)
+and released under BSD license.
+
+
+Prerequisites
+=============
+
+To convert a TeX document to a raster image, the extension uses the
+following executables::
+
+* ``pdflatex``
+* ``pdftoppm``
+* ``pnmcrop``
+* ``pnmtopng``
+
+On a Debian_ or `Debian-derived`_ system, they could be installed with::
+
+    # apt-get install texlive
+    # apt-get install poppler-utils
+    # apt-get install netpbm
+
+If you want to generate diagrams using TikZ_, install::
+
+    # apt-get install texlive-pictures
+
+
+Usage
+=====
+
+To enable this extension, add the following line to ``conf.py``::
+
+    extensions.append('sphinxcontrib.teximage')
+
+To render an image from a TeX document, use ``teximage`` directive::
+
+    .. teximage:: diagram.tex
+
+Place the file ``diagram.tex`` in the same directory.  It must contain
+a valid TeX/LaTeX document.  For example::
+
+    \documentclass{article}
+
+    \usepackage{tikz}
+    \pagestyle{empty}
+
+    \begin{document}
+
+    \begin{tikzpicture}
+    \node[draw] {Hello, World!};
+    \end{tikzpicture}
+
+    \end{document}
+
+
+Reference
+=========
+
+Directives
+----------
+
+``teximage``
+    Renders an image from a TeX document.
+
+    Options:
+
+    ``align``
+        Image alignment (``left``, ``center``, or ``right``)
+
+    ``alt``
+        Image alternative text.
+
+Configuration parameters
+------------------------
+
+``teximage_pdftex`` (default: ``pdflatex``)
+    Path to ``pdftex`` or ``pdflatex`` executable.
+
+``teximage_pdftoppm`` (default: ``pdftoppm``)
+    Path to ``pdftoppm`` executable.
+
+``teximage_pnmcrop`` (default: ``pnmcrop``)
+    Path to ``pnmcrop`` executable.
+
+``teximage_pnmtopng`` (default: ``pnmtopng``)
+    Path to ``pnmtopng`` executable.
+
+``teximage_texinputs`` (default: ``[]``)
+    List of directories where TeX searches for input files.
+
+``teximage_resolution`` (default: ``110``)
+    Image resolution, in DPI.
+
+CSS classes
+-----------
+
+``teximage``
+    Wraps the generated image.
+
+
+.. _Sphinx: http://sphinx-doc.org/
+.. _sphinxcontrib-tikz: https://pypi.python.org/pypi/sphinxcontrib-tikz
+.. _Prometheus Research, LLC: http://prometheusresearch.com/
+.. _Debian: http://debian.org/
+.. _Debian-derived: http://ubuntu.com/
+.. _TikZ: http://www.texample.net/tikz/
+
+.. vim: set spell spelllang=en textwidth=72:
+
+# You can set these variables from the command line.
+SPHINXBUILD   = sphinx-build
+BUILDDIR      = _build
+
+ifeq ($(shell $(SPHINXBUILD) 2> /dev/null; echo $$?), 127)
+define MSG
+
+
+The 'sphinx-build' command was not found. Make sure you have Sphinx
+installed, then set the SPHINXBUILD environment variable to point
+to the full path of the 'sphinx-build' executable. Alternatively you
+may add the Sphinx directory to PATH.
+
+If you don't have Sphinx installed, grab it from
+http://sphinx-doc.org/
+endef
+$(error $(MSG))
+endif
+
+html:
+	$(SPHINXBUILD) -b html . $(BUILDDIR)/html
+	@echo
+	@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+clean:
+	-rm -rf $(BUILDDIR)
+
+
+# Enable `sphinxcontrib-teximage` extension.
+extensions = ['sphinxcontrib.teximage']
+
+# Standard configuration.
+project = u'A Project with Diagrams'
+master_doc = 'index'
+highlight_language = 'latex'
+exclude_patterns = ['_build']
+

demo/database-schema.tex

+\documentclass{article}
+
+\include{preamble}
+
+\begin{document}
+
+\tikzset{
+    > = triangle 45,
+    node distance = 2.5cm and 3.5cm,
+    table/.style = {draw, rectangle,
+                    minimum width=2.5cm, minimum height=1cm,
+                    text height=1.5ex, text depth=.25ex},
+    link/.style = {text width=2cm, font=\small\itshape}
+}
+
+\begin{tikzpicture}
+
+\node[table] (department)
+    {department};
+\node[table] (school) [right=of department]
+    {school};
+\node[table] (course) [below=of department]
+    {course};
+\node[table] (program) [below=of school]
+    {program};
+
+\draw[o->] (department)
+           -- node[link, above] {department may be a part of school}
+           (school);
+\draw[*->] (course)
+           -- node[link, left] {department offers courses}
+           (department);
+\draw[*->] (program)
+           -- node[link, right] {school may offer some programs}
+           (school);
+
+\end{tikzpicture}
+
+\end{document}
+

demo/hello-world.tex

+\documentclass{article}
+
+\usepackage{tikz}
+\pagestyle{empty}
+
+\begin{document}
+
+\begin{tikzpicture}
+\node[draw] {Hello, World!};
+\end{tikzpicture}
+
+\end{document}
+Diagram Examples
+================
+
+This document shows how to include diagrams with ``sphinxcontrib-teximage``
+extensions.
+
+Hello, World!
+-------------
+
+.. sourcecode:: rst
+
+   .. teximage:: hello-world.tex
+
+.. literalinclude:: hello-world.tex
+
+.. teximage:: hello-world.tex
+
+Database Schema
+---------------
+
+.. sourcecode:: rst
+
+   .. teximage:: database-schema.tex
+      :align: center
+
+.. teximage:: database-schema.tex
+   :align: center
+
+.. literalinclude:: preamble.tex
+
+.. literalinclude:: database-schema.tex
+

demo/preamble.tex

+
+\usepackage[landscape]{geometry}
+\usepackage{tikz}
+\usetikzlibrary{arrows,chains}
+\renewcommand*\familydefault{\sfdefault}
+\pagestyle{empty}
+
+#
+# Copyright (c) 2013, Prometheus Research, LLC
+#
+
+
+from setuptools import setup
+
+
+NAME = "sphinxcontrib-teximage"
+VERSION = "0.1"
+DESCRIPTION = "TeX Image extension for Sphinx"
+LONG_DESCRIPTION = open('README').read()
+AUTHOR = "Kirill Simonov (Prometheus Research, LLC)"
+AUTHOR_EMAIL = "xi@resolvent.net"
+LICENSE = "BSD"
+URL = "http://bitbucket.org/prometheus/sphinxcontrib-teximage"
+DOWNLOAD_URL = "http://pypi.python.org/pypi/sphinxcontrib-teximage"
+CLASSIFIERS = [
+        'Development Status :: 4 - Beta',
+        'Intended Audience :: Developers',
+        'License :: OSI Approved :: BSD License',
+        'Operating System :: OS Independent',
+        'Programming Language :: Python',
+        'Topic :: Documentation',
+        'Topic :: Text Processing',
+]
+PLATFORMS = 'any'
+REQUIRES = ['Sphinx']
+PACKAGES = ['sphinxcontrib']
+ZIP_SAFE = False
+INCLUDE_PACKAGE_DATA = True
+NAMESPACE_PACKAGES = ['sphinxcontrib']
+
+
+setup(name=NAME,
+      version=VERSION,
+      description=DESCRIPTION,
+      long_description=LONG_DESCRIPTION,
+      author=AUTHOR,
+      author_email=AUTHOR_EMAIL,
+      license=LICENSE,
+      url=URL,
+      download_url=DOWNLOAD_URL,
+      classifiers=CLASSIFIERS,
+      platforms=PLATFORMS,
+      requires=REQUIRES,
+      packages=PACKAGES,
+      zip_safe=ZIP_SAFE,
+      include_package_data=INCLUDE_PACKAGE_DATA,
+      namespace_packages=NAMESPACE_PACKAGES)
+
+

sphinxcontrib/__init__.py

+#
+# Copyright (c) 2013, Prometheus Research, LLC
+#
+
+
+__import__('pkg_resources').declare_namespace(__name__)
+
+

sphinxcontrib/teximage.py

+#
+# Copyright (c) 2013, Prometheus Research, LLC
+#
+
+
+from docutils import nodes
+from docutils.parsers.rst import Directive, directives
+from sphinx.util.osutil import ensuredir
+from subprocess import Popen, PIPE
+import os, os.path, tempfile, shutil
+
+
+class TeXImageDirective(Directive):
+
+    required_arguments = 1
+    has_content = False
+    option_spec = {
+        'alt': directives.unchanged,
+        'align': lambda arg: directives.choice(arg, ('left', 'center', 'right')),
+    }
+
+    def run(self):
+        doc = self.state.document
+        env = doc.settings.env
+        docdir = os.path.dirname(env.doc2path(env.docname, base=None))
+        filename = self.arguments[0]
+        if filename.startswith('/'):
+            filename = os.path.normpath(filename[1:])
+        else:
+            filename = os.path.normpath(os.path.join(docdir, filename))
+        env.note_dependency(filename)
+        filename = os.path.join(env.srcdir, filename)
+        try:
+            name, data, width, height = render_teximage(env, filename)
+        except TeXImageError, exc:
+            return [doc.reporter.error(str(exc))]
+        node = teximage()
+        node['name'] = name
+        node['data'] = data
+        node['width'] = width
+        node['height'] = height
+        node['alt'] = self.options.get('alt')
+        node['align'] = self.options.get('align')
+        return [node]
+
+
+class TeXImageError(Exception):
+    pass
+
+
+class teximage(nodes.General, nodes.Element):
+    pass
+
+
+def render_teximage(env, filename):
+    directory = os.path.dirname(filename)
+    basename = os.path.basename(filename)
+    stem = os.path.splitext(basename)[0]
+    name = stem + '.png'
+    temp = tempfile.mkdtemp()
+    try:
+        texinputs = [directory]
+        for texdir in env.config.teximage_texinputs:
+            texdir = os.path.join(env.srcdir, texdir)
+            texinputs.append(texdir)
+        texinputs.append('')
+        texinputs = ':'.join(texinputs)
+        environ = os.environ.copy()
+        environ['TEXINPUTS'] = texinputs
+        cmdline = [env.config.teximage_pdftex,
+                   '-halt-on-error',
+                   '-interaction', 'nonstopmode',
+                   '-output-directory', temp,
+                   basename]
+        execute(cmdline, env=environ)
+        cmdline = [env.config.teximage_pdftoppm,
+                   '-r', str(env.config.teximage_resolution),
+                   '-f', '1', '-l', '1',
+                   os.path.join(temp, stem)+'.pdf',
+                   os.path.join(temp, stem)]
+        execute(cmdline)
+        ppmfile = os.path.join(temp, stem)+'-1.ppm'
+        if not os.path.exists(ppmfile):
+            raise TeXImageError("file not found: %s" % ppmfile)
+        data = open(ppmfile).read()
+        cmdline = [env.config.teximage_pnmcrop]
+        data = execute(cmdline, data)
+        line = data.splitlines()[1]
+        width, height = [int(chunk) for chunk in line.split()]
+        cmdline = [env.config.teximage_pnmtopng,
+                   '-transparent', 'white',
+                   '-compression', '9']
+        data = execute(cmdline, data)
+    finally:
+        shutil.rmtree(temp)
+    return name, data, width, height
+
+
+def execute(cmdline, input=None, env=None):
+    try:
+        process = Popen(cmdline, stdin=PIPE, stdout=PIPE, stderr=PIPE, env=env)
+    except OSError, exc:
+        raise TeXImageError("cannot start executable `%s`: %s"
+                            % (' '.join(cmdline), exc))
+    output, error = process.communicate(input)
+    if process.returncode != 0:
+        if not error:
+            error = output
+        raise TeXImageError("`%s` exited with an error:\n%s"
+                            % (' '.join(cmdline), error))
+    return output
+
+
+def visit_teximage(self, node):
+    href = "%s/%s" % (self.builder.imgpath, node['name'])
+    filename = os.path.join(self.builder.outdir, '_images', node['name'])
+    ensuredir(os.path.dirname(filename))
+    open(filename, 'wb').write(node['data'])
+    if (isinstance(node.parent, nodes.TextElement) or
+        (isinstance(node.parent, nodes.reference) and
+         not isinstance(node.parent.parent, nodes.TextElement))):
+        suffix = ''
+    else:
+        suffix = '\n'
+    atts = {}
+    atts['src'] = href
+    atts['width'] = node['width']
+    atts['height'] = node['height']
+    if node['alt']:
+        atts['alt'] = node['alt']
+    atts['class'] = 'teximage'
+    if node['align']:
+        atts['class'] += ' align-%s' % node['align']
+    self.body.append(self.emptytag(node, 'img', suffix, **atts))
+
+
+def depart_teximage(self, node):
+    pass
+
+
+def setup(app):
+    app.add_config_value('teximage_pdftex', 'pdflatex', 'env')
+    app.add_config_value('teximage_pdftoppm', 'pdftoppm', 'env')
+    app.add_config_value('teximage_pnmcrop', 'pnmcrop', 'env')
+    app.add_config_value('teximage_pnmtopng', 'pnmtopng', 'env')
+    app.add_config_value('teximage_texinputs', [], 'env')
+    app.add_config_value('teximage_resolution', 110, 'env')
+    app.add_directive('teximage', TeXImageDirective)
+    app.add_node(teximage,
+                 html=(visit_teximage, depart_teximage))
+
+