User:Mr.Z-man/SVG/source
< User:Mr.Z-man | SVG
Source code and brief installation instructions
Notes
editRequirements
edit- A Unix-based system
- A sufficiently recent version of Inkscape (it must support the
--shell
command line option) - Python with python-daemon
- A C compiler
- GLib
Installation
edit- Copy the 2 files below onto your server
- Change
SOCK_LOCATION
in both programs to a different location if desired - Compile the C client program
- If GLib is installed through a package and gcc is used:
gcc -o/path/to/compiled/program `pkg-config --cflags --libs glib-2.0` filename.c
- Set up the python program to run automatically (using cron or a similar utility)
- Add the following lines to LocalSettings.php
$wgSVGConverters['inkscape-daemon'] = '/path/to/compiled/program -z -w $width -f $input -e $output';
$wgSVGConverter = 'inkscape-daemon';
Caveats
edit- This is highly experimental and not recommended for a production server.
- The Python program does not automatically restart if it crashes for any reason.
Python server
editimport SocketServer
import subprocess
import os
import stat
import daemon
SOCK_LOCATION = '/usr/tmp/ink.sock'
def main():
try:
server = InkscapeServer(SOCK_LOCATION, InkscapeRequestHandler)
server.serve_forever(poll_interval=0.1)
finally:
os.remove(SOCK_LOCATION)
class InkscapeServer(SocketServer.UnixStreamServer):
def __init__(self, server_address, RequestHandlerClass):
SocketServer.UnixStreamServer.__init__(self, server_address, RequestHandlerClass)
self.proc = subprocess.Popen(['inkscape', '--shell'], stderr=subprocess.STDOUT, stdout=subprocess.PIPE, stdin=subprocess.PIPE)
readToEnd(self.proc.stdout) # version stuff
os.chmod(server_address, stat.S_IRWXO|stat.S_IRWXG|stat.S_IRWXU) # chmod 777 /path/to/socket
self.requestcount = 0
class InkscapeRequestHandler(SocketServer.StreamRequestHandler):
def handle(self):
args = self.rfile.readline()
self.server.proc.stdin.write(args)
ret = readToEnd(self.server.proc.stdout)
self.wfile.write(ret)
def finish(self): # Inkscape slowly leaks memory, if it leaks too much it gets /really/ slow
self.server.requestcount += 1
if self.server.requestcount > 50 or self.server.proc.returncode is not None: # also check if inksccape crashed
self.server.requestcount = 0
self.server.proc.terminate()
self.server.proc = subprocess.Popen(['inkscape', '--shell'], stderr=subprocess.STDOUT, stdout=subprocess.PIPE, stdin=subprocess.PIPE)
readToEnd(self.server.proc.stdout)
# Since Inkscape stays running, we never get an EOF
def readToEnd(buf):
ret = ''
lastchar = ''
while True:
char = buf.readline(1)
if char == '>' and lastchar == '\n':
break
ret += char
lastchar = char
return ret
if __name__ == "__main__":
with daemon.DaemonContext():
main()
C client
edit#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <glib.h>
#define SOCK_LOCATION "/usr/tmp/ink.sock"
int main ( int argc, char * argv[] ) {
if (!argv[1]) {
printf("No args given\n");
exit(1);
}
int sock, retval, len;
char args[5000]; // These should probably use less-arbitrary numbers
char ret[5000];
char *arg;
int returncode = 0;
int i=1;
while(arg = argv[i]) {
arg = g_shell_quote(arg);
strncat(args, arg, strlen(arg));
strncat(args, " ", 1);
i++;
}
strncat(args, "\n", 1);
struct sockaddr_un remote;
if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
printf("Socket error\n");
exit(1);
}
remote.sun_family = AF_UNIX;
strcpy(remote.sun_path, SOCK_LOCATION);
len = strlen(remote.sun_path) + sizeof(remote.sun_family);
if (connect(sock, (struct sockaddr *)&remote, len) == -1) {
printf("Unable to connect to socket\n");
exit(1);
}
if (send(sock, args, strlen(args)+1, 0) == -1) {
printf("Error during sending of data\n");
exit(1);
}
if ( (retval=recv(sock, ret, 5000, 0)) > 0) {
ret[retval] = '\0';
printf(ret);
} else {
if (retval < 0) {
printf("Error during receiving of data\n");
} else {
printf("Server closed connection\n");
}
exit(1);
}
// If inkscape threw an error, set the returncode to 1. Inkscape errors
// follow a fairly standard format:
// ** (inkscape:PID): WARNING ** Error message
if (strstr(ret, "\n**") != NULL) {
returncode = 1;
}
return returncode;
}