Hi all,
This is my first post to the Inkscape developer
list, so - hello! I've been using Inkscape for various
server-side operations as part of a project I'm currently
working on, and I believe I've run into the limits of the
existing scripting / extensions capability. However, I'll
describe my requirements, problem, current solution, and
proposed improvements, and see what you think.
The requirements: I wish to perform "deep
subtraction" of one pre-defined path (let's call it P) from an
SVG - that is, to perform a Boolean difference operation
against each path within the SVG (let's call them S1, S2, ...
Sn) such that a 'hole' (in the shape of my path) is punched
through all of the SVG layers.
The problem: Inkscape Boolean difference
operations operate on pairs of paths, such that the uppermost
of the two paths is subtracted from the lower path. The
operation may only be performed on selections of two paths
(i.e. you can't select 10 paths and have the uppermost path be
subtracted from all of the lower 9 simultaneously).
My current solution: The obvious approach is to
simply perform the Boolean operation once for each path in the
SVG, cloning the path P to allow it to be subtracted again
each time. That is:
Create P
Perform S1 - P
Create P
Perform S2 - P
...
Create P
Perform Sn - P
This results in every path in the SVG having P
subtracted, which is exactly what I want. To implement the
"Create P" operation, I've written a Python extension that
inserts a <path> element into the document (i.e. I can
create P by simply executing this extension script within
Inkscape). To perform a difference operation, I can use the
(somewhat maligned?) command line interface with
--select <id of S1> --select <id of P>
--verb SelectionDiff
and I can automatically call my "create P"
extension with --verb <my.extension.name.noprefs>.
I therefore just have to ensure all paths in the
source SVG have IDs, extract these IDs, and then chain a big
long command line together to perform all the creation,
selection, and Boolean subtractions. I accomplish the ID
extraction with my own Python script (running independently
from Inkscape, simply using normal XML parsing code) and get
that script to concoct a long string of command-line
arguments.
The obvious problem here is that for files with
more than a few IDs, I run into the command-line argument
length limit. I have hacked around this by editing Inkscape's
main.cpp file and allowing it to take --select / --verb
arguments from a text file instead (note that --shell does not
do the same thing - it still requires all commands to be on
one shell-line, and the line length has a limit). Clearly this
is not particularly clever, although it does work - it means I
have my own special build of Inkscape and it uses an extremely
clunky "scripting" mechanism.
The proposed improvements: I have looked at
alternative solutions and have come up with the following:
- I could edit the C++ code for Boolean
operations such that the difference operation works on more
than one path. However this is very specific to my problem,
and it's likely that I'll want to perform other Inkscape
automation tasks in future that don't use the Boolean ops.
- Allow further scripting of Inkscape through a
Python API - this is my preferred solution, and also, it
seems, several other peoples'. The major drawback is that this
is likely to be more coding work. However, I have a suggestion
that will solve my immediate problem and potentially be useful
to others. If I wrote a Python API that allowed Inkscape
extension scripts to execute Inkscape verbs and selections,
then I could perform all of the necessary operations inside a
single Python extension. I could then run the extension from
the command line in the usual way (--verb
my.extension.name.noprefs). Initially this might take the form
of an extra couple of functions on the Python inkex.Effect
object:
- do_verb(verb_name)
- select_ids(id_list)
Then any Inkscape Effect extensions can execute
verbs and modify selections as they see fit.
Does this sound like a good plan? Any other input?
I'm happy to write the code for this if you think it would be
generally useful, it seems a bit limiting at the moment that
effects essentially have to modify the raw XML document
themselves to get any useful work done. If the "do_verb"
function was modified to take an argument list (along with the
appropriate C++ functions), then it would allow for even
richer GUI-free interaction (e.g. automation of "Save As"
operations and so on).
Thanks for reading such a long message,
Eric