simplified "open in roland cutstudio"
This commit is contained in:
parent
06f96fe1e5
commit
ab25f2ad94
@ -22,49 +22,34 @@ along with this program; if not, write to the Free Software
|
|||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
'''
|
'''
|
||||||
|
|
||||||
# The source code is a horrible mess. I apologize for your inconvenience, but hope that it still helps. Feel free to improve :-)
|
'''
|
||||||
# Keep everything python2 compatible as long as people out there are using Inkscape <= 0.92.4!
|
KNOWN BUGS:
|
||||||
|
WONTFIX: clipping of paths doesnt work
|
||||||
|
WONTFIX: if there is any object with opacity != 100%, inkscape exports some objects as bitmaps. They will disappear in CutStudio! The same problem also occurs if the alpha value of stroke or fill color is not 100%.
|
||||||
|
WONTFIX: filters (e.g. blur) are not supported
|
||||||
|
'''
|
||||||
|
|
||||||
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 sys
|
||||||
import os
|
import os
|
||||||
from subprocess import Popen
|
|
||||||
import subprocess
|
import subprocess
|
||||||
|
from subprocess import Popen
|
||||||
|
from functools import reduce
|
||||||
|
from pathlib import Path
|
||||||
import shutil
|
import shutil
|
||||||
import numpy
|
import numpy
|
||||||
from functools import reduce
|
|
||||||
import atexit
|
import atexit
|
||||||
import filecmp
|
import filecmp
|
||||||
try:
|
|
||||||
from pathlib import Path
|
|
||||||
except ImportError:
|
|
||||||
# Workaround for Python < 3.5
|
|
||||||
class fakepath:
|
|
||||||
def home(self):
|
|
||||||
return os.path.expanduser("~")
|
|
||||||
Path = fakepath()
|
|
||||||
try:
|
|
||||||
from functools import lru_cache
|
|
||||||
except ImportError:
|
|
||||||
def lru_cache():
|
|
||||||
def wrapper(func):
|
|
||||||
return func
|
|
||||||
return wrapper
|
|
||||||
import tempfile
|
import tempfile
|
||||||
|
import warnings
|
||||||
|
import inkex.command
|
||||||
|
from inkex.command import inkscape
|
||||||
|
|
||||||
DEVNULL = open(os.devnull, 'w')
|
DEVNULL = open(os.devnull, 'w')
|
||||||
atexit.register(DEVNULL.close)
|
atexit.register(DEVNULL.close)
|
||||||
|
|
||||||
def message(s):
|
def message(s):
|
||||||
sys.stderr.write(s+"\n")
|
sys.stderr.write(s+"\n")
|
||||||
|
|
||||||
def debug(s):
|
def debug(s):
|
||||||
message(s)
|
message(s)
|
||||||
|
|
||||||
@ -94,17 +79,6 @@ def which(program, raiseError, extraPaths=[], subdir=None):
|
|||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# mostly copied from https://github.com/t-oster/VisiCut/blob/0abe785a30d5d5085dd3b5953b38239b1ff83358/tools/inkscape_extension/visicut_export.py
|
|
||||||
@lru_cache()
|
|
||||||
def inkscape_version():
|
|
||||||
"""determine if Inkscape is version 0 or 1"""
|
|
||||||
version = subprocess.check_output([INKSCAPEBIN, "--version"], stderr=DEVNULL).decode('ASCII', 'ignore')
|
|
||||||
assert version.startswith("Inkscape ")
|
|
||||||
if version.startswith("Inkscape 0"):
|
|
||||||
return 0
|
|
||||||
else:
|
|
||||||
return 1
|
|
||||||
|
|
||||||
# copied from https://github.com/t-oster/VisiCut/blob/0abe785a30d5d5085dd3b5953b38239b1ff83358/tools/inkscape_extension/visicut_export.py
|
# copied from https://github.com/t-oster/VisiCut/blob/0abe785a30d5d5085dd3b5953b38239b1ff83358/tools/inkscape_extension/visicut_export.py
|
||||||
# Strip SVG to only contain selected elements, convert objects to paths, unlink clones
|
# Strip SVG to only contain selected elements, convert objects to paths, unlink clones
|
||||||
# Inkscape version: takes care of special cases where the selected objects depend on non-selected ones.
|
# Inkscape version: takes care of special cases where the selected objects depend on non-selected ones.
|
||||||
@ -115,72 +89,34 @@ def inkscape_version():
|
|||||||
def stripSVG_inkscape(src, dest, elements):
|
def stripSVG_inkscape(src, dest, elements):
|
||||||
# create temporary file for opening with inkscape.
|
# create temporary file for opening with inkscape.
|
||||||
# delete this file later so that it will disappear from the "recently opened" list.
|
# delete this file later so that it will disappear from the "recently opened" list.
|
||||||
tmpfile = tempfile.NamedTemporaryFile(delete=False, prefix='temp-visicut-', suffix='.svg')
|
tmpfile = tempfile.NamedTemporaryFile(delete=False, prefix='temp-cutstudio-', suffix='.svg')
|
||||||
tmpfile.close()
|
tmpfile.close()
|
||||||
tmpfile = tmpfile.name
|
tmpfile = tmpfile.name
|
||||||
import shutil
|
|
||||||
shutil.copyfile(src, tmpfile)
|
shutil.copyfile(src, tmpfile)
|
||||||
|
actions_list=[]
|
||||||
|
actions_list.append("ObjectToPath")
|
||||||
|
actions_list.append("UnlockAllInAllLayers")
|
||||||
|
|
||||||
|
if elements: # something is selected
|
||||||
if inkscape_version() == 0:
|
actions_list.append("select:{}".format(",".join(elements)))
|
||||||
# inkscape 0.92 long-term-support release. Will be in Linux distributions until 2025 or so
|
|
||||||
# Selection commands: select items, invert selection, delete
|
|
||||||
selection = []
|
|
||||||
for el in elements:
|
|
||||||
selection += ["--select=" + el]
|
|
||||||
|
|
||||||
if len(elements) > 0:
|
|
||||||
# selection += ["--verb=FitCanvasToSelection"] # TODO add a user configuration option whether to keep the page size (and by this the position relative to the page)
|
|
||||||
selection += ["--verb=EditInvertInAllLayers", "--verb=EditDelete"]
|
|
||||||
|
|
||||||
|
|
||||||
hidegui = ["--without-gui"]
|
|
||||||
|
|
||||||
# currently this only works with gui because of a bug in inkscape: https://bugs.launchpad.net/inkscape/+bug/843260
|
|
||||||
hidegui = []
|
|
||||||
|
|
||||||
command = [INKSCAPEBIN] + hidegui + [tmpfile, "--verb=UnlockAllInAllLayers", "--verb=UnhideAllInAllLayers"] + selection + ["--verb=EditSelectAllInAllLayers", "--verb=EditUnlinkClone", "--verb=ObjectToPath", "--verb=FileSave", "--verb=FileQuit"]
|
|
||||||
else:
|
else:
|
||||||
# Inkscape 1.0, to be released ca 2020
|
actions_list.append("EditSelectAllInAllLayers")
|
||||||
# inkscape --select=... --verbs=...
|
actions_list.append("UnhideAllInAllLayers")
|
||||||
# (see inkscape --help, inkscape --verb-list)
|
actions_list.append("EditInvertInAllLayers")
|
||||||
command = [INKSCAPEBIN, tmpfile, "--batch-process"]
|
actions_list.append("EditDelete")
|
||||||
verbs = ["ObjectToPath", "UnlockAllInAllLayers"]
|
actions_list.append("EditSelectAllInAllLayers")
|
||||||
if elements: # something is selected
|
actions_list.append("EditUnlinkClone")
|
||||||
# --select=object1,object2,object3,...
|
actions_list.append("ObjectToPath")
|
||||||
command += ["--select=" + ",".join(elements)]
|
actions_list.append("FileSave")
|
||||||
else:
|
actions = ";".join(actions_list)
|
||||||
verbs += ["EditSelectAllInAllLayers"]
|
cli_output = inkscape(tmpfile, "--batch-process", actions=actions) #process recent file
|
||||||
verbs += ["UnhideAllInAllLayers", "EditInvertInAllLayers", "EditDelete", "EditSelectAllInAllLayers", "EditUnlinkClone", "ObjectToPath", "FileSave"]
|
if len(cli_output) > 0:
|
||||||
# --verb=action1;action2;...
|
self.msg("Inkscape returned the following output when trying to run the file export; the file export may still have worked:")
|
||||||
command += ["--verb=" + ";".join(verbs)]
|
self.msg(cli_output)
|
||||||
|
|
||||||
|
|
||||||
DEBUG = False
|
|
||||||
if DEBUG:
|
|
||||||
# Inkscape sometimes silently ignores wrong verbs, so we need to double-check that everything's right
|
|
||||||
for verb in verbs:
|
|
||||||
verb_list = [line.split(":")[0] for line in subprocess.check_output([INKSCAPEBIN, "--verb-list"], stderr=DEVNULL).split("\n")]
|
|
||||||
if verb not in verb_list:
|
|
||||||
sys.stderr.write("Inkscape does not have the verb '{}'. Please report this as a VisiCut bug.".format(verb))
|
|
||||||
|
|
||||||
inkscape_output = "(not yet run)"
|
|
||||||
try:
|
|
||||||
#sys.stderr.write(" ".join(command))
|
|
||||||
# run inkscape, buffer output
|
|
||||||
inkscape = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
|
||||||
inkscape_output = inkscape.communicate()[0]
|
|
||||||
if inkscape.returncode != 0:
|
|
||||||
sys.stderr.write("Error: cleaning the document with inkscape failed. Something might still be shown in visicut, but it could be incorrect.\nInkscape's output was:\n" + inkscape_output)
|
|
||||||
except:
|
|
||||||
sys.stderr.write("Error: cleaning the document with inkscape failed. Something might still be shown in visicut, but it could be incorrect. Exception information: \n" + str(sys.exc_info()[0]) + "Inkscape's output was:\n" + inkscape_output)
|
|
||||||
|
|
||||||
# move output to the intended destination filename
|
# move output to the intended destination filename
|
||||||
os.rename(tmpfile, dest)
|
os.rename(tmpfile, dest)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# header
|
# header
|
||||||
# for debugging purposes you can open the resulting EPS file in Inkscape,
|
# for debugging purposes you can open the resulting EPS file in Inkscape,
|
||||||
# select all, ungroup multiple times
|
# select all, ungroup multiple times
|
||||||
@ -282,6 +218,7 @@ end restore
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def OpenInRolandCutStudio(src, dest, mirror=False):
|
def OpenInRolandCutStudio(src, dest, mirror=False):
|
||||||
|
|
||||||
def outputFromStack(stack, n, transformCoordinates=True):
|
def outputFromStack(stack, n, transformCoordinates=True):
|
||||||
arr=stack[-(n+1):-1]
|
arr=stack[-(n+1):-1]
|
||||||
if transformCoordinates:
|
if transformCoordinates:
|
||||||
@ -291,6 +228,7 @@ def OpenInRolandCutStudio(src, dest, mirror=False):
|
|||||||
return output(arrTransformed+[stack[-1]])
|
return output(arrTransformed+[stack[-1]])
|
||||||
else:
|
else:
|
||||||
return output(arr+[stack[-1]])
|
return output(arr+[stack[-1]])
|
||||||
|
|
||||||
def transform(x, y):
|
def transform(x, y):
|
||||||
#debug("trafo from: {} {}".format(x, y))
|
#debug("trafo from: {} {}".format(x, y))
|
||||||
p=numpy.array([[float(x),float(y),1]]).transpose()
|
p=numpy.array([[float(x),float(y),1]]).transpose()
|
||||||
@ -304,6 +242,7 @@ def OpenInRolandCutStudio(src, dest, mirror=False):
|
|||||||
y=float(pnew[1])
|
y=float(pnew[1])
|
||||||
#debug("to: {} {}".format(x, y))
|
#debug("to: {} {}".format(x, y))
|
||||||
return [x, y]
|
return [x, y]
|
||||||
|
|
||||||
def toString(v):
|
def toString(v):
|
||||||
"""
|
"""
|
||||||
like str(), but gives the exact same output for floats across python2 and python3
|
like str(), but gives the exact same output for floats across python2 and python3
|
||||||
@ -312,17 +251,21 @@ def OpenInRolandCutStudio(src, dest, mirror=False):
|
|||||||
return repr(v)
|
return repr(v)
|
||||||
else:
|
else:
|
||||||
return str(v)
|
return str(v)
|
||||||
|
|
||||||
def outputMoveto(x, y):
|
def outputMoveto(x, y):
|
||||||
[xx, yy]=transform(x, y)
|
[xx, yy]=transform(x, y)
|
||||||
return output([toString(xx), toString(yy), "m"])
|
return output([toString(xx), toString(yy), "m"])
|
||||||
|
|
||||||
def outputLineto(x, y):
|
def outputLineto(x, y):
|
||||||
[xx, yy]=transform(x, y)
|
[xx, yy]=transform(x, y)
|
||||||
return output([toString(xx), toString(yy), "l"])
|
return output([toString(xx), toString(yy), "l"])
|
||||||
|
|
||||||
def output(array):
|
def output(array):
|
||||||
array=list(map(toString, array))
|
array=list(map(toString, array))
|
||||||
output=" ".join(array)
|
output=" ".join(array)
|
||||||
#debug("OUTPUT: "+output)
|
#debug("OUTPUT: "+output)
|
||||||
return output + "\n"
|
return output + "\n"
|
||||||
|
|
||||||
stack=[]
|
stack=[]
|
||||||
scalingStack=[numpy.identity(3)]
|
scalingStack=[numpy.identity(3)]
|
||||||
if mirror:
|
if mirror:
|
||||||
@ -383,13 +326,6 @@ def OpenInRolandCutStudio(src, dest, mirror=False):
|
|||||||
outputFile.close()
|
outputFile.close()
|
||||||
inputFile.close()
|
inputFile.close()
|
||||||
|
|
||||||
if os.name=="nt": # windows
|
|
||||||
INKSCAPEBIN = which("inkscape.exe", True, subdir="Inkscape")
|
|
||||||
else:
|
|
||||||
INKSCAPEBIN=which("inkscape", True)
|
|
||||||
|
|
||||||
assert os.path.isfile(INKSCAPEBIN), "cannot find inkscape binary " + INKSCAPEBIN
|
|
||||||
|
|
||||||
selectedElements=[]
|
selectedElements=[]
|
||||||
for arg in sys.argv[1:]:
|
for arg in sys.argv[1:]:
|
||||||
if arg[0] == "-":
|
if arg[0] == "-":
|
||||||
@ -406,19 +342,21 @@ else:
|
|||||||
# only take selected elements
|
# only take selected elements
|
||||||
stripSVG_inkscape(src=filename, dest=filename+".filtered.svg", elements=selectedElements)
|
stripSVG_inkscape(src=filename, dest=filename+".filtered.svg", elements=selectedElements)
|
||||||
|
|
||||||
if inkscape_version() == 0:
|
actions_list=[]
|
||||||
# Inkscape 0.92.4
|
actions_list.append("export-text-to-path")
|
||||||
cmd = [INKSCAPEBIN,"-z",filename+".filtered.svg","-T", "--export-ignore-filters", "--export-eps="+filename+".inkscape.eps"]
|
actions_list.append("export-ignore-filters")
|
||||||
else:
|
actions_list.append("export-area-drawing")
|
||||||
# Inkscape 1.0
|
actions_list.append("export-filename:{}".format(filename + ".inkscape.eps"))
|
||||||
cmd = [INKSCAPEBIN, "-T", "--export-ignore-filters", "--export-area-drawing", "--export-filename="+filename+".inkscape.eps", filename+".filtered.svg"]
|
actions_list.append("export-do")
|
||||||
|
actions = ";".join(actions_list)
|
||||||
|
cli_output = inkscape(filename + ".filtered.svg", actions=actions) #process recent file
|
||||||
|
if len(cli_output) > 0:
|
||||||
|
self.msg("Inkscape returned the following output when trying to run the file export; the file export may still have worked:")
|
||||||
|
self.msg(cli_output)
|
||||||
|
|
||||||
inkscape_eps_file = filename + ".inkscape.eps"
|
inkscape_eps_file = filename + ".inkscape.eps"
|
||||||
|
|
||||||
#debug(" ".join(cmd))
|
|
||||||
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) + '"'
|
assert os.path.exists(inkscape_eps_file), 'EPS conversion failed: command did not create result file: ' + '"' + '" "'.join(cmd) + '"'
|
||||||
|
|
||||||
|
|
||||||
if "--selftest" in sys.argv:
|
if "--selftest" in sys.argv:
|
||||||
# used for unit-testing: fixed location of output file
|
# used for unit-testing: fixed location of output file
|
||||||
destination = "./test-output-actual.cutstudio.eps"
|
destination = "./test-output-actual.cutstudio.eps"
|
||||||
@ -437,7 +375,10 @@ if "--selftest" in sys.argv:
|
|||||||
|
|
||||||
if os.name=="nt":
|
if os.name=="nt":
|
||||||
DETACHED_PROCESS = 8 # start as "daemon"
|
DETACHED_PROCESS = 8 # start as "daemon"
|
||||||
Popen([which("CutStudio\CutStudio.exe", True), "/import", destination], creationflags=DETACHED_PROCESS, close_fds=True)
|
warnings.simplefilter('ignore', ResourceWarning) #suppress "enable tracemalloc to get the object allocation traceback"
|
||||||
|
proc = Popen([which("CutStudio\CutStudio.exe", True), "/import", destination], creationflags=DETACHED_PROCESS, close_fds=True)
|
||||||
|
#warnings.simplefilter("default", ResourceWarning)
|
||||||
|
|
||||||
else: #check if we have access to "wine"
|
else: #check if we have access to "wine"
|
||||||
CUTSTUDIO_C_DRIVE = str(Path.home()) + "/.wine/drive_c/"
|
CUTSTUDIO_C_DRIVE = str(Path.home()) + "/.wine/drive_c/"
|
||||||
CUTSTUDIO_PATH_LINUX_WINE = CUTSTUDIO_C_DRIVE + "Program Files (x86)/CutStudio/CutStudio.exe"
|
CUTSTUDIO_PATH_LINUX_WINE = CUTSTUDIO_C_DRIVE + "Program Files (x86)/CutStudio/CutStudio.exe"
|
||||||
@ -454,9 +395,3 @@ else: #check if we have access to "wine"
|
|||||||
"Please open that with CutStudio manually. \n\n" + \
|
"Please open that with CutStudio manually. \n\n" + \
|
||||||
"Tip: On Linux, you can use 'wine' to install CutStudio 3.10. Then, the file will be directly opened with CutStudio. \n" + \
|
"Tip: On Linux, you can use 'wine' to install CutStudio 3.10. Then, the file will be directly opened with CutStudio. \n" + \
|
||||||
" Diagnostic information: \n" + str(exc))
|
" Diagnostic information: \n" + str(exc))
|
||||||
#os.popen("/usr/bin/xdg-open " + filename) #os.popen is deprecated. Use subprocess.Popen
|
|
||||||
#Popen(["inkscape", filename+".filtered.svg"], stderr=DEVNULL)
|
|
||||||
#Popen(["inkscape", filename+".cutstudio.eps"])
|
|
||||||
#os.unlink(filename+".filtered.svg")
|
|
||||||
#os.unlink(filename)
|
|
||||||
#os.unlink(filename+".cutstudio.eps")
|
|
Reference in New Issue
Block a user