#!/usr/bin/env python3
#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, see .
# Author: Giacomo Mirabassi
# Version: 0.2
import os
import re
import subprocess
import math
import inkex
import shutil
inkex.localization.localize
class JPEGExport(inkex.EffectExtension):
def add_arguments(self, pars):
pars.add_argument("--path", default="")
pars.add_argument("--bgcol", default="#ffffff")
pars.add_argument("--quality",type=int, default="90")
pars.add_argument("--density", type=int, default="90")
pars.add_argument("--page", type=inkex.Boolean, default=False)
pars.add_argument("--fast", type=inkex.Boolean, default=True)
def effect(self):
"""get selected item coords and call command line command to export as a png"""
# The user must supply a directory to export:
if not self.options.path:
inkex.errormsg(_('Please indicate a file name and path to export the jpg.'))
exit()
if not os.path.basename(self.options.path):
inkex.errormsg(_('Please indicate a file name.'))
exit()
if not os.path.dirname(self.options.path):
inkex.errormsg(_('Please indicate a directory other than your system\'s base directory.'))
exit()
# Test if the directory exists and filename is valid:
filebase = os.path.dirname(self.options.path)
if not os.path.exists(filebase):
inkex.errormsg(_('The directory "%s" does not exist.') % filebase)
exit()
filename = os.path.splitext(os.path.basename(self.options.path))
filename_base = filename[0]
filename_ending = filename[1]
if self.get_valid_filename(filename_base) != filename_base:
inkex.errormsg(_('The file name "%s" is invalid.') % filename_base)
return
if filename_ending != 'jpg' or filename_ending != 'jpeg':
filename_ending = 'jpg'
outfile = os.path.join(filebase, filename_base + '.' + filename_ending)
shutil.copy(self.options.input_file, self.options.input_file + ".svg") #make a file copy with file ending to suppress import warnings
curfile = self.options.input_file + ".svg"
#inkex.utils.debug("curfile:" + curfile)
# Test if color is valid
_rgbhexstring = re.compile(r'#[a-fA-F0-9]{6}$')
if not _rgbhexstring.match(self.options.bgcol):
inkex.errormsg(_('Please indicate the background color like this: \"#abc123\" or leave the field empty for white.'))
exit()
bgcol = self.options.bgcol
if self.options.page == False:
if len(self.svg.selected) == 0:
inkex.errormsg(_('Please select something.'))
exit()
coords=self.processSelected()
self.exportArea(int(coords[0]),int(coords[1]),int(coords[2]),int(coords[3]),curfile,outfile,bgcol)
elif self.options.page == True:
self.exportPage(curfile,outfile,bgcol)
def processSelected(self):
"""Iterate trough nodes and find the bounding coordinates of the selected area"""
startx=None
starty=None
endx=None
endy=None
nodelist=[]
root=self.document.getroot();
toty=self.svg.unittouu(root.attrib['height'])
scale = self.svg.unittouu('1px')
props=['x', 'y', 'width', 'height']
for id in self.svg.selected:
if self.options.fast == True:
nodelist.append(self.svg.getElementById(id))
else: # uses command line
rawprops=[]
for prop in props:
command=("inkscape", "--query-id", id, "--query-"+prop, self.options.input_file)
proc=subprocess.Popen(command,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
proc.wait()
rawprops.append(math.ceil(self.svg.unittouu(proc.stdout.read())))
proc.stdout.close()
proc.stderr.close()
nodeEndX = rawprops[0] + rawprops[2]
nodeStartY = toty - rawprops[1] - rawprops[3]
nodeEndY = toty - rawprops[1]
if rawprops[0] < startx or startx is None:
startx = rawprops[0]
if nodeStartY < starty or starty is None:
starty = nodeStartY
if nodeEndX > endx or endx is None:
endx = nodeEndX
if nodeEndY > endy or endy is None:
endy = nodeEndY
if self.options.fast == True:
bbox = sum([node.bounding_box() for node in nodelist], None)
#inkex.utils.debug(bbox) - see transform.py
'''
width = property(lambda self: self.x.size)
height = property(lambda self: self.y.size)
top = property(lambda self: self.y.minimum)
left = property(lambda self: self.x.minimum)
bottom = property(lambda self: self.y.maximum)
right = property(lambda self: self.x.maximum)
center_x = property(lambda self: self.x.center)
center_y = property(lambda self: self.y.center)
'''
startx = math.ceil(bbox.left)
endx = math.ceil(bbox.right)
h = -bbox.top + bbox.bottom
starty = toty - math.ceil(bbox.top) -h
endy = toty - math.ceil(bbox.top)
coords = [startx / scale, starty / scale, endx / scale, endy / scale]
return coords
def exportArea(self, x0, y0, x1, y1, curfile, outfile, bgcol):
tmp = self.getTmpPath()
command="inkscape --export-area %s:%s:%s:%s -d %s --export-filename \"%sjpinkexp.png\" -b \"%s\" \"%s\"" % (x0, y0, x1, y1, self.options.density, tmp, bgcol, curfile)
p = subprocess.Popen(command, shell=True)
return_code = p.wait()
self.tojpeg(outfile)
#inkex.utils.debug("command:" + command)
#inkex.utils.debug("Errorcode:" + str(return_code))
def exportPage(self, curfile, outfile, bgcol):
tmp = self.getTmpPath()
command = "inkscape --export-area-drawing -d %s --export-filename \"%sjpinkexp.png\" -b \"%s\" \"%s\"" % (self.options.density, tmp, bgcol, curfile)
p = subprocess.Popen(command, shell=True)
return_code = p.wait()
self.tojpeg(outfile)
#inkex.utils.debug("command:" + command)
#inkex.utils.debug("Errorcode:" + str(return_code))
def tojpeg(self, outfile):
tmp = self.getTmpPath()
if os.name == 'nt':
outfile = outfile.replace("\\","\\\\")
# set the ImageMagick command to run based on what's installed
if shutil.which('magick'):
command = "magick \"%sjpinkexp.png\" -sampling-factor 4:4:4 -strip -interlace JPEG -colorspace RGB -quality %s -density %s \"%s\" " % (tmp, self.options.quality, self.options.density, outfile)
# inkex.utils.debug(command)
elif shutil.which('convert'):
command = "convert \"%sjpinkexp.png\" -sampling-factor 4:4:4 -strip -interlace JPEG -colorspace RGB -quality %s -density %s \"%s\" " % (tmp, self.options.quality, self.options.density, outfile)
# inkex.utils.debug(command)
else:
inkex.errormsg(_('ImageMagick does not appear to be installed.'))
exit()
p = subprocess.Popen(command, shell=True)
return_code = p.wait()
#inkex.utils.debug("command:" + command)
#inkex.utils.debug("Errorcode:" + str(return_code))
def getTmpPath(self):
"""Define the temporary folder path depending on the operating system"""
if os.name == 'nt':
return os.getenv('TEMP') + '\\'
else:
return '/tmp/'
def get_valid_filename(self, s):
s = str(s).strip().replace(" ", "_")
return re.sub(r"(?u)[^-\w.]", "", s)
if __name__ == '__main__':
JPEGExport().run()