2020-07-30 01:16:18 +02:00
#!/usr/bin/env python
# coding=utf-8
#
# NextGenerator - an Inkscape extension to export images with automatically replaced values
# Copyright (C) 2008 Aurélio A. Heckert (original Generator extension in Bash)
# 2019 Maren Hachmann (Python rewrite, update for Inkscape 1.0)
#
# 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 3 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# Version 0.9
"""
An Inkscape extension to automatically replace values ( text , attribute values )
in an SVG file and to then export the result to various file formats .
This is useful e . g . for generating images for name badges and other similar items .
"""
from __future__ import unicode_literals
import os
import csv
import json
import time #for debugging purposes
import inkex
from inkex . command import inkscape
class NextGenerator ( inkex . base . TempDirMixin , inkex . base . InkscapeExtension ) :
""" Generate image files by replacing variables in the current file """
def add_arguments ( self , pars ) :
pars . add_argument ( " -c " , " --csv_file " , type = str , dest = " csv_file " , help = " path to a CSV file " )
pars . add_argument ( " -e " , " --extra-vars " , help = " additional variables to replace and the corresponding columns, in JSON format " )
pars . add_argument ( " -f " , " --format " , help = " file format to export to: png, pdf, svg, ps, eps " )
pars . add_argument ( " -d " , " --dpi " , type = int , default = " 300 " , help = " dpi value for exported raster images " )
pars . add_argument ( " -o " , " --output_folder " , help = " path to output folder " )
pars . add_argument ( " -p " , " --file_pattern " , help = " pattern for the output file " )
pars . add_argument ( " -t " , " --tab " , type = str , default = " any " , help = " not needed at all " )
pars . add_argument ( " -i " , " --id " , type = str , default = " " , help = " not needed at all " )
def effect ( self ) :
# load the attributes that should be replaced in addition to textual values
if self . options . extra_vars == None :
self . options . extra_vars = ' {} '
extra_vars = json . loads ( self . options . extra_vars )
# load the CSV file
# spaces around commas will be stripped
csv . register_dialect ( ' generator ' , ' excel ' , skipinitialspace = True )
2021-01-31 18:49:28 +01:00
with open ( self . options . csv_file , newline = ' ' , encoding = ' utf-8-sig ' ) as csvfile :
2020-07-30 01:16:18 +02:00
data = csv . DictReader ( csvfile , dialect = ' generator ' )
for row in data :
export_base_name = self . options . file_pattern
self . new_doc = self . document
for i , ( key , value ) in enumerate ( row . items ( ) ) :
search_string = " % VAR_ " + key + " % "
# replace any occurrances of %VAR_my_variable_name% in the SVG file source code
self . new_doc = self . new_doc . replace ( search_string , value )
# build the file name, still without file extension
export_base_name = export_base_name . replace ( search_string , value )
for key , svg_cont in extra_vars . items ( ) :
if key in row . keys ( ) :
# replace any attributes and other SVG content by the values from the CSV file
self . new_doc = self . new_doc . replace ( svg_cont , row [ key ] )
else :
2020-08-20 13:12:34 +02:00
inkex . errormsg ( " The replacements in the generated images may be incomplete. Please check your entry ' {key} ' in the field for the non-text values. " ) . format ( key = key )
2020-07-30 01:16:18 +02:00
if self . export ( export_base_name ) != True :
return
def export ( self , export_base_name ) :
export_file_name = ' {0} . {1} ' . format ( export_base_name , self . options . format )
if os . path . exists ( self . options . output_folder ) :
export_file_path = os . path . join ( self . options . output_folder , export_file_name )
else :
2020-08-20 13:12:34 +02:00
inkex . errormsg ( " The selected output folder does not exist. " )
2020-07-30 01:16:18 +02:00
return False
if self . options . format == ' svg ' :
# would use this, but it cannot overwrite, nor handle strings for writing...:
# write_svg(self.new_doc, export_file_path)
with open ( export_file_path , ' w ' ) as f :
f . write ( self . new_doc )
else :
actions = {
' png ' : ' export-dpi: {dpi} ;export-filename: {file_name} ;export-do;FileClose ' . \
format ( dpi = self . options . dpi , file_name = export_file_path ) ,
' pdf ' : ' export-dpi: {dpi} ;export-pdf-version:1.5;export-text-to-path;export-filename: {file_name} ;export-do;FileClose ' . \
format ( dpi = self . options . dpi , file_name = export_file_path ) ,
' ps ' : ' export-dpi: {dpi} ;export-text-to-path;export-filename: {file_name} ;export-do;FileClose ' . \
format ( dpi = self . options . dpi , file_name = export_file_path ) ,
' eps ' : ' export-dpi: {dpi} ;export-text-to-path;export-filename: {file_name} ;export-do;FileClose ' . \
format ( dpi = self . options . dpi , file_name = export_file_path ) ,
}
# create a temporary svg file from our string
temp_svg_name = ' {0} . {1} ' . format ( export_base_name , ' svg ' )
temp_svg_path = os . path . join ( self . tempdir , temp_svg_name )
#inkex.utils.debug("temp_svg_path=" + temp_svg_path)
with open ( temp_svg_path , ' w ' ) as f :
f . write ( self . new_doc )
#inkex.utils.debug("self.new_doc=" + self.new_doc)
# let Inkscape do the exporting
# self.debug(actions[self.options.format])
cli_output = inkscape ( temp_svg_path , actions = actions [ self . options . format ] )
if len ( cli_output ) > 0 :
self . debug ( _ ( " Inkscape returned the following output when trying to run the file export; the file export may still have worked: " ) )
self . debug ( cli_output )
return False
2021-01-31 18:49:28 +01:00
return True
2020-07-30 01:16:18 +02:00
def load ( self , stream ) :
return str ( stream . read ( ) , ' utf-8 ' )
def save ( self , stream ) :
# must be implemented, but isn't needed.
pass
if __name__ == ' __main__ ' :
NextGenerator ( ) . run ( )