Merge lp:~hannes-hochreiner/jessyink/pdf-export into lp:jessyink/1.x

Proposed by Hannes Hochreiner
Status: Merged
Approved by: Hannes Hochreiner
Approved revision: 57
Merged at revision: not available
Proposed branch: lp:~hannes-hochreiner/jessyink/pdf-export
Merge into: lp:jessyink/1.x
Diff against target: None lines
To merge this branch: bzr merge lp:~hannes-hochreiner/jessyink/pdf-export
Reviewer Review Type Date Requested Status
Hannes Hochreiner tested on windows and osx Approve
Review via email: mp+6937@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Hannes Hochreiner (hannes-hochreiner) wrote :

PDF-export seems to work now on all platforms and is therefore ready to be merged into trunk.

Revision history for this message
Hannes Hochreiner (hannes-hochreiner) wrote :

Worked fine in my tests.

review: Approve (tested on windows and osx)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'inkscapeExtensions/jessyInk_pdfOutput.inx'
2--- inkscapeExtensions/jessyInk_pdfOutput.inx 1970-01-01 00:00:00 +0000
3+++ inkscapeExtensions/jessyInk_pdfOutput.inx 2009-04-25 19:35:37 +0000
4@@ -0,0 +1,18 @@
5+<inkscape-extension>
6+ <_name>JessyInk zipped pdf output</_name>
7+ <id>jessyink.pdfOutput</id>
8+ <dependency type="extension">org.inkscape.output.svg.inkscape</dependency>
9+ <dependency type="executable" location="extensions">jessyInk_pdfOutput.py</dependency>
10+ <dependency type="executable" location="extensions">inkex.py</dependency>
11+ <output>
12+ <extension>.zip</extension>
13+ <mimetype>application/x-zip</mimetype>
14+ <_filetypename>JessyInk zipped pdf output (*.zip)</_filetypename>
15+ <_filetypetooltip>Creates a zip file containing pdfs of all slides of a JessyInk presentation.</_filetypetooltip>
16+ <dataloss>TRUE</dataloss>
17+ </output>
18+ <script>
19+ <command reldir="extensions" interpreter="python">jessyInk_pdfOutput.py</command>
20+ <helper_extension>org.inkscape.output.svg.inkscape</helper_extension>
21+ </script>
22+</inkscape-extension>
23
24=== added file 'inkscapeExtensions/jessyInk_pdfOutput.py'
25--- inkscapeExtensions/jessyInk_pdfOutput.py 1970-01-01 00:00:00 +0000
26+++ inkscapeExtensions/jessyInk_pdfOutput.py 2009-06-01 08:31:39 +0000
27@@ -0,0 +1,270 @@
28+#!/usr/bin/env python
29+# Copyright 2008, 2009 Hannes Hochreiner
30+# This program is free software: you can redistribute it and/or modify
31+# it under the terms of the GNU General Public License as published by
32+# the Free Software Foundation, either version 3 of the License, or
33+# (at your option) any later version.
34+#
35+# This program is distributed in the hope that it will be useful,
36+# but WITHOUT ANY WARRANTY; without even the implied warranty of
37+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
38+# GNU General Public License for more details.
39+#
40+# You should have received a copy of the GNU General Public License
41+# along with this program. If not, see http://www.gnu.org/licenses/.
42+
43+# These lines are only needed if you don't put the script directly into
44+# the installation directory
45+import sys
46+# Unix
47+sys.path.append('/usr/share/inkscape/extensions')
48+# OS X
49+sys.path.append('/Applications/Inkscape.app/Contents/Resources/extensions')
50+# Windows
51+sys.path.append('C:\Program Files\Inkscape\share\extensions')
52+
53+import inkex, os.path
54+import subprocess
55+import tempfile
56+import os
57+import zipfile
58+import glob
59+
60+def propStrToDict(inStr):
61+ dictio = {}
62+
63+ for prop in inStr.split(";"):
64+ values = prop.split(":")
65+
66+ if (len(values) == 2):
67+ dictio[values[0].strip()] = values[1].strip()
68+
69+ return dictio
70+
71+def dictToPropStr(dictio):
72+ str = ""
73+
74+ for key in dictio.keys():
75+ str += " " + key + ":" + dictio[key] + ";"
76+
77+ return str[1:]
78+
79+def setStyle(node, propKey, propValue):
80+ props = {}
81+
82+ if node.attrib.has_key("style"):
83+ props = propStrToDict(node.get("style"))
84+
85+ props[propKey] = propValue
86+ node.set("style", dictToPropStr(props))
87+
88+class MyEffect(inkex.Effect):
89+ inkscapeCommand = None
90+ zipFile = None
91+
92+ def __init__(self):
93+ inkex.Effect.__init__(self)
94+
95+ # Register jessyink namespace.
96+ inkex.NSS[u"jessyink"] = u"https://launchpad.net/jessyink"
97+
98+ # Set inkscape command.
99+ self.inkscapeCommand = self.findInkscapeCommand()
100+
101+ if (self.inkscapeCommand == None):
102+ sys.stderr.write("Could not find Inkscape command.\n")
103+ sys.exit(1)
104+
105+ def output(self):
106+ pass
107+
108+ def effect(self):
109+ # Check version.
110+ scriptNodes = self.document.xpath("//svg:script[@jessyink:version='1.1.1']", namespaces=inkex.NSS)
111+
112+ if len(scriptNodes) != 1:
113+ sys.stderr.write("The JessyInk script is not installed in this SVG file or has a different version than the JessyInk extensions. Please select \"install/update...\" from the \"JessyInk\" sub-menu of the \"Effects\" menu to install or update the JessyInk script.\n\n")
114+
115+ # Remove any temporary files that might be left from last time.
116+ self.removeJessyInkFilesInTempDir()
117+
118+ zipFileDesc, zpFile = tempfile.mkstemp(suffix=".zip", prefix="jessyInk__")
119+
120+ output = zipfile.ZipFile(zpFile, "w", compression=zipfile.ZIP_STORED)
121+ slides = []
122+ masterSlide = None
123+
124+ # Make slide array and find master slide (if assigned).
125+ nodes = self.document.xpath("//*[@inkscape:groupmode='layer']", namespaces=inkex.NSS)
126+
127+ for node in nodes:
128+ if node.attrib.has_key("{" + inkex.NSS["jessyink"] + "}masterSlide"):
129+ masterSlide = node
130+
131+ # Set master slide visibility.
132+ setStyle(node, "display", "inherit")
133+ else:
134+ # Set visibility.
135+ setStyle(node, "display", "none")
136+ setStyle(node, "opacity", "0")
137+ slides.append(node)
138+
139+ # Remove master slide from document.
140+ if masterSlide != None:
141+ masterSlide.getparent().remove(masterSlide)
142+
143+ # Set slide number.
144+ slideNumber = 1
145+
146+ # Iterate through slides.
147+ for slide in slides:
148+ # Prepare svg file.
149+ setStyle(slide, "display", "inherit")
150+ setStyle(slide, "opacity", "1")
151+
152+ # Insert master slide.
153+ if masterSlide != None:
154+ slide.insert(0, masterSlide)
155+
156+ # Substitute auto-texts.
157+ autoTextNodes = slide.xpath(".//*[@jessyink:autoText]", namespaces=inkex.NSS)
158+
159+ for autoTextNode in autoTextNodes:
160+ autoTextKind = autoTextNode.get("{" + inkex.NSS["jessyink"] + "}autoText")
161+
162+ if autoTextKind == "slideTitle":
163+ autoTextNode.text = slide.get("{" + inkex.NSS["inkscape"] + "}label")
164+ elif autoTextKind == "slideNumber":
165+ autoTextNode.text = str(slideNumber)
166+ elif autoTextKind == "numberOfSlides":
167+ autoTextNode.text = str(len(slides))
168+
169+ # Collect information about effects.
170+ effects = {}
171+
172+ for effectNode in slide.xpath(".//*[@jessyink:effectIn]", namespaces=inkex.NSS):
173+ dictio = propStrToDict(effectNode.get("{" + inkex.NSS["jessyink"] + "}effectIn"))
174+ dictio["direction"] = "in"
175+ dictio["node"] = effectNode
176+
177+ if not effects.has_key(dictio["order"]):
178+ effects[dictio["order"]] = []
179+
180+ effects[dictio["order"]].append(dictio)
181+
182+ for effectNode in slide.xpath(".//*[@jessyink:effectOut]", namespaces=inkex.NSS):
183+ dictio = propStrToDict(effectNode.get("{" + inkex.NSS["jessyink"] + "}effectOut"))
184+ dictio["direction"] = "out"
185+ dictio["node"] = effectNode
186+
187+ if not effects.has_key(dictio["order"]):
188+ effects[dictio["order"]] = []
189+
190+ effects[dictio["order"]].append(dictio)
191+
192+ order = sorted(effects.keys())
193+ order.reverse()
194+
195+ # Set slide to initial state.
196+ for effectNumber in order:
197+ for effect in effects[effectNumber]:
198+ if effect["direction"] == "out":
199+ setStyle(effect["node"], "display", "inherit")
200+ setStyle(effect["node"], "opacity", "1")
201+ elif effect["direction"] == "in":
202+ setStyle(effect["node"], "display", "none")
203+ setStyle(effect["node"], "opacity", "0")
204+
205+ # Add new page.
206+ effectNmb = 0
207+ self.takeSnapshot(output, slideNumber, len(slides), effectNmb, len(order) - 1)
208+
209+ # Step through effects.
210+ order.reverse()
211+
212+ for effectNumber in order:
213+ effectNmb += 1
214+
215+ for effect in effects[effectNumber]:
216+ if effect["direction"] == "in":
217+ setStyle(effect["node"], "display", "inherit")
218+ setStyle(effect["node"], "opacity", "1")
219+ elif effect["direction"] == "out":
220+ setStyle(effect["node"], "display", "none")
221+ setStyle(effect["node"], "opacity", "0")
222+
223+ self.takeSnapshot(output, slideNumber, len(slides), effectNmb, len(order) - 1)
224+
225+ # Post-process svg.
226+ setStyle(slide, "display", "none")
227+ setStyle(slide, "opacity", "0")
228+
229+ # Increment slide number.
230+ slideNumber += 1
231+
232+ # Write temporary zip file to stdout.
233+ output.close()
234+ out = open(zpFile,'rb')
235+
236+ # Switch stdout to binary on Windows.
237+ if sys.platform == "win32":
238+ import os, msvcrt
239+ msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
240+
241+ # Output the file.
242+ sys.stdout.write(out.read())
243+ sys.stdout.close()
244+ out.close()
245+
246+ # Delete temporary files.
247+ self.removeJessyInkFilesInTempDir()
248+
249+ def takeSnapshot(self, output, slideNumber, maxSlideNumber, effectNumber, maxEffectNumber):
250+ # Write the svg file.
251+ svgFileDesc, svgFile = tempfile.mkstemp(suffix=".svg", prefix="jessyInk__")
252+ self.document.write(os.fdopen(svgFileDesc, "wb"))
253+
254+ # Prepare pdf file.
255+ pdfFileDesc, pdfFile = tempfile.mkstemp(suffix=".pdf", prefix="jessyInk__")
256+
257+ proc = subprocess.Popen([self.inkscapeCommand + " --file=" + svgFile + " --without-gui --export-pdf=" + pdfFile], shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
258+ stdout_value, stderr_value = proc.communicate()
259+
260+ output.write(pdfFile, "slide_" + self.padNumber(slideNumber, maxSlideNumber) + "_effect_" + self.padNumber(effectNumber, maxEffectNumber) + ".pdf")
261+
262+ def removeJessyInkFilesInTempDir(self):
263+ for infile in glob.glob(os.path.join(tempfile.gettempdir(), 'jessyInk__*')):
264+ try:
265+ os.remove(infile)
266+ except:
267+ pass
268+
269+ def padNumber(self, nmb, maxNmb):
270+ if (maxNmb < 0):
271+ maxNmb = 0
272+
273+ maxNmbStr = str(maxNmb)
274+ nmbStr = str(nmb)
275+
276+ while len(nmbStr) < len(maxNmbStr):
277+ nmbStr = "0" + nmbStr
278+
279+ return nmbStr
280+
281+ def findInkscapeCommand(self):
282+ commands = []
283+ commands.append("inkscape")
284+ commands.append("C:\Program Files\Inkscape\inkscape.exe")
285+ commands.append("/Applications/Inkscape.app/Contents/Resources/bin/inkscape")
286+
287+ for command in commands:
288+ proc = subprocess.Popen([command + " --without-gui --version"], shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
289+ stdout_value, stderr_value = proc.communicate()
290+
291+ if proc.returncode == 0:
292+ return command
293+
294+ return None
295+
296+e = MyEffect()
297+e.affect()

Subscribers

People subscribed via source and target branches

to all changes: