3
#----------------------------------------------------------------------------------------------
5
# B. Crowell, crowellXX at lightandmatter.com (replace XX with last two digits of current year)
7
# This program is available under version 2 of the GPL License, http://www.gnu.org/copyleft/gpl.html,
8
# or, at your option, under the same license as Perl.
9
# For information about this program, scroll down in the source code, or invoke the program
10
# without any command-line arguments.
11
#----------------------------------------------------------------------------------------------
21
embed_raster_in_svg foo.svg
22
Looks through the svg file for raster images that are given as links, rather than
23
being embedded, and embeds them in the file. The links must be local URIs, and if
24
they're relative, they must be relative to the directory where the svg file is located.
25
Starting with Inkscape 0.41, Inkscape can
26
handle embedded raster images as well as ones that are linked to (?).
27
Typical input looks like this:
30
sodipodi:absref="/home/bcrowell/Documents/programming/embed_raster_in_svg/tests/beer.jpg"
36
The output should look like this:
43
xlink:href="data:;base64,...
44
The SVG standard only allows the <image> tag to refer to data of type png, jpg, or svg,
45
and this script only handles png or jpg.
48
undef $/; # slurp whole file
57
die "input file $svg not found" if ! -e $svg;
58
die "input file $svg not readable" if ! -r $svg;
60
open(FILE,"<$svg") or die "error opening file $svg for input, $!";
64
chdir dirname(Cwd::realpath($svg)); # so from now on, we can open raster files if they're relative to this directory
67
# The file is now in memory.
68
# First we go once through it and (1) find out if there are indeed any links to raster images,
69
# (2) rearrange things a little so that the (lengthy) base64 data will be the last attribute of the
73
my @raster_files = ();
75
s@\<image\s+((?:(?:\w|\:)+\=\"[^"]*\"\s*)*)xlink\:href=\"([^"]+)\"\s*((?:(?:\w|:)+\=\"[^"]*\"\s*)*)\/>@<imageHOBBITSES $1 $3 ITHURTSUS\"$2\"MYPRECIOUSS />@g;
76
while ($data=~m@<imageHOBBITSES\s*(?:(?:(?:\w|\:)+\=\"[^"]*\"\s*)*)ITHURTSUS\"([^"]+)\"MYPRECIOUSS />@g) {
78
die "error, raster filename $raster contains a double quote" if $raster=~m/\"/;
79
if (!($raster=~m/data\:\;/)) {
81
push @raster_files,$raster;
86
print "no embedded jpgs found in file $svg\n";
91
# Eliminate sodipodi:absref attributes. If these are present, Inkscape looks for the linked
92
# file, and ignores the embedded data. Also, get rid of those nasty hobbitses.
93
$data=~s@(<image)HOBBITSES\s*((?:(?:\w|\:)+\=\"[^"]*\"\s*)*)sodipodi\:absref\=\"[^"]+\"\s*((:?(?:\w|\:)+\=\"[^"]*\"\s*)*ITHURTSUS)@$1 $2 $3@g;
94
$data=~s@(<image)HOBBITSES@$1@g;
99
foreach my $raster(@raster_files) {
100
die "file $raster not found relative to directory ".getcwd() if ! -e $raster;
101
die "file $raster is nor readable" if ! -r $raster;
102
open(RASTER,"<$raster") or die "error opening file $raster for input, $!";
103
my $raster_data = <RASTER>;
106
$type='image/png' if $raster_data=~m/^\x{89}PNG/;
107
$type='image/jpg' if $raster_data=~m/^\x{ff}\x{d8}/;
108
die "file $raster does not appear to be of type PNG or JPG" unless $type;
109
my $raster_data_base64 = encode_base64($raster_data);
110
($data =~ s@ITHURTSUS\"$raster\"MYPRECIOUSS@\n xlink:href=\"data\:$type\;base64,$raster_data_base64\"@) or die "error embedding data for $raster";
111
print "embedded raster file $raster, $type\n";
113
my $bak = "$svg.bak";
114
rename $svg,$bak or die "error renaming file $svg to $bak, $!";
115
open(FILE,">$svg") or die "error creating new version of file $svg for output, $!";