1
#!/usr/bin/env python
2
# vim: set fileencoding=utf-8 tabstop=4 shiftwidth=4 expandtab :
3
u"""
4
Publish OpenOffice/LibreOffice's presentations on the web
5
=========================================================
6
7
This script does not handle the whole conversion process, it's rather a
8
bridge between different tools, which all do their part in the conversion
9
process. Here's an overview of the steps involved:
10
11
#. Create or edit your presentation in OpenOffice/LibreOffice_
12
#. Export it to PDF
13
#. Use it as input for this script
14
15
   - it runs pdf2svg_ for you
16
   - it merges the resulting SVG files
17
   - it adds Inkscape layer information
18
   - it produces an SVG file
19
20
#. Open the SVG file with Inkscape_
21
#. Add the JessyInk_ extension (from the 'Extensions' menu)
22
23
   - add JessyInk_ animations or transitions if you want to
24
25
#. Save the SVG file
26
#. Open it in a supported browser (Firefox, Chrome, Safari, Opera)
27
28
If you use slide transitions in your presentation, they will not be exported in
29
the SVG file. This is currently not supported (and anyway it has to be
30
supported in pdf2svg_ first).
31
32
If you use animations (object that appear or disappear on click), you should
33
use the macro in the attached document `in this mail
34
<http://www.mail-archive.com/dev@graphics.openoffice.org/msg00841.html>`_.
35
Run it on a copy of your presentation, and it will expand all the slides
36
containing animations. Export the result to PDF.
37
38
.. _LibreOffice: http://www.libreoffice.org/
39
.. _pdf2svg: http://www.cityinthesky.co.uk/opensource/pdf2svg
40
.. _Inkscape: http://inkscape.org/
41
.. _JessyInk: http://code.google.com/p/jessyink/
42
43
Use the ``--help`` command-line argument for a quick usage help.
44
45
.. :Authors:
46
      Aurélien Bompard <aurelien@bompard.org> <http://aurelien.bompard.org>
47
48
.. :License:
49
      GNU GPL v3 or later
50
51
"""
52
53
54
__version__ = "0.1"
55
56
57
import os
58
import sys
59
import optparse
60
import tempfile
61
import atexit
62
import shutil
63
import subprocess
64
import glob
65
66
try:
67
    from lxml import etree
68
except ImportError:
69
    import xml.etree.ElementTree as etree
70
    print "You should install the 'lxml' module for Python"
71
72
73
NS_SVG = "http://www.w3.org/2000/svg"
74
NS_XLINK = "http://www.w3.org/1999/xlink"
75
NS_INKSCAPE = "http://www.inkscape.org/namespaces/inkscape"
76
77
DESC = """%prog helps converting a PDF presentation (for example as exported by
78
OpenOffice/LibreOffice) to an SVG format that can be imported in Inkscape, to
79
add the JessyInk extension.
80
%prog requires the pdf2svg tool, which you can obtain from your
81
distributions's package manager or download and compile it from
82
http://www.cityinthesky.co.uk/opensource/pdf2svg
83
"""
84
85
def parse_opts():
86
    """Parse command-line arguments"""
87
    usage = "%prog input.pdf output.svg"
88
    parser = optparse.OptionParser(usage, description=DESC,
89
                                   version="%%prog %s" % __version__)
90
    #parser.add_option("-o", "--output", help="Output file")
91
    opts, args = parser.parse_args()
92
    if len(args) != 2:
93
        parser.error("Wrong number of arguments")
94
    if not os.path.exists(args[0]):
95
        parser.error("No such file: %s" % args[0])
96
    return opts, args[0], args[1]
97
98
def pdf2svg(input_pdf, tmpdir):
99
    """Run pdf2svg, or error out if it's not available"""
100
    try:
101
        subprocess.call(["pdf2svg", input_pdf,
102
                os.path.join(tmpdir, "slide-%d.svg"), "all"])
103
    except OSError:
104
        print  "You need to install pdf2svg."
105
        print ("Get it from your distribution's package manager or "
106
               "download and compile it from "
107
               "http://www.cityinthesky.co.uk/opensource/pdf2svg")
108
        sys.exit(1)
109
110
def make_unique(svg, prefix):
111
    """Prefixes IDs and references, to make them unique before merging"""
112
    ref_elements = ["{%s}href" % NS_XLINK, "style", "clip-path"]
113
    for element in svg.iter():
114
        if "id" in element.attrib:
115
            element.set("id", "%s-%s" % (prefix, element.get("id")))
116
        for ref in ref_elements:
117
            if ref in element.attrib:
118
                element.set(ref, element.get(ref).replace("#",
119
                            "#%s-" % prefix))
120
121
def import_svg(svg_in, svg):
122
    """Import an SVG document into another"""
123
    # defs
124
    defs = svg_in.find("{%s}defs" % NS_SVG)
125
    if defs is not None:
126
        for definition in defs:
127
            svg.find("{%s}defs" % NS_SVG).append(definition)
128
    else:
129
        print "no defs !"
130
    # layers
131
    for group in svg_in.findall("{%s}g" % NS_SVG):
132
        svg.getroot().append(group)
133
134
def make_layers(svg):
135
    """Add Inkscape layer information to an SVG file"""
136
    for index, group in enumerate(svg.findall("{%s}g" % NS_SVG)):
137
        group.set("{%s}groupmode" % NS_INKSCAPE, "layer")
138
        group.set("{%s}label" % NS_INKSCAPE, "slide %d" % (index + 1))
139
        if index > 0:
140
            group.set("style", "display:none")
141
142
143
def main():
144
    """Run the whole process"""
145
    _, input_pdf, output = parse_opts()
146
    tmpdir = tempfile.mkdtemp()
147
    atexit.register(shutil.rmtree, tmpdir)
148
    pdf2svg(input_pdf, tmpdir)
149
    svg_files = glob.glob(os.path.join(tmpdir, "slide-*.svg"))
150
    if not svg_files:
151
        print "ERROR: no pages found in the PDF"
152
        sys.exit(1)
153
    svg_files.sort(key=lambda f: int(os.path.basename(f)[6:-4]))
154
    svg = etree.parse(svg_files[0])
155
    for svg_in_path in svg_files[1:]:
156
        svg_in = etree.parse(svg_in_path)
157
        prefix, _ = os.path.splitext(os.path.basename(svg_in_path))
158
        make_unique(svg_in, prefix)
159
        import_svg(svg_in, svg)
160
    make_layers(svg)
161
    svg.write(output, encoding="utf-8")
162
    print ("Now, open %s in Inkscape, and add JessyInk to it (in the "
163
           "'Extensions' menu)." % output)
164
165
166
if __name__ == "__main__":
167
    main()