Làm thế nào để thực thi các đường dẫn tệp tương đối


4

Khi liên kết với đồ họa raster PNG từ các tài liệu Inkscape SVG , có vẻ như Inkscape luôn khăng khăng viết đường dẫn tuyệt đối đến đồ họa PNG vào tệp. Điều này có nhiều nhược điểm (rõ ràng có thể được giảm thiểu bằng cách chỉnh sửa thủ công tệp SVG trong trình chỉnh sửa văn bản sau mỗi lần lưu, nhưng đó không thể là ý tưởng đằng sau trình chỉnh sửa đồ họa như Inkscape):

  • Tôi không thể di chuyển thư mục với đồ họa của mình mà không phá vỡ SVG.
  • Tôi không thể lưu trữ thư mục với đồ họa của mình trên bộ nhớ di động để hoạt động trên thư mục đó từ nhiều máy tính khác nhau, vì thiết bị di động sẽ được gán các ký tự ổ đĩa khác nhau.
  • Tôi không thể chỉnh sửa đồ họa của mình từ các hệ điều hành khác nhau, vì chúng có thể gắn phân vùng lưu trữ các tệp SVG và đồ họa PNG trên các điểm gắn khác nhau.
  • Tôi không thể cung cấp thư mục với đồ họa của mình cho các đồng nghiệp trên mạng chia sẻ từ nơi họ có thể sao chép nó, vì các đường dẫn sẽ không khớp.
  • Các tệp không thể được cam kết và chia sẻ trực tiếp thông qua các hệ thống kiểm soát phiên bản như SVN hoặc Git vì lý do tương tự. Ít nhất, mỗi khi ai đó cam kết tệp đã thay đổi, các dòng chứa đường dẫn đầy đủ sẽ được đăng ký vô nghĩa dưới dạng thay đổi của VCS.
  • Với các tệp được lưu trữ thường xuyên trong thư mục nhà của người dùng, điều này thậm chí còn gây ra rủi ro riêng tư bằng cách cho đi tên người dùng của người tạo (trong cài đặt công việc, thường là tên thật) hoặc thông tin khác về hệ thống tệp của người tạo.

Ngay cả bây giờ, Inkscape dường như sử dụng các đường dẫn tương đối và chỉ thêm đường dẫn đầy đủ trong một thuộc tính bổ sung ( sodipodi:absref), một số vấn đề ở trên vẫn còn tồn tại (đặc biệt là vấn đề bảo mật không thay đổi và vấn đề VCS cũng vậy).

Lưu ý rằng tôi không muốn nhúng dữ liệu PNG vào tài liệu Inkscape vì nhiều lý do, hai trong số đó là:

  • Đồ họa có thể thay đổi sau này và linh hoạt hơn khi có hình ảnh PNG dưới dạng tệp PNG riêng biệt nơi tôi có thể chỉnh sửa nó (và do đó nó sẽ được cập nhật tự động khi mở lại Inkscape), thay vì nhúng dữ liệu PNG vào SVG , vẫn lưu nó dưới dạng tệp bổ sung (để tôi có thể chỉnh sửa hình ảnh PNG sau này) và mỗi lần tôi thay đổi PNG; nhúng phiên bản mới một lần nữa trong Inkscape, tự điều chỉnh vị trí và kích thước của nó để phù hợp với phiên bản trước và sau đó xóa phiên bản trước.
  • Nhiều hình ảnh PNG (nghĩ logo hoặc đồ họa liên quan đến danh tính công ty khác) được sử dụng trong vô số tài liệu SVG, do đó, sẽ rất lãng phí không gian để nhúng một hình ảnh như vậy vào mỗi tài liệu SVG, thay vì lưu trữ nó chỉ một lần và tham khảo đồ họa PNG gốc từ mỗi tài liệu SVG. (Và tất nhiên, nỗ lực từ mục trước nhân lên với mỗi tài liệu SVG mà tôi sử dụng một đồ họa raster đã sửa đổi cho trước.)

Như một giải pháp thay thế, tôi đã nghĩ đến việc viết một tập lệnh phải chạy trên các tệp SVG sau khi lưu, bằng XSLT hoặc với một số ngôn ngữ thông thường có thể tải SVG. Rất có thể, điều này cũng có thể được thiết lập như một móc nối trước cho các hệ thống kiểm soát phiên bản đã nói ở trên. Tuy nhiên, làm như vậy có vẻ đủ tẻ nhạt đối với tôi, vì vậy tôi chỉ muốn đi đến những chiều dài đó nếu thực sự không có cách nào khác.

Có cách nào để buộc Inkscape chỉ viết các đường dẫn tương đối đến các hình ảnh được liên kết vào tệp SVG không? (Cũng cho đường dẫn xuất bitmap được sử dụng gần đây nhất, nếu có thể.)

Câu trả lời:


1

Đây là một câu hỏi tuyệt vời, và tôi ước tôi có một giải pháp thực sự tốt. Tất cả những gì tôi có thể nghĩ ra là kịch bản hackish sau:

#!/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;
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.