Cómo aplicar rutas de archivos relativas

4

Cuando se vincula a gráficos ráster PNG desde documentos SVG de Inkscape , parece que Inkscape siempre insiste en escribir la ruta absoluta al gráfico PNG en el archivo. Esto tiene muchas desventajas (que, obviamente, pueden mitigarse editando manualmente el archivo SVG en un editor de texto después de cada guardado, pero esa no puede ser la idea detrás de un editor gráfico como Inkscape):

  • No puedo mover el directorio con mis gráficos sin romper el SVG.
  • No puedo almacenar el directorio con mis gráficos en una memoria portátil para trabajar en él desde varias computadoras, ya que al dispositivo portátil se le asignarán diferentes letras de unidad.
  • No puedo editar mis gráficos desde diferentes sistemas operativos, ya que pueden montar la partición que almacena los archivos SVG y los gráficos PNG en diferentes puntos de montaje.
  • No puedo proporcionar el directorio con mis gráficos a colegas en un recurso compartido de red desde donde pueden copiarlo, porque las rutas no coincidirán.
  • Los archivos no pueden enviarse directamente y compartirse a través de sistemas de control de versiones como SVN o Git por la misma razón. Por lo menos, cada vez que alguien confirma el archivo modificado, las líneas que contienen rutas completas serán registradas sin sentido como cambios por el VCS.
  • Con los archivos almacenados con frecuencia en el directorio de inicio del usuario, esto incluso presenta un riesgo de privacidad al revelar el nombre de usuario del creador (en la configuración de trabajo, a menudo el nombre real) u otra información sobre el sistema de archivos del creador.

Incluso ahora, que Inkscape parece usar rutas relativas y solo agrega la ruta completa en un atributo adicional ( sodipodi:absref), varios de los problemas anteriores aún existen (en particular, la preocupación por la privacidad no ha cambiado, y también lo es el problema de VCS).

Tenga en cuenta que no quiero incrustar los datos PNG en los documentos de Inkscape por varias razones, dos de las cuales son:

  • Los gráficos pueden cambiar más adelante, y es más flexible tener la imagen PNG como un archivo PNG separado donde puedo editarlo (y, por lo tanto, se actualizará automáticamente al abrir Inkscape nuevamente), en lugar de incrustar los datos PNG en el SVG , aún lo guardo como un archivo adicional (para poder editar la imagen PNG más adelante) y cada vez que cambio el PNG; incrustando la nueva versión nuevamente en Inkscape, adaptando manualmente su posición y tamaño para que coincida con la versión anterior y luego eliminando la versión anterior.
  • Varias de las imágenes PNG (piense en logotipos u otros gráficos relacionados con la identidad corporativa) se usan en una multitud de documentos SVG, por lo que simplemente sería una pérdida de espacio incrustar una de esas imágenes en cada documento SVG, en lugar de almacenarla solo una vez y haciendo referencia a ese gráfico PNG original de cada documento SVG. (Y, por supuesto, el esfuerzo del elemento anterior se multiplica con cada documento SVG en el que uso un gráfico ráster modificado dado).

Como solución alternativa, he pensado escribir un script que tenga que ejecutarse sobre archivos SVG después de guardar, ya sea con XSLT o con algún lenguaje convencional que pueda cargar SVG. Posiblemente, esto también podría configurarse como un enlace previo para los sistemas de control de versiones antes mencionados. Sin embargo, hacerlo me parece lo suficientemente tedioso, por lo que solo quiero llegar a esos extremos si realmente no hay otra manera.

¿Hay alguna manera de obligar a Inkscape a escribir solo las rutas relativas a las imágenes vinculadas en el archivo SVG? (También para la ruta de exportación de mapa de bits utilizada más recientemente, si es posible).

O Mapper
fuente

Respuestas:

1

Esta es una gran pregunta, y desearía tener una solución realmente buena. Todo lo que he podido encontrar es el siguiente script hackish:

#!/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;
}
Ben Crowell
fuente