#!/usr/bin/env python ''' svg_and_media_zip_output.py An extention which collects all images to the documents directory and creates a zip archive containing all images and the document Copyright (C) 2005 Pim Snel, pim@lingewoud.com Copyright (C) 2008 Aaron Spike, aaron@ekips.org Copyright (C) 2011 Nicolas Dufour, nicoduf@yahoo.fr * Fix for a bug related to special caracters in the path (LP #456248). * Fix for Windows support (LP #391307 ). * Font list and image directory features. this is the first Python script ever created its based on embedimage.py This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA TODOs - fix bug: not saving existing .zip after a Collect for Output is run this bug occurs because after running an effect extention the inkscape:output_extension is reset to svg.inkscape the file name is still xxx.zip. after saving again the file xxx.zip is written with a plain .svg which looks like a corrupt zip - maybe add better extention - consider switching to lzma in order to allow cross platform compression with no encoding problem... ''' # standard library import urlparse import urllib import os, os.path import string import zipfile import shutil import sys import tempfile import locale # local library import inkex import simplestyle locale.setlocale(locale.LC_ALL, '') inkex.localize() class CompressedMediaOutput(inkex.Effect): def __init__(self): inkex.Effect.__init__(self) if os.name == 'nt': self.encoding = "cp437" else: self.encoding = "latin-1" self.text_tags = ['{http://www.w3.org/2000/svg}tspan', '{http://www.w3.org/2000/svg}text', '{http://www.w3.org/2000/svg}flowRoot', '{http://www.w3.org/2000/svg}flowPara', '{http://www.w3.org/2000/svg}flowSpan'] self.OptionParser.add_option("--image_dir", action="store", type="string", dest="image_dir", default="", help="Image directory") self.OptionParser.add_option("--font_list", action="store", type="inkbool", dest="font_list", default=False, help="Add font list") self.OptionParser.add_option("--tab", action="store", type="string", dest="tab", help="The selected UI-tab when OK was pressed") def output(self): ''' Writes the temporary compressed file to its destination and removes the temporary directory. ''' out = open(self.zip_file,'rb') if os.name == 'nt': try: import msvcrt msvcrt.setmode(1, os.O_BINARY) except: pass sys.stdout.write(out.read()) out.close() shutil.rmtree(self.tmp_dir) def collect_images(self, docname, z): ''' Collects all images in the document and copy them to the temporary directory. ''' if locale.getpreferredencoding(): dir_locale = locale.getpreferredencoding() else: dir_locale = "UTF-8" dir = unicode(self.options.image_dir, dir_locale) for node in self.document.xpath('//svg:image', namespaces=inkex.NSS): xlink = node.get(inkex.addNS('href',u'xlink')) if (xlink[:4] != 'data'): absref = node.get(inkex.addNS('absref',u'sodipodi')) url = urlparse.urlparse(xlink) href = urllib.url2pathname(url.path) if (href != None): absref = os.path.realpath(href) absref = unicode(absref, "utf-8") image_path = os.path.join(dir, os.path.basename(absref)) if (os.path.isfile(absref)): shutil.copy(absref, self.tmp_dir) z.write(absref, image_path.encode(self.encoding)) elif (os.path.isfile(os.path.join(self.tmp_dir, absref))): # TODO: please explain why this clause is necessary shutil.copy(os.path.join(self.tmp_dir, absref), self.tmp_dir) z.write(os.path.join(self.tmp_dir, absref), image_path.encode(self.encoding)) else: inkex.errormsg(_('Could not locate file: %s') % absref) node.set(inkex.addNS('href',u'xlink'), image_path) #node.set(inkex.addNS('absref',u'sodipodi'), image_path) def collect_SVG(self, docstripped, z): ''' Copy SVG document to the temporary directory and add it to the temporary compressed file ''' dst_file = os.path.join(self.tmp_dir, docstripped) stream = open(dst_file,'w') self.document.write(stream) stream.close() z.write(dst_file,docstripped.encode(self.encoding)+'.svg') def is_text(self, node): ''' Returns true if the tag in question is an element that can hold text. ''' return node.tag in self.text_tags def get_fonts(self, node): ''' Given a node, returns a list containing all the fonts that the node is using. ''' fonts = [] s = '' if 'style' in node.attrib: s = simplestyle.parseStyle(node.attrib['style']) if not s: return fonts if s.has_key('font-family'): if s.has_key('font-weight'): fonts.append(s['font-family'] + ' ' + s['font-weight']) else: fonts.append(s['font-family']) elif s.has_key('-inkscape-font-specification'): fonts.append(s['-inkscape-font-specification']) return fonts def list_fonts(self, z): ''' Walks through nodes, building a list of all fonts found, then reports to the user with that list. Based on Craig Marshall's replace_font.py ''' items = [] nodes = [] items = self.document.getroot().getiterator() nodes.extend(filter(self.is_text, items)) fonts_found = [] for node in nodes: for f in self.get_fonts(node): if not f in fonts_found: fonts_found.append(f) findings = sorted(fonts_found) # Write list to the temporary compressed file filename = 'fontlist.txt' dst_file = os.path.join(self.tmp_dir, filename) stream = open(dst_file,'w') if len(findings) == 0: stream.write(_("Didn't find any fonts in this document/selection.")) else: if len(findings) == 1: stream.write(_("Found the following font only: %s") % findings[0]) else: stream.write(_("Found the following fonts:\n%s") % '\n'.join(findings)) stream.close() z.write(dst_file, filename) def effect(self): docroot = self.document.getroot() docname = docroot.get(inkex.addNS('docname',u'sodipodi')) #inkex.errormsg(_('Locale: %s') % locale.getpreferredencoding()) if docname is None: docname = self.args[-1] # TODO: replace whatever extention docstripped = os.path.basename(docname.replace('.zip', '')) docstripped = docstripped.replace('.svg', '') docstripped = docstripped.replace('.svgz', '') # Create os temp dir self.tmp_dir = tempfile.mkdtemp() # Create destination zip in same directory as the document self.zip_file = os.path.join(self.tmp_dir, docstripped) + '.zip' z = zipfile.ZipFile(self.zip_file, 'w') self.collect_images(docname, z) self.collect_SVG(docstripped, z) if self.options.font_list == True: self.list_fonts(z) z.close() if __name__ == '__main__': #pragma: no cover e = CompressedMediaOutput() e.affect() # vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99