关于svg:使用perl的Inkscape shell

Using the Inkscape shell from perl

Inkscape有一个这样调用的shell模式

1
inkscape --shell

您可以在其中执行如下命令:

1
some_svg_file.svg -e some_png_output.png -y 1.0 -b #ffffff -D -d 150

它将生成一个PNG文件,或者像这样:

1
/home/simone/some_text.svg -S

它为您提供返回消息中文件中所有元素的边界框,如下所示

1
2
3
4
 svg2,0.72,-12.834,122.67281,12.942
 layer1,0.72,-12.834,122.67281,12.942
 text2985,0.72,-12.834,122.67281,12.942
 tspan2987,0.72,-12.834,122.67281,12.942

这样做的好处是,您可以对SVG文件执行操作,而不必每次都重新启动Inkscape。

我想这样做:

1
2
3
4
5
sub do_inkscape {
     my ($file, $commands) = @_;
     # capture output
     return $output
}

如果我使用open2和forking,一切都可以正常工作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
use IPC::Open2;

$pid = open2(\*CHLD_OUT, \*CHLD_IN, 'inkscape --shell');
$\ ="
"
; $/ =">";

my $out; open my $fh, '>', \$out;

if (!defined($kidpid = fork())) {
    die"cannot fork: $!";
} elsif ($kidpid == 0) {
    while (<>) { print CHLD_IN $_; }
} else {
    while (<CHLD_OUT>) { chop; s/\s*$//gmi; print""$_"";  }
    waitpid($kidpid, 0);
}

但我不知道如何只输入一行,而不必每次重新启动inkscape就只捕获输出。

谢谢

西蒙尼


你不需要叉子,open2自己处理。您需要做的是找到一种方法来检测何时inkscape正在等待输入。

下面是一个非常基本的例子,说明如何实现这一目标:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#! /usr/bin/perl
use strict;
use warnings;

use IPC::Open2;

sub read_until_prompt($) {
    my ($fh) = (@_);
    my $done = 0;
    while (!$done) {
        my $in;
        read($fh, $in, 1);
        if ($in eq '>') {
            $done = 1;
        } else {
            print $in;
        }
    }
}

my ($is_in, $is_out);
my $pid = open2($is_out, $is_in, 'inkscape --shell');

read_until_prompt($is_out);
print"ready
"
;

print $is_in"test.svg -S
"
;
read_until_prompt($is_out);

print $is_in"quit
"
;
waitpid $pid, 0;

print"done!
"
;

read_until_promptinkscape的输出中读取,直到找到>字符,并假定当它看到一个字符时,inkscape已就绪。

注意:这太简单了,如果>可以出现在所期望的输出的提示之外,您可能需要更多的逻辑来使它更可靠地工作。上面的脚本中也没有任何错误检查,这很糟糕。