File Coverage

blib/lib/FigAnim/ConvertSVG.pm
Criterion Covered Total %
statement 6 180 3.3
branch 0 124 0.0
condition 0 120 0.0
subroutine 2 15 13.3
pod n/a
total 8 439 1.8


line stmt bran cond sub pod time code
1             package ConvertSVG;
2              
3             # SVG styles and tags generator
4              
5 1     1   5 use strict;
  1         2  
  1         36  
6 1     1   5 use warnings;
  1         1  
  1         3467  
7              
8              
9             # returns the min of the values
10             sub min {
11 0     0     my $min = $_[0];
12 0           for (my $i = 0; $i < scalar @_; $i++) {
13 0 0         if ($_[$i] < $min) { $min = $_[$i]; }
  0            
14             }
15 0           return $min;
16             }
17              
18              
19             # return the max of the values
20             sub max {
21 0     0     my $max = $_[0];
22 0           for (my $i = 0; $i < scalar @_; $i++) {
23 0 0         if ($_[$i] > $max) { $max = $_[$i]; }
  0            
24             }
25 0           return $max;
26             }
27              
28              
29             # converts paper size into cm/in with viewBox
30             sub papersize_to_units {
31 0     0     my ($papersize, $orientation, $magnification, $resolution) = @_;
32              
33             # removes spaces at the end of the string
34 0           $papersize =~ s/\s*$//;
35              
36 0           my %paperdef =
37             ("Letter" => [8.5, 11, 'in'],
38             "Legal" => [8.5, 14, 'in'],
39             "Tabloid" => [11, 17, 'in'],
40             "A" => [8.5, 11, 'in'],
41             "B" => [11, 17, 'in'],
42             "C" => [17, 22, 'in'],
43             "D" => [22, 34, 'in'],
44             "E" => [34, 44, 'in'],
45             "A9" => [37, 52, 'mm'],
46             "A8" => [52, 74, 'mm'],
47             "A7" => [74, 105, 'mm'],
48             "A6" => [105, 148, 'mm'],
49             "A5" => [148, 210, 'mm'],
50             "A4" => [210, 297, 'mm'],
51             "A3" => [297, 420, 'mm'],
52             "A2" => [420, 594, 'mm'],
53             "A1" => [594, 841, 'mm'],
54             "A0" => [841, 1189, 'mm'],
55             "B10" => [32, 45, 'mm'],
56             "B9" => [45, 64, 'mm'],
57             "B8" => [64, 91, 'mm'],
58             "B7" => [91, 128, 'mm'],
59             "B6" => [128, 182, 'mm'],
60             "B5" => [182, 257, 'mm'],
61             "B4" => [257, 364, 'mm'],
62             "B3" => [364, 515, 'mm'],
63             "B2" => [515, 728, 'mm'],
64             "B1" => [728, 1030, 'mm'],
65             "B0" => [1030, 1456, 'mm']);
66              
67 0           my $width = $paperdef{$papersize}[0];
68 0           my $height = $paperdef{$papersize}[1];
69 0           my $unit = $paperdef{$papersize}[2];
70 0           my $w = ($width * $magnification / 100) . $unit;
71 0           my $h = ($height * $magnification / 100) . $unit;
72 0           my $vb_w = $width * $resolution;
73 0           my $vb_h = $height * $resolution;
74 0 0         if ($unit eq 'mm') {
75 0           $vb_w = int($vb_w / 25.4);
76 0           $vb_h = int($vb_h / 25.4);
77             }
78              
79 0 0         if ($orientation eq "Landscape") { # Landscape
80 0           return "width=\"$h\" height=\"$w\" viewBox=\"0 0 $vb_h $vb_w\"";
81             } else { # Portrait
82 0           return "width=\"$w\" height=\"$h\" viewBox=\"0 0 $vb_w $vb_h\"";
83             }
84             }
85              
86             # converts FIG pen and fill colors into SVG value: #rrggbb
87             sub pen_fill_colors_to_rgb {
88 0     0     my ($color, $colors) = @_;
89 0           my %table =
90             (-1 => "#000000", # Default
91             0 => "#000000", # Black
92             1 => "#0000ff", # Blue
93             2 => "#00ff00", # Green
94             3 => "#00ffff", # Cyan
95             4 => "#ff0000", # Red
96             5 => "#ff00ff", # Magenta
97             6 => "#ffff00", # Yellow
98             7 => "#ffffff", # White
99             8 => "#000090", # Blue4
100             9 => "#0000b0", # Blue3
101             10 => "#0000d0", # Blue2
102             11 => "#87ceff", # LtBlue
103             12 => "#009000", # Green4
104             13 => "#00b000", # Green3
105             14 => "#00d000", # Green2
106             15 => "#009090", # Cyan4
107             16 => "#00b0b0", # Cyan3
108             17 => "#00d0d0", # Cyan2
109             18 => "#900000", # Red4
110             19 => "#b00000", # Red3
111             20 => "#d00000", # Red2
112             21 => "#900090", # Magenta4
113             22 => "#b000b0", # Magenta3
114             23 => "#d000d0", # Magenta2
115             24 => "#803000", # Brown4
116             25 => "#a04000", # Brown3
117             26 => "#c06000", # Brown2
118             27 => "#ff8080", # Pink4
119             28 => "#ffa0a0", # Pink3
120             29 => "#ffc0c0", # Pink2
121             30 => "#ffe0e0", # Pink
122             31 => "#ffd700"); # Gold
123              
124 0 0         if ($color >= 32) { # user colors
125 0           for (0 .. scalar(@$colors)-1) {
126 0 0         if (@$colors[$_]->{color_number} == $color) {
127 0           return @$colors[$_]->{rgb};
128             }
129             }
130             } else {
131 0           return $table{$color};
132             }
133             }
134              
135             # converts FIG area fill into SVG style: fill
136             sub area_fill_to_fill {
137 0     0     my ($area_fill, $color, $colors) = @_;
138              
139 0 0 0       if ($color == 7) { # White
    0          
140 0 0 0       if ($area_fill == -1) { # not filled
    0 0        
    0 0        
    0          
    0          
    0          
141 0           return "fill: none";
142             } elsif ($area_fill == 0) { # black
143 0           return "fill: #000000";
144             } elsif (($area_fill >= 1) && ($area_fill <= 19)) { # shades
145 0           my $c = int((255/20)*$area_fill);
146 0           $c = sprintf "%02x", $c;
147 0           return "fill: #" . $c . $c . $c;
148             } elsif ($area_fill == 20) { # white
149 0           return "fill: #ffffff";
150             } elsif (($area_fill >= 21) && ($area_fill <= 40)) { # not used
151 0           return "fill: none";
152             } elsif (($area_fill >= 41) && ($area_fill <= 56)) { # patterns
153 0           return "fill: #ffffff";
154             }
155              
156             } elsif (($color == 0) || ($color == -1)) { # Black or Default
157 0 0 0       if ($area_fill == -1) { # not filled
    0 0        
    0 0        
    0          
    0          
    0          
158 0           return "fill: none";
159             } elsif ($area_fill == 0) { # white
160 0           return "fill: #ffffff";
161             } elsif (($area_fill >= 1) && ($area_fill <= 19)) { # shades
162 0           my $c = int((-255/20)*$area_fill + 255);
163 0           $c = sprintf "%02x", $c;
164 0           return "fill: #" . $c . $c . $c;
165             } elsif ($area_fill == 20) { # black
166 0           return "fill: #000000";
167             } elsif (($area_fill >= 21) && ($area_fill <= 40)) { # not used
168 0           return "fill: none";
169             } elsif (($area_fill >= 41) && ($area_fill <= 56)) { # patterns
170 0           return "fill: #000000";
171             }
172              
173             } else { # other colors
174 0 0 0       if ($area_fill == -1) { # not filled
    0 0        
    0 0        
    0          
    0          
    0          
    0          
175 0           return "fill: none";
176             } elsif ($area_fill == 0) { # black
177 0           return "fill: #000000";
178             } elsif (($area_fill >= 1) && ($area_fill <= 19)) { # shades
179 0           my $c = pen_fill_colors_to_rgb($color, $colors);
180 0           my $r = hex(substr($c, 1, 2));
181 0           my $g = hex(substr($c, 3, 2));
182 0           my $b = hex(substr($c, 5, 2));
183 0           $r = int(($r/20)*$area_fill);
184 0           $g = int(($g/20)*$area_fill);
185 0           $b = int(($b/20)*$area_fill);
186 0           $r = sprintf "%02x", $r;
187 0           $g = sprintf "%02x", $g;
188 0           $b = sprintf "%02x", $b;
189 0           return "fill: #" . $r . $g . $b;
190             } elsif ($area_fill == 20) { # full saturation
191 0           return "fill: " . pen_fill_colors_to_rgb($color, $colors);
192             } elsif (($area_fill >= 21) && ($area_fill <= 39)) { # tints
193 0           my $c = pen_fill_colors_to_rgb($color, $colors);
194 0           my $r = hex(substr($c, 1, 2));
195 0           my $g = hex(substr($c, 3, 2));
196 0           my $b = hex(substr($c, 5, 2));
197 0           $r = int(((255-$r)/20)*$area_fill + (2*$r - 255));
198 0           $g = int(((255-$g)/20)*$area_fill + (2*$g - 255));
199 0           $b = int(((255-$b)/20)*$area_fill + (2*$b - 255));
200 0           $r = sprintf "%02x", $r;
201 0           $g = sprintf "%02x", $g;
202 0           $b = sprintf "%02x", $b;
203 0           return "fill: #" . $r . $g . $b;
204             } elsif ($area_fill == 40) { # white
205 0           return "fill: #ffffff";
206             } elsif (($area_fill >= 41) && ($area_fill <= 56)) { # patterns
207 0           return "fill: " . pen_fill_colors_to_rgb($color, $colors);
208             }
209             }
210             }
211              
212             # converts FIG line styles into SVG styles: stroke, stroke-dasharray
213             sub line_style_to_stroke {
214 0     0     my ($line_style, $style_val, $color, $colors) = @_;
215 0 0         if ($line_style == -1) {
    0          
    0          
    0          
    0          
    0          
    0          
216 0           return "stroke: black";
217              
218             } elsif ($line_style == 0) {
219 0           return "stroke: " . pen_fill_colors_to_rgb($color, $colors);
220              
221             } elsif ($line_style == 1) {
222             return
223 0           "stroke: " .
224             pen_fill_colors_to_rgb($color, $colors) .
225             "; " .
226             "stroke-dasharray: " .
227             thickness_to_value($style_val) . ", " .
228             thickness_to_value($style_val) . "; ";
229              
230             } elsif ($line_style == 2) {
231             return
232 0           "stroke: " .
233             pen_fill_colors_to_rgb($color, $colors) .
234             "; " .
235             "stroke-dasharray: " .
236             1 . ", " .
237             thickness_to_value($style_val) . "; ";
238              
239             } elsif ($line_style == 3) {
240             return
241 0           "stroke: " .
242             pen_fill_colors_to_rgb($color, $colors) .
243             "; " .
244             "stroke-dasharray: " .
245             thickness_to_value($style_val) . ", " .
246             thickness_to_value($style_val) / 2 . ", " .
247             1 . ", " .
248             thickness_to_value($style_val) / 2 . "; ";
249              
250             } elsif ($line_style == 4) {
251             return
252 0           "stroke: " .
253             pen_fill_colors_to_rgb($color, $colors) .
254             "; " .
255             "stroke-dasharray: " .
256             thickness_to_value($style_val) . ", " .
257             thickness_to_value($style_val) / 2 . ", " .
258             1 . ", " .
259             thickness_to_value($style_val) / 2 . ", " .
260             1 . ", " .
261             thickness_to_value($style_val) / 2 . "; ";
262              
263             } elsif ($line_style == 5) {
264             return
265 0           "stroke: " .
266             pen_fill_colors_to_rgb($color, $colors) .
267             "; " .
268             "stroke-dasharray: " .
269             thickness_to_value($style_val) . ", " .
270             thickness_to_value($style_val) / 2 . ", " .
271             1 . ", " .
272             thickness_to_value($style_val) / 2 . ", " .
273             1 . ", " .
274             thickness_to_value($style_val) / 2 . ", " .
275             1 . ", " .
276             thickness_to_value($style_val) / 2 . "; ";
277             }
278             }
279              
280             # converts FIG thickness into SVG value
281             sub thickness_to_value {
282 0     0     my ($thickness) = @_;
283 0           return $thickness * 15;
284             }
285              
286             # converts FIG line thickness into SVG style: stroke-width
287             sub thickness_to_stroke {
288 0     0     my ($thickness) = @_;
289             return
290 0           "stroke-width: " .
291             thickness_to_value($thickness);
292             }
293              
294             # converts FIG join_style into SVG style: stroke-linejoin
295             sub join_style_to_linejoin {
296 0     0     my ($join_style) = @_;
297 0 0         if ($join_style == 0) {
    0          
    0          
298 0           return "stroke-linejoin: miter";
299             } elsif ($join_style == 1) {
300 0           return "stroke-linejoin: round";
301             } elsif ($join_style == 2) {
302 0           return "stroke-linejoin: bevel";
303             }
304             }
305              
306             # converts FIG cap_style into SVG style: stroke-linecap
307             sub cap_style_to_linecap {
308 0     0     my ($cap_style) = @_;
309 0 0         if ($cap_style == 0) {
    0          
    0          
310 0           return "stroke-linecap: butt";
311             } elsif ($cap_style == 1) {
312 0           return "stroke-linecap: round";
313             } elsif ($cap_style == 2) {
314 0           return "stroke-linecap: square";
315             }
316             }
317              
318             # converts rad into deg
319             sub rad_to_deg {
320 0     0     my ($rad) = @_;
321 0           return -1 * (180 / 3.14) * $rad;
322             }
323              
324             # converts FIG arrows into SVG markers+paths
325             sub arrows_to_markers {
326 0     0     my ($arrow_name,
327             $direction,
328             $orientation,
329             $arrow_type,
330             $arrow_style,
331             $arrow_thickness,
332             $arrow_width,
333             $arrow_height,
334             $pen_color,
335             $colors) = @_;
336              
337 0           my $width = int($arrow_height);
338 0           my $height = int($arrow_width);
339              
340 0           my $thick = thickness_to_value($arrow_thickness);
341              
342 0           my $id = "id=\"$arrow_name";
343 0           $id .= "\"";
344              
345 0           my $markerUnits = "markerUnits=\"userSpaceOnUse\"";
346 0           my $orient = "orient=\"" . $orientation . "\"";
347              
348 0           my $markerWidth = "markerWidth=\"" . ($width+2*$thick) . "\"";
349 0           my $markerHeight = "markerHeight=\"" . ($height+2*$thick) . "\"";
350              
351 0           my $refX = "";
352 0           my $refY = "";
353              
354 0 0         if ($direction == 1) {
355 0           $refX = "refX=\"" . ($thick+$width) . "\"";
356             } else {
357 0           $refX = "refX=\"" . $thick . "\"";
358             }
359              
360 0           $refY = "refY=\"" . ($thick+$height/2) . "\"";
361              
362 0           my $marker =
363             "
364             "$markerUnits " .
365             "$orient " .
366             "$markerWidth " . "$markerHeight " .
367             "$refX " . "$refY " . ">\n";
368              
369             # converts FIG arrows into SVG paths
370              
371 0           my $d = "d=\"";
372 0           my $style = "style=\"";
373              
374 0           $style .=
375             "stroke: " . pen_fill_colors_to_rgb($pen_color, $colors) .
376             "; " .
377             thickness_to_stroke($arrow_thickness) . "; ";
378              
379 0 0         if ($arrow_type == 0) {
    0          
    0          
    0          
380 0 0         if ($direction == 1) {
381 0           $d .=
382             "M " . $thick . " " . ($thick+$height) . ", " .
383             "L " . ($thick+$width) . " " . int($thick+$height/2) . ", " .
384             "L " . $thick . " " . $thick;
385             } else {
386 0           $d .=
387             "M " . ($thick+$width) . " " . $thick . ", " .
388             "L " . $thick . " " . int($thick+$height/2) . ", " .
389             "L " . ($thick+$width) . " " . ($thick+$height);
390             }
391              
392             } elsif($arrow_type == 1) {
393 0 0         if ($direction == 1) {
394 0           $d .=
395             "M " . $thick . " " . ($thick+$height) . ", " .
396             "L " . ($width+$thick) . " " . int($thick+$height/2) . ", " .
397             "L " . $thick . " " . $thick . ", " .
398             "Z";
399             } else {
400 0           $d .=
401             "M " . ($thick+$width) . " " . $thick . ", " .
402             "L " . $thick . " " . int($thick+$height/2) . ", " .
403             "L " . ($thick+$width) . " " . ($thick+$height) . ", " .
404             "Z";
405             }
406              
407             } elsif($arrow_type == 2) {
408 0 0         if ($direction == 1) {
409 0           $d .=
410             "M " . $thick . " " . ($thick+$height) . ", " .
411             "L " . int($width+$thick) . " " . int($thick+$height/2) . ", " .
412             "L " . $thick . " " . $thick . ", " .
413             "L " . ($thick+$width/3) . " " . ($thick+$height/2) . ", " .
414             "Z";
415             } else {
416 0           $d .=
417             "M " . ($thick+$width) . " " . $thick . ", " .
418             "L " . $thick . " " . int($thick + $height/2) . ", " .
419             "L " . ($thick+$width) . " " . ($thick+$height) . ", " .
420             "L " . int($thick+2*$width/3) . " " . int($thick+$height/2) . ", " .
421             "Z";
422             }
423              
424             } elsif($arrow_type == 3) {
425 0 0         if ($direction == 1) {
426 0           $d .=
427             "M " . int($thick+$width/3) . " " . ($thick+$height) . ", " .
428             "L " . int($width+$thick) . " " . int($thick+$height/2) . ", " .
429             "L " . int($thick+$width/3) . " " . $thick . ", " .
430             "L " . $thick . " " . int($thick+$height/2) . ", " .
431             "Z";
432             } else {
433 0           $d .=
434             "M " . int($thick+2*$width/3) . " " . $thick . ", " .
435             "L " . $thick . " " . int($thick+$height/2) . ", " .
436             "L " . int($thick+2*$width/3) . " " . ($thick+$height) . ", " .
437             "L " . ($thick+$width) . " " . int($thick+$height/2) . ", " .
438             "Z";
439             }
440             }
441              
442             # fills arrow with pen color
443 0 0         if ($arrow_type == 0) {
444 0           $style .= "fill: none";
445             } else {
446 0 0         if ($arrow_style == 0) {
447 0           $style .= "fill: white";
448             } else {
449 0           $style .=
450             "fill: " .
451             pen_fill_colors_to_rgb($pen_color, $colors);
452             }
453             }
454              
455 0           $d .= "\"";
456 0           $style .= "\"";
457              
458 0           $marker .= "\t\n";
459              
460 0           $marker .= "\n";
461              
462 0           return $marker;
463             }
464              
465             # converts FIG font into SVG styles
466             sub font_flags_to_font {
467 0     0     my ($font_flags, $font) = @_;
468              
469 0           my %postscript_fonts =
470             (0 => "serif",
471             1 => "serif",
472             2 => "serif",
473             3 => "serif",
474             4 => "'Avant Garde'",
475             5 => "'Avant Garde'",
476             6 => "'Avant Garde'",
477             7 => "'Avant Garde'",
478             8 => "Bookman",
479             9 => "Bookman",
480             10 => "Bookman",
481             11 => "Bookman",
482             12 => "monospace",
483             13 => "monospace",
484             14 => "monospace",
485             15 => "monospace",
486             16 => "sans-serif",
487             17 => "sans-serif",
488             18 => "sans-serif",
489             19 => "sans-serif",
490             20 => "sans-serif",
491             21 => "sans-serif",
492             22 => "sans-serif",
493             23 => "sans-serif",
494             24 => "'new century schoolbook'",
495             25 => "'new century schoolbook'",
496             26 => "'new century schoolbook'",
497             27 => "'new century schoolbook'",
498             28 => "Palatino",
499             29 => "Palatino",
500             30 => "Palatino",
501             31 => "Palatino",
502             32 => "Symbol",
503             33 => "cursive",
504             34 => "cursive");
505              
506 0           my $font_flags_bit0 = $font_flags % 2;
507 0           my $font_flags_bit1 = int($font_flags/2) % 2;
508 0           my $font_flags_bit2 = int($font_flags/(2*2)) % 2;
509 0           my $font_flags_bit3 = int($font_flags/(2*2*2)) % 2;
510              
511 0           my $svg_font = "";
512              
513 0 0         if ($font_flags_bit2 == 0) { # LaTeX fonts
514              
515 0 0         if ($font == 1) {
    0          
    0          
    0          
    0          
516 0           $svg_font = "font-family: serif; ";
517             } elsif ($font == 2) {
518 0           $svg_font .= "font-weight: bold";
519             } elsif ($font == 3) {
520 0           $svg_font .= "font-style: italic";
521             } elsif ($font == 4) {
522 0           $svg_font .= "font-family: sans-serif";
523             } elsif ($font == 5) {
524 0           $svg_font .= "font-family: monospace";
525             }
526              
527              
528             } else { # PostScript fonts
529              
530 0 0 0       if (($font >= 1) && ($font <= 34)) {
531 0           $svg_font = "font-family: " . $postscript_fonts{$font} . "; ";
532             }
533              
534             # Italic
535 0 0 0       if (($font == 1) ||
      0        
      0        
      0        
      0        
      0        
      0        
      0        
536             ($font == 3) ||
537             ($font == 9) ||
538             ($font == 11) ||
539             ($font == 25) ||
540             ($font == 27) ||
541             ($font == 29) ||
542             ($font == 31) ||
543             ($font == 33)) {
544 0           $svg_font .= "font-style: italic; ";
545             }
546              
547             # Bold
548 0 0 0       if (($font == 2) ||
      0        
      0        
      0        
      0        
      0        
      0        
      0        
      0        
      0        
      0        
549             ($font == 3) ||
550             ($font == 14) ||
551             ($font == 15) ||
552             ($font == 18) ||
553             ($font == 19) ||
554             ($font == 22) ||
555             ($font == 23) ||
556             ($font == 26) ||
557             ($font == 27) ||
558             ($font == 30) ||
559             ($font == 31)) {
560 0           $svg_font .= "font-weight: bold; ";
561             }
562              
563             # Oblique
564 0 0 0       if (($font == 5) ||
      0        
      0        
      0        
      0        
      0        
      0        
565             ($font == 7) ||
566             ($font == 13) ||
567             ($font == 15) ||
568             ($font == 17) ||
569             ($font == 19) ||
570             ($font == 21) ||
571             ($font == 23)) {
572 0           $svg_font .= "font-style: oblique; ";
573             }
574              
575             # Narrow
576 0 0 0       if (($font == 20) ||
      0        
      0        
577             ($font == 21) ||
578             ($font == 22) ||
579             ($font == 23)) {
580 0           $svg_font .= "font-stretch: narrower; ";
581             }
582             }
583              
584 0           return $svg_font;
585             }
586              
587              
588             # return
589             1;