added some crap-style roland cutstudio eps export extension
This commit is contained in:
parent
998a6e397f
commit
8c8b2a7400
@ -36,7 +36,7 @@ possible import file types -> https://www.graphics.rwth-aachen.de/media/openmesh
|
||||
|
||||
ToDos:
|
||||
- Add glue tabs
|
||||
- Fix bug with canvas resizing. bounding box of paperfoldMainGroup returns undexplainable wrong results. Why the fuck? How to update the view to get correct values here?
|
||||
- Fix bug with canvas resizing. bounding box of paperfoldMainGroup returns unexplainable wrong results. How to update the view to get correct values here?
|
||||
- Print statistics about
|
||||
- groups
|
||||
- triagle count
|
||||
|
15
extensions/fablabchemnitz/roland_eps_export.inx
Normal file
15
extensions/fablabchemnitz/roland_eps_export.inx
Normal file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
|
||||
<name>Roland CutStudio *.eps Export</name>
|
||||
<id>fablabchemnitz.de.roland_eps_export</id>
|
||||
<output>
|
||||
<extension>.eps</extension>
|
||||
<mimetype>application/postscript</mimetype>
|
||||
<filetypename>Roland CutStudio compatible (*.eps)</filetypename>
|
||||
<filetypetooltip>Desktop Cutting Plotter</filetypetooltip>
|
||||
<dataloss>true</dataloss>
|
||||
</output>
|
||||
<script>
|
||||
<command location="inx" interpreter="python">roland_eps_export.py</command>
|
||||
</script>
|
||||
</inkscape-extension>
|
296
extensions/fablabchemnitz/roland_eps_export.py
Normal file
296
extensions/fablabchemnitz/roland_eps_export.py
Normal file
@ -0,0 +1,296 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
'''
|
||||
Roland CutStudio export script
|
||||
Copyright (C) 2014 - 2020 Max Gaukler <development@maxgaukler.de>
|
||||
|
||||
skeleton based on visicut Inkscape Plugin :
|
||||
Copyright (C) 2012 Thomas Oster, thomas.oster@rwth-aachen.de
|
||||
|
||||
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
|
||||
'''
|
||||
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
from __future__ import absolute_import
|
||||
|
||||
from builtins import open
|
||||
from builtins import map
|
||||
from builtins import str
|
||||
from builtins import range
|
||||
import sys
|
||||
import os
|
||||
from subprocess import Popen
|
||||
import subprocess
|
||||
import shutil
|
||||
import numpy
|
||||
from functools import reduce
|
||||
import inkex
|
||||
import filecmp
|
||||
from pathlib import Path
|
||||
from functools import lru_cache
|
||||
import atexit
|
||||
DEVNULL = open(os.devnull, 'w')
|
||||
atexit.register(DEVNULL.close)
|
||||
|
||||
def message(s):
|
||||
sys.stderr.write(s+"\n")
|
||||
def debug(s):
|
||||
message(s)
|
||||
|
||||
# copied from https://github.com/t-oster/roland_eps/blob/0abe785a30d5d5085dd3b5953b38239b1ff83358/tools/inkscape_extension/roland_eps_export.py
|
||||
def which(program, raiseError, extraPaths=[], subdir=None):
|
||||
"""
|
||||
find program in the $PATH environment variable and in $extraPaths.
|
||||
If $subdir is given, also look in the given subdirectory of each $PATH entry.
|
||||
"""
|
||||
pathlist=os.environ["PATH"].split(os.pathsep)
|
||||
if "nt" in os.name:
|
||||
pathlist.append(os.environ.get("ProgramFiles","C:\Program Files\\"))
|
||||
pathlist.append(os.environ.get("ProgramFiles(x86)","C:\Program Files (x86)\\"))
|
||||
pathlist.append("C:\Program Files\\") # needed for 64bit inkscape on 64bit Win7 machines
|
||||
pathlist.append(os.path.dirname(os.path.dirname(os.getcwd()))) # portable application in the current directory
|
||||
pathlist += extraPaths
|
||||
if subdir:
|
||||
pathlist = [os.path.join(p, subdir) for p in pathlist] + pathlist
|
||||
def is_exe(fpath):
|
||||
return os.path.isfile(fpath) and (os.access(fpath, os.X_OK) or fpath.endswith(".exe"))
|
||||
for path in pathlist:
|
||||
exe_file = os.path.join(path, program)
|
||||
if is_exe(exe_file):
|
||||
return exe_file
|
||||
if raiseError:
|
||||
raise Exception("Cannot find " + str(program) + " in any of these paths: " + str(pathlist) + ". Either the program is not installed, PATH is not set correctly, or this is a bug.")
|
||||
else:
|
||||
return None
|
||||
|
||||
# header
|
||||
# for debugging purposes you can open the resulting EPS file in Inkscape,
|
||||
# select all, ungroup multiple times
|
||||
# --> now you can view the exported lines in inkscape
|
||||
prefix="""
|
||||
%!PS-Adobe-3.0 EPSF-3.0
|
||||
%%LanguageLevel: 2
|
||||
%%BoundingBox -10000 -10000 10000 10000
|
||||
%%EndComments
|
||||
%%BeginSetup
|
||||
%%EndSetup
|
||||
%%BeginProlog
|
||||
% This code (until EndProlog) is from an inkscape-exported EPS, copyright unknown, see cairo-library
|
||||
save
|
||||
50 dict begin
|
||||
/q { gsave } bind def
|
||||
/Q { grestore } bind def
|
||||
/cm { 6 array astore concat } bind def
|
||||
/w { setlinewidth } bind def
|
||||
/J { setlinecap } bind def
|
||||
/j { setlinejoin } bind def
|
||||
/M { setmiterlimit } bind def
|
||||
/d { setdash } bind def
|
||||
/m { moveto } bind def
|
||||
/l { lineto } bind def
|
||||
/c { curveto } bind def
|
||||
/h { closepath } bind def
|
||||
/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto
|
||||
0 exch rlineto 0 rlineto closepath } bind def
|
||||
/S { stroke } bind def
|
||||
/f { fill } bind def
|
||||
/f* { eofill } bind def
|
||||
/n { newpath } bind def
|
||||
/W { clip } bind def
|
||||
/W* { eoclip } bind def
|
||||
/BT { } bind def
|
||||
/ET { } bind def
|
||||
/pdfmark where { pop globaldict /?pdfmark /exec load put }
|
||||
{ globaldict begin /?pdfmark /pop load def /pdfmark
|
||||
/cleartomark load def end } ifelse
|
||||
/BDC { mark 3 1 roll /BDC pdfmark } bind def
|
||||
/EMC { mark /EMC pdfmark } bind def
|
||||
/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def
|
||||
/Tj { show currentpoint cairo_store_point } bind def
|
||||
/TJ {
|
||||
{
|
||||
dup
|
||||
type /stringtype eq
|
||||
{ show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse
|
||||
} forall
|
||||
currentpoint cairo_store_point
|
||||
} bind def
|
||||
/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore
|
||||
cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def
|
||||
/Tf { pop /cairo_font exch def /cairo_font_matrix where
|
||||
{ pop cairo_selectfont } if } bind def
|
||||
/Td { matrix translate cairo_font_matrix matrix concatmatrix dup
|
||||
/cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point
|
||||
/cairo_font where { pop cairo_selectfont } if } bind def
|
||||
/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def
|
||||
cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def
|
||||
/g { setgray } bind def
|
||||
/rg { setrgbcolor } bind def
|
||||
/d1 { setcachedevice } bind def
|
||||
%%EndProlog
|
||||
%%Page: 1 1
|
||||
%%BeginPageSetup
|
||||
%%PageBoundingBox: -10000 -10000 10000 10000
|
||||
%%EndPageSetup
|
||||
% This is a severely crippled fucked-up pseudo-postscript for importing in Roland CutStudio
|
||||
% Do not even try to open it with something else
|
||||
% FIXME opening with inkscape currently does not show any objects, although it worked some time in the past
|
||||
|
||||
% Inkscape header, not used by cutstudio
|
||||
% Start
|
||||
q -10000 -10000 10000 10000 rectclip q
|
||||
|
||||
0 g
|
||||
0.286645 w
|
||||
0 J
|
||||
0 j
|
||||
[] 0.0 d
|
||||
4 M q
|
||||
% Cutstudio Start
|
||||
"""
|
||||
postfix="""
|
||||
% Cutstudio End
|
||||
|
||||
%this is necessary for CutStudio so that the last line isnt skipped:
|
||||
0 0 m
|
||||
|
||||
% Inkscape footer
|
||||
S Q
|
||||
Q Q
|
||||
showpage
|
||||
%%Trailer
|
||||
end restore
|
||||
%%EOF
|
||||
"""
|
||||
|
||||
class EPS2CutstudioEPS(inkex.OutputExtension):
|
||||
|
||||
def save(self, stream):
|
||||
def outputFromStack(stack, n, transformCoordinates=True):
|
||||
arr=stack[-(n+1):-1]
|
||||
if transformCoordinates:
|
||||
arrTransformed=[]
|
||||
for i in range(n//2):
|
||||
arrTransformed+=transform(arr[2*i], arr[2*i+1])
|
||||
return output(arrTransformed+[stack[-1]])
|
||||
else:
|
||||
return output(arr+[stack[-1]])
|
||||
|
||||
def transform(x, y):
|
||||
#debug("trafo from: {} {}".format(x, y))
|
||||
p=numpy.array([[float(x),float(y),1]]).transpose()
|
||||
multiply = lambda a, b: numpy.matmul(a, b)
|
||||
# concatenate transformations by multiplying: new = transformation x previousTransformtaion
|
||||
m=reduce(multiply, scalingStack[::-1])
|
||||
m=m.transpose()
|
||||
#debug("with {}".format(m))
|
||||
pnew = numpy.matmul(m, p)
|
||||
x=float(pnew[0])
|
||||
y=float(pnew[1])
|
||||
#debug("to: {} {}".format(x, y))
|
||||
return [x, y]
|
||||
|
||||
def toString(v):
|
||||
"""
|
||||
like str(), but gives the exact same output for floats across python2 and python3
|
||||
"""
|
||||
if isinstance(v, (type(float()), type(int()))):
|
||||
return repr(v)
|
||||
else:
|
||||
return str(v)
|
||||
def outputMoveto(x, y):
|
||||
[xx, yy]=transform(x, y)
|
||||
return output([toString(xx), toString(yy), "m"])
|
||||
|
||||
def outputLineto(x, y):
|
||||
[xx, yy]=transform(x, y)
|
||||
return output([toString(xx), toString(yy), "l"])
|
||||
|
||||
def output(array):
|
||||
array=list(map(toString, array))
|
||||
output=" ".join(array)
|
||||
#debug("OUTPUT: "+output)
|
||||
return output + "\n"
|
||||
|
||||
if os.name=="nt": # windows
|
||||
INKSCAPEBIN = which("inkscape.exe", True, subdir="Inkscape")
|
||||
else:
|
||||
INKSCAPEBIN=which("inkscape", True)
|
||||
filename = self.options.input_file
|
||||
shutil.copyfile(filename, filename+".filtered.svg")
|
||||
cmd = [INKSCAPEBIN, "-T", "--export-ignore-filters", "--export-area-drawing", "--export-filename="+filename+".inkscape.eps", filename+".filtered.svg"]
|
||||
inkscape_eps_file = filename + ".inkscape.eps"
|
||||
assert 0 == subprocess.call(cmd, stderr=DEVNULL), 'EPS conversion failed: command returned error: ' + '"' + '" "'.join(cmd) + '"'
|
||||
assert os.path.exists(inkscape_eps_file), 'EPS conversion failed: command did not create result file: ' + '"' + '" "'.join(cmd) + '"'
|
||||
stack=[]
|
||||
scalingStack=[numpy.identity(3)]
|
||||
lastMoveCoordinates=None
|
||||
outputStr=prefix
|
||||
inputFile=open(inkscape_eps_file)
|
||||
for line in inputFile.readlines():
|
||||
line=line.strip()
|
||||
if line.startswith("%"):
|
||||
# comment line
|
||||
continue
|
||||
if line.endswith("re W n"):
|
||||
continue # ignore clipping rectangle
|
||||
#debug(line)
|
||||
for item in line.split(" "):
|
||||
item=item.strip()
|
||||
if item=="":
|
||||
continue
|
||||
#debug("INPUT: " + item.__repr__())
|
||||
stack.append(item)
|
||||
if item=="h": # close path
|
||||
assert lastMoveCoordinates, "closed path before first moveto"
|
||||
outputStr += outputLineto(float(lastMoveCoordinates[0]), float(lastMoveCoordinates[1]))
|
||||
elif item == "c": # bezier curveto
|
||||
outputStr += outputFromStack(stack, 6)
|
||||
stack=[]
|
||||
elif item=="re": # rectangle
|
||||
x=float(stack[-5])
|
||||
y=float(stack[-4])
|
||||
dx=float(stack[-3])
|
||||
dy=float(stack[-2])
|
||||
outputStr += outputMoveto(x, y)
|
||||
outputStr += outputLineto(x+dx, y)
|
||||
outputStr += outputLineto(x+dx, y+dy)
|
||||
outputStr += outputLineto(x, y+dy)
|
||||
outputStr += outputLineto(x, y)
|
||||
elif item=="cm": # matrix transformation
|
||||
newTrafo=numpy.array([[float(stack[-7]), float(stack[-6]), 0], [float(stack[-5]), float(stack[-4]), 0], [float(stack[-3]), float(stack[-2]), 1]])
|
||||
#debug("applying trafo "+str(newTrafo))
|
||||
scalingStack[-1] = numpy.matmul(scalingStack[-1], newTrafo)
|
||||
elif item=="q": # save graphics state to stack
|
||||
scalingStack.append(numpy.identity(3))
|
||||
elif item=="Q": # pop graphics state from stack
|
||||
scalingStack.pop()
|
||||
elif item in ["m", "l"]:
|
||||
if item=="m": # moveto
|
||||
lastMoveCoordinates=stack[-3:-1]
|
||||
elif item=="l": # lineto
|
||||
pass
|
||||
outputStr += outputFromStack(stack, 2)
|
||||
stack=[]
|
||||
else:
|
||||
pass # do nothing
|
||||
outputStr += postfix
|
||||
inputFile.close()
|
||||
stream.write(outputStr.encode('utf-8'))
|
||||
|
||||
if __name__ == '__main__':
|
||||
EPS2CutstudioEPS().run()
|
Reference in New Issue
Block a user