User:Mr.Z-man/SVG/source

From MediaWiki.org
Jump to: navigation, search

Source code and brief installation instructions

Contents

[edit] Notes

[edit] Requirements

  • 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

[edit] Installation

  1. Copy the 2 files below onto your server
  2. Change SOCK_LOCATION in both programs to a different location if desired
  3. 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
  4. Set up the python program to run automatically (using cron or a similar utility)
  5. Add the following lines to LocalSettings.php
$wgSVGConverters['inkscape-daemon'] = '/path/to/compiled/program -z -w $width -f $input -e $output';
$wgSVGConverter = 'inkscape-daemon';

[edit] Caveats

  • This is highly experimental and not recommended for a production server.
  • The Python program does not automatically restart if it crashes for any reason.

[edit] Python server

import 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()

[edit] C client

#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;
}
Personal tools
Namespaces

Variants
Actions
Navigation
Support
Download
Development
Communication
Print/export
Toolbox