1 #!/usr/bin/perl
2 # convert an illustrator file (on stdin) to svg (on stdout)
3 use strict;
4 use warnings;
5 use Getopt::Std;
7 my $skip_images;
9 BEGIN {
10 $skip_images = 0;
11 eval "use Image::Magick;";
12 if ($@) {
13 warn "Couldn't load Perl module Image::Magick. Images will be skipped.\n";
14 warn "$@\n";
15 $skip_images = 1;
16 }
17 }
20 my %args;
22 # Newline characters
23 my $NL_DOS = "\015\012";
24 my $NL_MAC = "\015";
25 my $NL_UNX = "\012";
27 getopts('h:', \%args);
29 my @ImageData;
30 my $pagesize=1052.36218;
31 my $imagewidth = 128;
32 my $imageheight = 88;
33 my $imagex = 0;
34 my $imagey = 0;
35 my $imagenum = 0;
36 my $strokeparams;
37 my $strokecolor;
38 my $strokewidth;
39 my $fillcolor;
40 my $firstChar = 0;
41 my $image;
42 my $path;
43 my $color = 0;
44 my $weareinimage=0;
45 my $weareintext=0;
46 my($red,$green,$blue);
47 my($cpx,$cpy);
49 if ($args{h}) { usage() && exit }
51 $color = "#000";
53 sub addImageLine {
54 my ($data) = @_;
55 chomp($data);
56 #push (@ImageData, $data);
58 my $len = length( $data );
59 my $count = 0;
61 #printf("%s %d\r\n",$data,$len);
62 #for( $loop=1; $loop < ($len - 2); $loop += 2){
63 for( my $loop=1; $loop < $len; $loop += 2){
64 my $value = substr( $data, $loop, 2);
66 #printf("[%d:%s]",$loop,$value);
68 if( $color == 0 ){
69 #$red = hex($value);
70 $red = $value;
71 $color ++;
72 #printf("Color: RED: %s,",$red);
73 } elsif ( $color == 1 ) {
74 #$green = hex($value);
75 $green = $value;
76 $color ++;
77 #printf("Color: GREEN %s,",$green);
79 } else {
80 $blue = $value;
81 my $pixel="pixel[${imagex},${imagey}]";
82 my $rgb=sprintf("#%s%s%s",$red,$green,$blue);
83 #$image->Set($pixel=>$rgb);
84 $image->Set("pixel[${imagex},${imagey}]"=>"#${red}${green}${blue}")
85 unless ($skip_images);
86 #printf("PIXX: %d ",$image->Get($pixel));
87 $color = 0;
88 $imagex++;
90 #printf("Color:BLUE: %s, X: %d Y: %d %dx%d %s [%s]\r\n",$blue,$imagex,$imagey,$imagewidth,$imageheight,$rgb,$pixel);
92 if( $imagex == $imagewidth ){
93 $imagex = 0;
94 $imagey ++;
95 } # if
98 } #else
100 }
102 #printf("len: %d %dx%d\r\n",$len,$imagewidth,$imageheight);
104 }
106 sub cmyk_to_css {
107 my ($c, $m, $y, $k) = @_;
108 my ($r, $g, $b);
110 $r = 1 - ($k + $c);
111 if ($r < 0) { $r = 0; }
112 $g = 1 - ($k + $m);
113 if ($g < 0) { $g = 0; }
114 $b = 1 - ($k + $y);
115 if ($b < 0) { $b = 0; }
116 return sprintf ("#%02x%02x%02x", 255 * $r, 255 * $g, 255 * $b);
117 }
119 sub nice_float {
120 my ($x) = @_;
122 my $result = sprintf ("%.3f", $x);
123 $result =~ s/0*$//;
124 $result =~ s/\.$//;
125 return $result;
126 }
128 sub xform_xy {
129 my ($x, $y) = @_;
130 my @result = ();
132 for my $i (0..$#_) {
133 if ($i & 1) {
134 #push @result, 1000 - $_[$i];
135 push @result, $pagesize - $_[$i];
136 } else {
137 #push @result, $_[$i] - 100;
138 push @result, $_[$i];
139 }
140 }
141 return join ' ', map { nice_float ($_) } @result;
142 }
144 sub strokeparams {
145 $strokecolor ||= 'black';
146 my $result = "stroke:$strokecolor";
147 if ($strokewidth && $strokewidth != 1) {
148 $result .= "; stroke-width:$strokewidth";
149 }
150 return $result;
151 }
153 sub usage {
154 warn qq|Usage: ill2svg [-l "string" -h] infile > outfile
155 options:
156 -h print this message and exit
157 |;
158 }
160 sub process_line {
161 chomp;
162 return if /^%_/;
164 if (/^([\d\.]+) ([\d\.]+) ([\d\.]+) ([\d\.]+) k$/) {
165 $fillcolor = cmyk_to_css ($1, $2, $3, $4);
166 } elsif (/^([\d\.]+) ([\d\.]+) ([\d\.]+) ([\d\.]+) K$/) {
167 $strokecolor = cmyk_to_css ($1, $2, $3, $4);
168 } elsif (/^([\d\.]+) g$/) {
169 $fillcolor = cmyk_to_css (0, 0, 0, 1 - $1);
170 } elsif (/^([\d\.]+) G$/) {
171 $strokecolor = cmyk_to_css (0, 0, 0, 1 - $1);
172 } elsif (/^([\d\.]+) ([\d\.]+) m$/) {
173 $path .= 'M'.xform_xy($1, $2);
174 $cpx = $1;
175 $cpy = $2;
176 } elsif (/^([\d\.]+) ([\d\.]+) l$/i) {
177 $path .= 'L'.xform_xy($1, $2);
178 $cpx = $1;
179 $cpy = $2;
180 } elsif (/^([\d\.]+) ([\d\.]+) ([\d\.]+) ([\d\.]+) v$/i) {
181 $path .= 'C'.xform_xy($cpx, $cpy, $1, $2, $3, $4);
182 $cpx = $3;
183 $cpy = $4;
184 } elsif (/^([\d\.]+) ([\d\.]+) ([\d\.]+) ([\d\.]+) y$/i) {
185 $path .= 'C'.xform_xy($1, $2, $3, $4, $3, $4);
186 $cpx = $3;
187 $cpy = $4;
188 } elsif (/^([\d\.]+) ([\d\.]+) ([\d\.]+) ([\d\.]+) ([\d\.]+) ([\d\.]+) c$/i) {
189 $path .= 'C'.xform_xy($1, $2, $3, $4, $5, $6);
190 $cpx = $5;
191 $cpy = $6;
192 } elsif (/^b$/) {
193 $path .= 'z';
194 $strokeparams = strokeparams ();
195 print " <g style=\"fill: $fillcolor; $strokeparams\">\n";
196 print " <path d=\"$path\"/>\n";
197 print " </g>\n";
198 $path = '';
199 } elsif (/^B$/) {
200 $strokeparams = strokeparams ();
201 print " <g style=\"fill: $fillcolor; $strokeparams\">\n";
202 print " <path d=\"$path\"/>\n";
203 print " </g>\n";
204 $path = '';
205 } elsif (/^f$/i) {
206 $path .= 'z';
207 if (! $fillcolor) {
208 warn "Error: Fill color not defined in source file!\n";
209 print " <path d=\"$path\"/>\n";
210 } else {
211 print " <g style=\"fill: $fillcolor;\">\n";
212 print " <path d=\"$path\"/>\n";
213 print " </g>\n";
214 }
215 $path = '';
216 } elsif (/^s$/) {
217 $path .= 'z';
218 $strokeparams = strokeparams ();
219 #print " <g style=\"fill:none;stroke:black;stroke-opacity:1; $strokeparams\">\n";
220 print " <g style=\"fill:none; $strokeparams\">\n";
221 print " <path d=\"$path\"/>\n";
222 print " </g>\n";
223 $path = '';
224 } elsif (/^S$/) {
225 $strokeparams = strokeparams ();
226 #print " <g style=\"fill:none; $strokeparams\">\n";
227 print " <g style=\"fill:none;stroke:black;$strokeparams;\">\n";
228 print " <path d=\"$path\"/>\n";
229 print " </g>\n";
230 $path = '';
231 } elsif (/^1 XR$/) {
233 if( $firstChar != 0){
234 print (" </tspan>\n</text>\n");
235 }
237 $weareintext=0;
239 $firstChar = 0;
240 } elsif (/^TP$/) {
241 #Something do with the text;)
242 # $weareintext=1;
243 } elsif (/^([\d\.]+) ([\d\.]+) ([\d\.]+) ([\d\.]+) ([\d\.]+) ([\d\.]+) ([\d\.]+) Tp$/i) {
245 # Text position etc;
246 $cpx=$5;
247 $cpy=$pagesize - $6;
248 ## print ("x:$5 y:$6\r\n");
250 } elsif (/^TO$/) {
251 #one text ends
252 } elsif (/^LB$/) {
253 #Everything ends??
254 ## Sometimes ain't working
255 warn "Error: Unexpected 'LB'! Everything has ended??\n";
256 if( $weareintext != 0){
257 print (" </tspan>\n</text>\n");
258 }
260 } elsif (/^\/_([\S\s]+) ([\d\.]+) Tf$/) {
261 my $FontName = $1;
262 my $FontSize = $2;
264 ## When we know font name we can render this.
265 if( $firstChar != 1){
266 print ("<text x=\"$cpx\" y=\"$cpy\"");
267 print (" style=\"font-size:$FontSize;font-weight:normal;stroke-width:1;");
268 print ("fill:$fillcolor;fill-opacity:1;");
269 print ("font-family:$FontName;\" id=\"text$5\">\n<tspan>");
270 $firstChar = 1;
271 $weareintext=1;
272 } else {
273 print ("</tspan>\n<tspan x=\"$cpx\" y=\"$cpy\"");
274 print (" style=\"font-size:$FontSize;font-weight:normal;stroke-width:1;");
275 print ("fill:$fillcolor;fill-opacity:1;");
276 print ("font-family:$FontName;\" id=\"text$5\">");
277 $weareintext=1;
278 }
280 } elsif (/^\(([\S\s]+)\) Tx$/) {
281 # Normal text
282 my $text = $1;
283 $text =~ s/ä/ä/;
284 $text =~ s/ö/ö/;
285 $text =~ s/å/Ã¥/;
287 print ("$text");
289 } elsif (/([\d\.]+) w$/) {
290 $strokewidth = $1;
291 } elsif (/^%%BeginData: ([\d\.]+)/) {
292 #How much we got image data
293 } elsif(/^%%EndData/) {
294 #and the data ends
295 } elsif (/^XI/) {
296 #actual image starts
297 $weareinimage=1;
298 } elsif (/^XH/) {
299 #it ends like they allways do.
300 #we just save it after this..
301 $weareinimage=0;
302 my $imagename="${imagenum}.png";
303 $image->Write($imagename) unless ($skip_images);
304 $imagenum++;
305 } elsif (/\[(.*)\](.*)Xh/) {
306 my @imagepos = split(/ /, $1);
307 my @imageinfo = split(/ /, $2);
308 $imagewidth = $imageinfo[1];
309 $imageheight = $imageinfo[2];
311 if (! $imagewidth && ! $imageheight ) {
312 die "ERROR: This fileformat is not supported by "
313 ."ill2svg.pl.\n(Is it possible you are trying to "
314 ."use ill2svg.pl on a PDF file?) \n";
315 }
317 my $imageposx = $imagepos[4];
318 my $imageposy = $pagesize - $imagepos[5];
320 #printf("%s %d %d Position x: %f 9y: %f\r\n",$1,@imagepos[4],@imagepos[5],$imageposx,$imageposy);
321 printf("<image");
322 printf(" xlink:href=\"%d.png\"",$imagenum);
323 printf(" width=\"%d\"",$imagewidth);
324 printf(" height=\"%d\"",$imageheight);
325 printf(" x=\"%f\"",$imageposx);
326 printf(" y=\"%f\"",$imageposy);
327 printf("/>\r\n");
329 my $size = "${imagewidth}x${imageheight}";
331 if (!$skip_images) {
332 $image = Image::Magick->new(size=>$size);
333 $image->Set('density'=>'72');
334 $image->Read("xc:white");
335 }
336 $imagex=0;
337 $imagey=0;
339 } else {
340 if( $weareinimage == 1 ){
341 addImageLine( $_ );
342 }
344 chomp;
346 #print "$_\r\n";
347 }
348 }
349 if( $firstChar != 0){
350 print (" </tspan>\n</text>\n");
351 }
353 print "<svg";
354 print " xmlns=\"http://www.w3.org/2000/svg\"";
355 print " xmlns:xlink=\"http://www.w3.org/1999/xlink\">\r\n";
357 while (<>) {
358 if (m/$NL_DOS$/) {
359 $/ = $NL_DOS;
360 foreach (split /$NL_DOS/) {
361 process_line($_);
362 }
363 } elsif (m/$NL_MAC$/) {
364 $/ = $NL_MAC;
365 foreach (split /$NL_MAC/) {
366 process_line($_);
367 }
368 } else {
369 chomp;
370 process_line($_);
371 }
372 }
373 print "</svg>\n";