如何强制使用相对文件路径

如何强制使用相对文件路径

当链接到 PNG 光栅图形时Inkscape SVG文档中,Inkscape 似乎始终坚持将 PNG 图形的绝对路径写入文件。这有很多缺点(显然,每次保存后都可以通过在文本编辑器中手动编辑 SVG 文件来缓解这些缺点,但这不是 Inkscape 等图形编辑器背后的想法):

  • 如果不破坏 SVG,我就无法移动包含图形的目录。
  • 我无法将包含我的图形的目录存储在便携式存储器上以便在不同的计算机上对其进行处理,因为便携式设备将被分配不同的驱动器号。
  • 我无法从不同的操作系统编辑我的图形,因为它们可能会将存储 SVG 文件和 PNG 图形的分区安装在不同的安装点上。
  • 我无法通过网络共享将包含我的图形的目录提供给同事以供他们复制,因为路径不匹配。
  • 这些文件无法直接提交并通过版本控制系统共享,例如SVN或者Git原因相同。至少,每次有人提交更改的文件时,包含完整路径的行都会被 VCS 毫无意义地注册为更改。
  • 由于文件经常存储在用户的主目录中,这甚至会带来隐私风险,因为会泄露创建者的用户名(在工作设置中,通常是真实姓名)或有关创建者文件系统的其他信息。

即使现在,Inkscape 似乎使用相对路径,并且只是在额外的属性 ( sodipodi:absref) 中添加完整路径,上面的几个问题是仍然(特别是隐私问题没有变化,VCS 问题也没有变化)。

请注意,我确实不是想要嵌入由于各种原因,Inkscape 文档中的 PNG 数据可能无法正常工作,其中两个原因是:

  • 图形稍后可能会发生变化,将 PNG 图像作为单独的 PNG 文件进行编辑(这样当再次打开 Inkscape 时它将自动更新)比将 PNG 数据嵌入 SVG 中更加灵活,仍然将其保存为一个额外的文件(这样我以后可以编辑 PNG 图像)并且每次我更改 PNG 时;将新版本再次嵌入 Inkscape 中,手动调整其位置和大小以匹配以前的版本,然后删除以前的版本。
  • 各种 PNG 图像(例如徽标或其他与企业标识相关的图形)都用于大量 SVG 文档中,因此将这样的图像嵌入到每个 SVG 文档中只会浪费空间,而不是只存储一次并在每个 SVG 文档中引用原始 PNG 图形。(当然,上一项的工作量会随着我在每一个 SVG 文档中使用给定的修改后的光栅图形而成倍增加。)

作为一种解决方法,我想到编写一个脚本,该脚本必须在保存后在 SVG 文件上运行,要么使用XSLT或者使用一些可以加载 SVG 的传统语言。可能,这也可以设置为上述版本控制系统的预提交钩子。但是,这样做对我来说似乎已经足够乏味了,所以只有在真的没有其他办法的情况下,我才会这么做。

有没有办法强制 Inkscape 仅将链接图像的相对路径写入 SVG 文件?(如果可能的话,也适用于最近使用的位图导出路径。)

答案1

这个问题问得好,我希望我能找到一个真正好的解决方案。我所能想到的只是以下这个黑客脚本:

#!/usr/bin/perl

use strict;

# usage:
#   relativise_svg.pl foo.svg
# Looks for absolute links in svg file and makes them relative.
# Also checks whether files linked to exist.

use File::Spec; 
use File::Basename;
use Cwd 'abs_path';
my $svg = $ARGV[0];

-e $svg or err("file $svg doesn't exist");
-w $svg or err("file $svg not writeable");

local $/; # slurp whole file

open(F,"<$svg");
my $xml = <F>;
close F;

# Absolute links look like this:
#   xlink:href="file:///home/bcrowell/Documents/writing/books/physics/share/..."
# After we relativise them, they look like this:
#   xlink:href="foo/bar.jpg"

my $cwd = Cwd::getcwd();
my $svg_dir = File::Basename::dirname(abs_path($svg));
my $original_xml = $xml;

my @changes = ();
while ($xml=~m@(file://(/[^'"]*))@g) {
  my $whole = $1;
  my $path = $2;
  my $rel = relativise($path,$svg_dir,$cwd);
  print "changing absolute path in $svg to $rel\n";
  push @changes,[$whole,$rel];
}
foreach my $change(@changes) {
  my $from = quotemeta($change->[0]);
  my $to = $change->[1];
  $xml =~ s/$from/$to/g;
}

while ($xml=~m@xlink:href\s*=\s*"([^'"]*)@g) {
  my $rel = $1;
  if ($rel=~/\.(png|jpg)$/ && !($rel=~/\A#/ || $rel=~/\Adata:;/)) {
    my $abs = File::Spec->rel2abs($rel,$svg_dir);
    -e $abs or err("file $rel doesn't exist, resolved to absolute path $abs");
  }
}

if ($xml ne $original_xml) {
  open(F,">$svg");
  print F $xml;
  close F;
}

sub err {
  my $message = shift;
  print "relativise_svg.pl, working on $svg, ",$message,"\n";
  exit(-1);
}

sub relativise {
  my ($abs,$rel_to,$within) = @_;
  my $rel = File::Spec->abs2rel($abs,$rel_to);
  if (File::Spec->abs2rel($rel,$within)=~/\.\./) {
    err("result, $rel, would have been outside $within");
  }
  return $rel;
}

相关内容