k40whisperer_turbo/svg_reader.py

921 wiersze
35 KiB
Python

#!/usr/bin/env python
'''
Copyright (C) 2017-2021 Scorch www.scorchworks.com
Derived from dxf_outlines.py by Aaron Spike and Alvin Penner
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
'''
# standard library
import math
import tempfile, os, sys, shutil
import zipfile
import re
# local library
import inkex
import simplestyle
import simpletransform
import cubicsuperpath
import cspsubdiv
import traceback
from PIL import Image
Image.MAX_IMAGE_PIXELS = None
from lxml import etree
try:
inkex.localize()
except:
pass
#### Subprocess timout stuff ######
from subprocess import Popen, PIPE
from threading import Timer
def run_external(cmd, timeout_sec):
stdout=None
stderr=None
FLAG=[True]
try:
proc = Popen(cmd, shell=False, stdout=PIPE, stderr=PIPE, stdin=PIPE, startupinfo=None)
except Exception as e:
raise Exception("\n%s\n\nExecutable Path:\n%s" %(e,cmd[0]))
if timeout_sec > 0:
kill_proc = lambda p: kill_sub_process(p,timeout_sec, FLAG)
timer = Timer(timeout_sec, kill_proc, [proc])
try:
timer.start()
stdout,stderr = proc.communicate()
finally:
timer.cancel()
if not FLAG[0]:
raise Exception("\nInkscape sub-process terminated after %d seconds." %(timeout_sec))
return (stdout,stderr)
def kill_sub_process(p,timeout_sec, FLAG):
FLAG[0]=False
p.kill()
##################################
class SVG_TEXT_EXCEPTION(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
class SVG_ENCODING_EXCEPTION(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
class SVG_PXPI_EXCEPTION(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
class CSS_value_class():
def __init__(self,type_name,value):
type_name_list = type_name.split('.')
try:
self.object_type = type_name_list[0]
except:
self.object_type = ""
try:
self.value_name = type_name_list[1]
except:
self.value_name = ""
self.data_string = value
class CSS_values_class():
def __init__(self):
self.CSS_value_list = []
def add(self,type_name,value):
self.CSS_value_list.append(CSS_value_class(type_name,value))
def get_css_value(self,tag_type,class_val):
value = ""
for entry in self.CSS_value_list:
if entry.object_type == "":
if entry.value_name == class_val:
value = value + entry.data_string
if entry.object_type == tag_type:
if entry.value_name == class_val:
value = entry.data_string
break
return value
class SVG_READER(inkex.Effect):
def __init__(self):
inkex.Effect.__init__(self)
self.flatness = 0.01
self.image_dpi = 1000
self.inkscape_exe_list = []
self.inkscape_exe_list.append("C:\\Program Files\\Inkscape\\bin\\inkscape.exe")
self.inkscape_exe_list.append("C:\\Program Files (x86)\\Inkscape\\bin\\inkscape.exe")
self.inkscape_exe_list.append("C:\\Program Files\\Inkscape\\inkscape.exe")
self.inkscape_exe_list.append("C:\\Program Files (x86)\\Inkscape\\inkscape.exe")
self.inkscape_exe_list.append("/usr/bin/inkscape")
self.inkscape_exe_list.append("/usr/local/bin/inkscape")
self.inkscape_exe_list.append("/Applications/Inkscape.app/Contents/Resources/bin/inkscape")
self.inkscape_exe_list.append("/Applications/Inkscape.app/Contents/MacOS/Inkscape")
self.inkscape_exe = None
self.lines =[]
self.Cut_Type = {}
self.Xsize=40
self.Ysize=40
self.raster = True
self.SVG_dpi = None
self.SVG_inkscape_version = None
self.SVG_size_mm = None
self.SVG_size_px = None
self.SVG_ViewBox = None
self.raster_PIL = None
self.cut_lines = []
self.eng_lines = []
self.id_cnt = 0
self.png_area = "--export-area-page"
self.timout = 180 #timeout time for external calls to Inkscape in seconds
self.layers = ['0']
self.layer = '0'
self.layernames = []
self.txt2paths = False
self.CSS_values = CSS_values_class()
def parse_svg(self,filename):
try:
self.parse(filename)
#self.parse(filename, encoding='utf-8')
except Exception as e:
exception_msg = "%s" %(e)
if exception_msg.find("encoding"):
self.parse(filename,encoding="ISO-8859-1")
else:
raise Exception(e)
def set_inkscape_path(self,PATH):
if PATH!=None:
self.inkscape_exe_list.insert(0,PATH)
for location in self.inkscape_exe_list:
if ( os.path.isfile( location ) ):
self.inkscape_exe=location
break
def colmod(self,r,g,b,path_id):
changed=False
k40_action = 'raster'
delta = 10
# Check if the color is Red (or close to it)
if (r >= 255-delta) and (g <= delta) and (b <= delta):
k40_action = "cut"
self.Cut_Type[path_id]=k40_action
(r,g,b) = (255,255,255)
changed=True
# Check if the color is Blue (or close to it)
elif (r <= delta) and (g <= delta) and (b >= 255-delta):
k40_action = "engrave"
self.Cut_Type[path_id]=k40_action
(r,g,b) = (255,255,255)
changed=True
else:
k40_action = "raster"
self.Cut_Type[path_id]=k40_action
changed=False
color_out = '#%02x%02x%02x' %(r,g,b)
return (color_out, changed, k40_action)
def process_shape(self, node, mat, group_stroke = None):
#################################
### Determine the shape type ###
#################################
try:
i = node.tag.find('}')
if i >= 0:
tag_type = node.tag[i+1:]
except:
tag_type=""
##############################################
### Set a unique identifier for each shape ###
##############################################
self.id_cnt=self.id_cnt+1
path_id = "ID%d"%(self.id_cnt)
sw_flag = False
changed = False
#######################################
### Handle references to CSS data ###
#######################################
class_val = node.get('class')
if class_val:
css_data = ""
for cv in class_val.split(' '):
if css_data!="":
css_data = self.CSS_values.get_css_value(tag_type,cv)+";"+css_data
else:
css_data = self.CSS_values.get_css_value(tag_type,cv)
# Remove the reference to the CSS data
del node.attrib['class']
# Check if a style entry already exists. If it does
# append the the existing style data to the CSS data
# otherwise create a new style entry.
if node.get('style'):
if css_data!="":
css_data = css_data + ";" + node.get('style')
node.set('style', css_data)
else:
node.set('style', css_data)
style = node.get('style')
self.Cut_Type[path_id]="raster" # Set default type to raster
text_message_warning = "SVG File with Color Coded Text Outlines Found: (i.e. Blue: engrave/ Red: cut)"
line1 = "SVG File with color coded text outlines found (i.e. Blue: engrave/ Red: cut)."
line2 = "Automatic conversion to paths failed: Try upgrading to Inkscape .90 or later"
line3 = "To convert manually in Inkscape: select the text then select \"Path\"-\"Object to Path\" in the menu bar."
text_message_fatal = "%s\n\n%s\n\n%s" %(line1,line2,line3)
##############################################
### Handle 'style' data outside of style ###
##############################################
stroke_outside = node.get('stroke')
if not stroke_outside:
stroke_outside = group_stroke
if stroke_outside:
stroke_width_outside = node.get('stroke-width')
col = stroke_outside
col= col.strip()
if simplestyle.isColor(col):
c=simplestyle.parseColor(col)
(new_val,changed,k40_action)=self.colmod(c[0],c[1],c[2],path_id)
else:
new_val = col
if changed:
node.set('stroke',new_val)
node.set('stroke-width',"0.0")
node.set('k40_action', k40_action)
sw_flag = True
if sw_flag == True:
if node.tag == inkex.addNS('text','svg') or node.tag == inkex.addNS('flowRoot','svg'):
if (self.txt2paths==False):
raise SVG_TEXT_EXCEPTION(text_message_warning)
else:
raise Exception(text_message_fatal)
###################################################
### Handle 'k40_action' data outside of style ###
###################################################
if node.get('k40_action'):
k40_action = node.get('k40_action')
changed=True
self.Cut_Type[path_id]=k40_action
##############################################
### Handle 'style' data ###
##############################################
if style:
declarations = style.split(';')
i_sw = -1
sw_prop = 'stroke-width'
for i,decl in enumerate(declarations):
parts = decl.split(':', 2)
if len(parts) == 2:
(prop, col) = parts
prop = prop.strip().lower()
if prop == 'display' and col == "none":
# display is 'none' return without processing group
return
if prop == 'k40_action':
changed = True
self.Cut_Type[path_id]=col
#if prop in color_props:
if prop == sw_prop:
i_sw = i
if prop == 'stroke':
col= col.strip()
if simplestyle.isColor(col):
c=simplestyle.parseColor(col)
(new_val,changed,k40_action)=self.colmod(c[0],c[1],c[2],path_id)
else:
new_val = col
if changed:
declarations[i] = prop + ':' + new_val
declarations.append('k40_action' + ':' + k40_action)
sw_flag = True
if sw_flag == True:
if node.tag == inkex.addNS('text','svg') or node.tag == inkex.addNS('flowRoot','svg'):
if (self.txt2paths==False):
raise SVG_TEXT_EXCEPTION(text_message_warning)
else:
raise Exception(text_message_fatal)
if i_sw != -1:
declarations[i_sw] = sw_prop + ':' + "0.0"
else:
declarations.append(sw_prop + ':' + "0.0")
node.set('style', ';'.join(declarations))
##############################################
#####################################################
### If vector data was found save the path data ###
#####################################################
if changed:
if node.get('display')=='none':
return
if node.tag == inkex.addNS('path','svg'):
d = node.get('d')
if not d:
return
p = cubicsuperpath.parsePath(d)
elif node.tag == inkex.addNS('rect','svg'):
x = 0.0
y = 0.0
if node.get('x'):
x=float(node.get('x'))
if node.get('y'):
y=float(node.get('y'))
width = float(node.get('width'))
height = float(node.get('height'))
rx = 0.0
ry = 0.0
if node.get('rx'):
rx=float(node.get('rx'))
if node.get('ry'):
ry=float(node.get('ry'))
if max(rx,ry) > 0.0:
if rx==0.0 or ry==0.0:
rx = max(rx,ry)
ry = rx
Rxmax = abs(width)/2.0
Rymax = abs(height)/2.0
rx = min(rx,Rxmax)
ry = min(ry,Rymax)
L1 = "M %f,%f %f,%f " %(x+rx , y , x+width-rx , y )
C1 = "A %f,%f 0 0 1 %f,%f" %(rx , ry , x+width , y+ry )
L2 = "M %f,%f %f,%f " %(x+width , y+ry , x+width , y+height-ry)
C2 = "A %f,%f 0 0 1 %f,%f" %(rx , ry , x+width-rx , y+height )
L3 = "M %f,%f %f,%f " %(x+width-rx , y+height , x+rx , y+height )
C3 = "A %f,%f 0 0 1 %f,%f" %(rx , ry , x , y+height-ry)
L4 = "M %f,%f %f,%f " %(x , y+height-ry, x , y+ry )
C4 = "A %f,%f 0 0 1 %f,%f" %(rx , ry , x+rx , y )
d = L1 + C1 + L2 + C2 + L3 + C3 + L4 + C4
else:
d = "M %f,%f %f,%f %f,%f %f,%f Z" %(x,y, x+width,y, x+width,y+height, x,y+height)
p = cubicsuperpath.parsePath(d)
elif node.tag == inkex.addNS('circle','svg'):
cx = 0.0
cy = 0.0
if node.get('cx'):
cx=float(node.get('cx'))
if node.get('cy'):
cy=float(node.get('cy'))
if node.get('r'):
r = float(node.get('r'))
d = "M %f,%f A %f,%f 0 0 1 %f,%f %f,%f 0 0 1 %f,%f %f,%f 0 0 1 %f,%f %f,%f 0 0 1 %f,%f Z" %(cx+r,cy, r,r,cx,cy+r, r,r,cx-r,cy, r,r,cx,cy-r, r,r,cx+r,cy)
else: #if there is no radius assume it is a path
if node.get('d'):
d = node.get('d')
p = cubicsuperpath.parsePath(d)
else:
raise Exception("Radius of SVG circle is not defined.")
p = cubicsuperpath.parsePath(d)
elif node.tag == inkex.addNS('ellipse','svg'):
cx = 0.0
cy = 0.0
if node.get('cx'):
cx=float(node.get('cx'))
if node.get('cy'):
cy=float(node.get('cy'))
if node.get('r'):
r = float(node.get('r'))
rx = r
ry = r
if node.get('rx'):
rx = float(node.get('rx'))
if node.get('ry'):
ry = float(node.get('ry'))
d = "M %f,%f A %f,%f 0 0 1 %f,%f %f,%f 0 0 1 %f,%f %f,%f 0 0 1 %f,%f %f,%f 0 0 1 %f,%f Z" %(cx+rx,cy, rx,ry,cx,cy+ry, rx,ry,cx-rx,cy, rx,ry,cx,cy-ry, rx,ry,cx+rx,cy)
p = cubicsuperpath.parsePath(d)
elif (node.tag == inkex.addNS('polygon','svg')) or (node.tag == inkex.addNS('polyline','svg')):
points = node.get('points')
if not points:
return
points = points.replace(',', ' ')
while points.find(' ') > -1:
points = points.replace(' ', ' ')
points = points.strip().split(" ")
d = "M "
for i in range(0,len(points),2):
x = float(points[i])
y = float(points[i+1])
d = d + "%f,%f " %(x,y)
#Close the loop if it is a ploygon
if node.tag == inkex.addNS('polygon','svg'):
d = d + "Z"
p = cubicsuperpath.parsePath(d)
elif node.tag == inkex.addNS('line','svg'):
x1 = float(node.get('x1'))
y1 = float(node.get('y1'))
x2 = float(node.get('x2'))
y2 = float(node.get('y2'))
d = "M "
d = "M %f,%f %f,%f" %(x1,y1,x2,y2)
p = cubicsuperpath.parsePath(d)
else:
#print("something was ignored")
#print(node.tag)
return
trans = node.get('transform')
if trans:
mat = simpletransform.composeTransform(mat, simpletransform.parseTransform(trans))
simpletransform.applyTransformToPath(mat, p)
##########################################
## Break Curves down into small lines ###
##########################################
f = self.flatness
is_flat = 0
while is_flat < 1:
try:
cspsubdiv.cspsubdiv(p, f)
is_flat = 1
except IndexError:
break
except:
f += 0.1
if f>2 :
break
#something has gone very wrong.
##########################################
rgb=(0,0,0)
for sub in p:
for i in range(len(sub)-1):
x1 = sub[i][1][0]
y1 = sub[i][1][1]
x2 = sub[i+1][1][0]
y2 = sub[i+1][1][1]
self.lines.append([x1,y1,x2,y2,rgb,path_id])
#####################################################
### End of saving the vector path data ###
#####################################################
def process_clone(self, node):
trans = node.get('transform')
x = node.get('x')
y = node.get('y')
mat = [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]
if trans:
mat = simpletransform.composeTransform(mat, simpletransform.parseTransform(trans))
if x:
mat = simpletransform.composeTransform(mat, [[1.0, 0.0, float(x)], [0.0, 1.0, 0.0]])
if y:
mat = simpletransform.composeTransform(mat, [[1.0, 0.0, 0.0], [0.0, 1.0, float(y)]])
# push transform
if trans or x or y:
self.groupmat.append(simpletransform.composeTransform(self.groupmat[-1], mat))
# get referenced node
refid = node.get(inkex.addNS('href','xlink'))
#print(refid,node.get('id'),node.get('layer'))
refnode = self.getElementById(refid[1:])
if refnode is not None:
if refnode.tag == inkex.addNS('g','svg') or refnode.tag == inkex.addNS('switch','svg'):
self.process_group(refnode)
elif refnode.tag == inkex.addNS('use', 'svg'):
#print(refnode,'1')
self.process_clone(refnode)
else:
self.process_shape(refnode, self.groupmat[-1])
# pop transform
if trans or x or y:
self.groupmat.pop()
def process_group(self, group):
##############################################
### Get color set at group level
stroke_group = group.get('stroke')
if group.get('display')=='none':
return
##############################################
### Handle 'style' data
style = group.get('style')
if style:
declarations = style.split(';')
for i,decl in enumerate(declarations):
parts = decl.split(':', 2)
if len(parts) == 2:
(prop, val) = parts
prop = prop.strip().lower()
if prop == 'stroke':
stroke_group = val.strip()
if prop == 'display' and val == "none":
#group display is 'none' return without processing group
return
##############################################
if group.get(inkex.addNS('groupmode', 'inkscape')) == 'layer':
style = group.get('style')
if style:
style = simplestyle.parseStyle(style)
if 'display' in style:
if style['display'] == 'none':
#layer display is 'none' return without processing layer
return
layer = group.get(inkex.addNS('label', 'inkscape'))
layer = layer.replace(' ', '_')
if layer in self.layers:
self.layer = layer
trans = group.get('transform')
if trans:
self.groupmat.append(simpletransform.composeTransform(self.groupmat[-1], simpletransform.parseTransform(trans)))
for node in group:
if node.tag == inkex.addNS('g','svg') or node.tag == inkex.addNS('switch','svg'):
self.process_group(node)
elif node.tag == inkex.addNS('use', 'svg'):
#print(node.get('id'),'2',node.get('href'))
self.process_clone(node)
elif node.tag == inkex.addNS('style', 'svg'):
if node.get('type')=="text/css":
self.parse_css(node.text)
elif node.tag == inkex.addNS('defs', 'svg'):
for sub in node:
if sub.tag == inkex.addNS('style','svg'):
self.parse_css(sub.text)
else:
self.process_shape(node, self.groupmat[-1], group_stroke = stroke_group)
if trans:
self.groupmat.pop()
def parse_css(self,css_string):
if css_string == None:
return
name_list=[]
value_list=[]
name=""
value=""
i=0
while i < len(css_string):
c=css_string[i]
if c==",":
i=i+1
name_list.append(name)
value_list.append(value)
name=""
value=""
continue
if c=="{":
i=i+1
while i < len(css_string):
c=css_string[i]
i=i+1
if c=="}":
break
else:
value = value+c
if len(value_list)>0:
len_value_list = len(value_list)
k=-1
while abs(k) <= len_value_list and value_list[k]=="":
value_list[k]=value
k=k-1
name_list.append(name)
value_list.append(value)
name=""
value=""
continue
name=name+c
i=i+1
for i in range(len(name_list)):
name_list[i]=" ".join(name_list[i].split())
self.CSS_values.add(name_list[i],value_list[i])
def unit2mm(self, string): #,dpi=None):
if string==None:
return None
# Returns mm given a string representation of units in another system
# a dictionary of unit to user unit conversion factors
uuconv = {'in': 25.4,
'pt': 25.4/72.0,
'mm': 1.0,
'cm': 10.0,
'm' : 1000.0,
'km': 1000.0*1000.0,
'pc': 25.4/6.0,
'yd': 25.4*12*3,
'ft': 25.4*12}
unit = re.compile('(%s)$' % '|'.join(uuconv.keys()))
param = re.compile(r'(([-+]?[0-9]+(\.[0-9]*)?|[-+]?\.[0-9]+)([eE][-+]?[0-9]+)?)')
string = string.replace(' ','')
p = param.match(string)
u = unit.search(string)
if p:
retval = float(p.string[p.start():p.end()])
else:
return None
if u:
retunit = u.string[u.start():u.end()]
else:
return None
try:
return retval * uuconv[retunit]
except KeyError:
return None
def unit2px(self, string):
if string==None:
return None
string = string.replace(' ','')
string = string.replace('px','')
try:
retval = float(string)
except:
retval = None
return retval
def Make_PNG(self):
#create OS temp folder
tmp_dir = tempfile.mkdtemp()
#tmp_dir = self.tempDir()
if self.inkscape_exe != None:
try:
svg_temp_file = os.path.join(tmp_dir, "k40w_temp.svg")
png_temp_file = os.path.join(tmp_dir, "k40w_image.png")
dpi = "%d" %(self.image_dpi)
#print(dpi)
self.document.write(svg_temp_file)
#self.document.write("svg_temp_file.svg", encoding='utf-8')
# Check Version of Inkscape
cmd = [ self.inkscape_exe, "-V"]
(stdout,stderr)=run_external(cmd, self.timout)
#print(stdout)
if stdout.find(b'Inkscape 1.')==-1:
cmd = [ self.inkscape_exe, self.png_area, "--export-dpi", dpi, \
"--export-background","rgb(255, 255, 255)","--export-background-opacity", \
"255" ,"--export-png", png_temp_file, svg_temp_file ]
else:
cmd = [ self.inkscape_exe, self.png_area, "--export-dpi", dpi, \
"--export-background","rgb(255, 255, 255)","--export-background-opacity", \
"255" ,"--export-type=png", "--export-filename=%s" %(png_temp_file), svg_temp_file ]
run_external(cmd, self.timout)
self.raster_PIL = Image.open(png_temp_file)
self.raster_PIL = self.raster_PIL.convert("L")
except Exception as e:
try:
shutil.rmtree(tmp_dir)
except:
pass
error_text = "%s" %(e)
raise Exception("Inkscape Execution Failed (while making raster data).\n%s" %(error_text))
else:
raise Exception("Inkscape Not found.")
try:
shutil.rmtree(tmp_dir)
except:
raise Exception("Temp dir failed to delete:\n%s" %(tmp_dir) )
## def open_cdr_file(self,filename):
## #create OS temp folder
## svg_temp_file=filename
## #tmp_dir = tempfile.mkdtemp()
## tmp_dir = self.tempDir()
## if self.inkscape_exe != None:
## try:
## #svg_temp_file = os.path.join(tmp_dir, "k40w_temp.svg")
## txt2path_file = os.path.join(tmp_dir, "txt2path.svg")
## #self.document.write(svg_temp_file)
## cmd = [ self.inkscape_exe, "--export-text-to-path","--export-plain-svg",txt2path_file, svg_temp_file ]
## run_external(cmd, self.timout)
## self.parse_svg(txt2path_file)
## except Exception as e:
## raise Exception("Inkscape Execution Failed (while converting text to paths).\n\n"+str(e))
## else:
## raise Exception("Inkscape Not found.")
## try:
## shutil.rmtree(tmp_dir)
## except:
## raise Exception("Temp dir failed to delete:\n%s" %(tmp_dir) )
## def tempDir(self):
## tmpdir = tempfile.mkdtemp()
## if os.path.isdir(tmpdir):
## print("first tmp dir exists")
## print(tmpdir)
## #raw_input("press any key...")
## else:
## print("try again")
## tmpdir_base = tempfile.gettempdir()
## print(tmpdir_base)
## tmpdir = tmpdir_base+"/k40whisperer"
## os.mkdir(tmpdir)
## if not os.path.isdir(tmpdir):
## print("still didn't work")
## #creatte folder intempdir
## #test if new dir exists
##
## return tmpdir
def convert_text2paths(self):
#create OS temp folder
tmp_dir = tempfile.mkdtemp()
#tmp_dir = self.tempDir()
if self.inkscape_exe != None:
try:
svg_temp_file = os.path.join(tmp_dir, "k40w_temp.svg")
txt2path_file = os.path.join(tmp_dir, "txt2path.svg")
self.document.write(svg_temp_file)
# Check Version of Inkscape
cmd = [ self.inkscape_exe, "-V"]
(stdout,stderr)=run_external(cmd, self.timout)
if stdout.find(b'Inkscape 1.')==-1:
cmd = [ self.inkscape_exe, "--export-text-to-path","--export-plain-svg", \
txt2path_file, svg_temp_file, ]
else:
cmd = [ self.inkscape_exe, "--export-text-to-path","--export-plain-svg", \
"--export-filename=%s" %(txt2path_file), svg_temp_file, ]
(stdout,stderr)=run_external(cmd, self.timout)
self.parse_svg(txt2path_file)
except Exception as e:
raise Exception("Inkscape Execution Failed (while converting text to paths).\n\n"+str(e))
else:
raise Exception("Inkscape Not found.")
try:
shutil.rmtree(tmp_dir)
except:
raise Exception("Temp dir failed to delete:\n%s" %(tmp_dir) )
def set_size(self,pxpi,viewbox):
width_mm = viewbox[2]/pxpi*25.4
height_mm = viewbox[3]/pxpi*25.4
self.document.getroot().set('width', '%fmm' %(width_mm))
self.document.getroot().set('height','%fmm' %(height_mm))
self.document.getroot().set('viewBox', '%f %f %f %f' %(viewbox[0],viewbox[1],viewbox[2],viewbox[3]))
def make_paths(self, txt2paths=False ):
self.txt2paths = txt2paths
msg = ""
if (self.txt2paths):
self.convert_text2paths()
#################
## GET VIEWBOX ##
#################
view_box_array = self.document.getroot().xpath('@viewBox', namespaces=inkex.NSS) #[0]
if view_box_array == []:
view_box_str = None
else:
view_box_str=view_box_array[0]
#################
## GET SIZE ##
#################
h_array = self.document.getroot().xpath('@height', namespaces=inkex.NSS)
w_array = self.document.getroot().xpath('@width' , namespaces=inkex.NSS)
if h_array == []:
h_string = None
else:
h_string = h_array[0]
if w_array == []:
w_string = None
else:
w_string = w_array[0]
#################
w_mm = self.unit2mm(w_string)
h_mm = self.unit2mm(h_string)
w_px = self.unit2px(w_string)
h_px = self.unit2px(h_string)
self.SVG_Size = [w_mm, h_mm, w_px, h_px]
if view_box_str!=None:
view_box_list = view_box_str.split(' ')
DXpix= float(view_box_list[0])
DYpix= float(view_box_list[1])
Wpix = float(view_box_list[2])
Hpix = float(view_box_list[3])
self.SVG_ViewBox = [DXpix, DYpix, Wpix, Hpix]
else:
SVG_ViewBox = None
if h_mm==None or w_mm==None or self.SVG_ViewBox==None:
line1 = "Cannot determine SVG size. Viewbox missing or Units not set."
raise SVG_PXPI_EXCEPTION("%s" %(line1))
scale_h = h_mm/Hpix
scale_w = w_mm/Wpix
Dx = DXpix * scale_w
Dy = DYpix * scale_h
if abs(1.0-scale_h/scale_w) > .01:
line1 ="SVG Files with different scales in X and Y are not supported.\n"
line2 ="In Inkscape (v0.92): 'File'-'Document Properties'"
line3 ="on the 'Page' tab adjust 'Scale x:' in the 'Scale' section"
raise Exception("%s\n%s\n%s" %(line1,line2,line3))
for node in self.document.getroot().xpath('//svg:g', namespaces=inkex.NSS):
if node.get(inkex.addNS('groupmode', 'inkscape')) == 'layer':
layer = node.get(inkex.addNS('label', 'inkscape'))
self.layernames.append(layer.lower())
layer = layer.replace(' ', '_')
if layer and not layer in self.layers:
self.layers.append(layer)
self.groupmat = [[[scale_w, 0.0, 0.0-Dx],
[0.0 , -scale_h, h_mm+Dy]]]
self.process_group(self.document.getroot())
#################################################
xmin= 0.0
xmax= w_mm
ymin= -h_mm
ymax= 0.0
self.Make_PNG()
self.Xsize=xmax-xmin
self.Ysize=ymax-ymin
Xcorner=xmin
Ycorner=ymax
for ii in range(len(self.lines)):
self.lines[ii][0] = self.lines[ii][0]-Xcorner
self.lines[ii][1] = self.lines[ii][1]-Ycorner
self.lines[ii][2] = self.lines[ii][2]-Xcorner
self.lines[ii][3] = self.lines[ii][3]-Ycorner
self.cut_lines = []
self.eng_lines = []
for line in self.lines:
ID=line[5]
if (self.Cut_Type[ID]=="engrave"):
self.eng_lines.append([line[0],line[1],line[2],line[3]])
elif (self.Cut_Type[ID]=="cut"):
self.cut_lines.append([line[0],line[1],line[2],line[3]])
else:
pass
if __name__ == '__main__':
svg_reader = SVG_READER()
#svg_reader.parse("test.svg")
#svg_reader.make_paths()
tests=["100 mm ",".1 m ","4 in ","100 px ", "100 "]
for line in tests:
print(svg_reader.unit2mm(line),svg_reader.unit2px(line))