Skip to content

Commit

Permalink
Fix Visicut calling inkscape in an AppImage.
Browse files Browse the repository at this point in the history
In Ubuntu 20.04, this worked flawlessly. But only by chance. We use libraries from the host system, together with the binary inside the mounted appimage.
in Ubintu 22.04, this crashes:

/tmp/.mount_inkscaYGPL8G/usr/bin/inkscape --version
 /tmp/.mount_inkscaYGPL8G/usr/bin/inkscape: error while loading shared libraries: libboost_filesystem.so.1.71.0: cannot open shared object file: No such file or directory

The fix is to not call the binary directly, but the AppRun scrit, which nicely prepares the environment. AppRun also prints a message for the user to stdout, (instead of stderr).
We now need to filter this, when parsing output from e.g. --version:

/tmp/.mount_inkscaYGPL8G/AppRun --version 2>/dev/null
 You should not use AppImage in production, but you can speedup the AppImage by following this guide: https://inkscape.org/learn/appimage/
 Inkscape 1.3.2 (091e20e, 2023-11-25)
  • Loading branch information
jnweiger committed Apr 8, 2024
1 parent 8797012 commit e435f2e
Showing 1 changed file with 24 additions and 5 deletions.
29 changes: 24 additions & 5 deletions tools/inkscape_extension/visicut_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,12 +141,19 @@ def is_exe(fpath):
def inkscape_version():
"""Return Inkscape version number as float, e.g. version "0.92.4" --> return: float 0.92"""
version = subprocess.check_output([INKSCAPEBIN, "--version"], stderr=DEVNULL).decode('ASCII', 'ignore')
if not version.startswith("Inkscape "):
## When inkscape lives in an appimage, AppRun may pollute stdout with extra information.
# Go through all the lines, and find the one that starts with Inkscape
lines = version.splitlines()
for version in lines:
if version.startswith("Inkscape "):
break
assert version.startswith("Inkscape ")
match = re.match("Inkscape ([0-9]+\.[0-9]+).*", version)
assert match is not None
version_float = float(match.group(1))
return version_float



# Strip SVG to only contain selected elements, convert objects to paths, unlink clones
Expand All @@ -157,7 +164,7 @@ def inkscape_version():
# The idea is similar to http://bazaar.launchpad.net/~nikitakit/inkscape/svg2sif/view/head:/share/extensions/synfig_prepare.py#L181 , but more primitive - there is no need for more complicated preprocessing here
def stripSVG_inkscape(src, dest, elements):
version = inkscape_version()

# create temporary file for opening with inkscape.
# delete this file later so that it will disappear from the "recently opened" list.
tmpfile = tempfile.NamedTemporaryFile(delete=False, prefix='temp-visicut-', suffix='.svg')
Expand Down Expand Up @@ -199,8 +206,8 @@ def stripSVG_inkscape(src, dest, elements):
verbs += ["UnhideAllInAllLayers", "EditInvertInAllLayers", "EditDelete", "EditSelectAllInAllLayers", "EditUnlinkClone", "ObjectToPath", "FileSave"]
# --verb=action1;action2;...
command += ["--verb=" + ";".join(verbs)]


DEBUG = False
if DEBUG:
# Inkscape sometimes silently ignores wrong verbs, so we need to double-check that everything's right
Expand Down Expand Up @@ -248,7 +255,7 @@ def stripSVG_inkscape(src, dest, elements):
actions += ["export-area-page"]

command = [INKSCAPEBIN, tmpfile, "--export-overwrite", "--actions=" + ";".join(actions)]

try:
#sys.stderr.write(" ".join(command))
# run inkscape, buffer output
Expand Down Expand Up @@ -326,6 +333,17 @@ def get_original_filename(filename):
VISICUTBIN = which("VisiCut.Linux", [VISICUTDIR, "/usr/share/visicut"])
INKSCAPEBIN = which("inkscape", [INKSCAPEDIR])

## Test if this inkscape is in an appimage.
# We detect this by checking for an AppRun file, in one of the parent folders of our INKSCAPEBIN.
# If so, replace INKSCAPEBIN with AppRun, as this is the only safe way to call inkscape.
# (a direct call mixes libraries from the host system with the appimage, may or may not work.)
dir = os.path.split(INKSCAPEBIN)[0]
while dir != '/':
if os.path.exists(os.path.join(dir, "AppRun")):
INKSCAPEBIN = os.path.join(dir, "AppRun")
break
dir = os.path.split(dir)[0]

tmpdir = tempfile.mkdtemp(prefix='temp-visicut-')
dest_filename = os.path.join(tmpdir, get_original_filename(filename))

Expand Down Expand Up @@ -384,3 +402,4 @@ def get_original_filename(filename):
sys.exit(1)

# TODO (complicated, probably WONTFIX): cleanup temporary directories -- this is really difficult because we need to make sure that visicut no longer needs the file, even for reloading!
# - maybe add the PID od the running visicut, then we can detect orphaned temp direcories.

0 comments on commit e435f2e

Please sign in to comment.