package ConvertSVG;
# SVG styles and tags generator
use strict;
use warnings;
# returns the min of the values
sub min {
my $min = $_[0];
for (my $i = 0; $i < scalar @_; $i++) {
if ($_[$i] < $min) { $min = $_[$i]; }
}
return $min;
}
# return the max of the values
sub max {
my $max = $_[0];
for (my $i = 0; $i < scalar @_; $i++) {
if ($_[$i] > $max) { $max = $_[$i]; }
}
return $max;
}
# converts paper size into cm/in with viewBox
sub papersize_to_units {
my ($papersize, $orientation, $magnification, $resolution) = @_;
# removes spaces at the end of the string
$papersize =~ s/\s*$//;
my %paperdef =
("Letter" => [8.5, 11, 'in'],
"Legal" => [8.5, 14, 'in'],
"Tabloid" => [11, 17, 'in'],
"A" => [8.5, 11, 'in'],
"B" => [11, 17, 'in'],
"C" => [17, 22, 'in'],
"D" => [22, 34, 'in'],
"E" => [34, 44, 'in'],
"A9" => [37, 52, 'mm'],
"A8" => [52, 74, 'mm'],
"A7" => [74, 105, 'mm'],
"A6" => [105, 148, 'mm'],
"A5" => [148, 210, 'mm'],
"A4" => [210, 297, 'mm'],
"A3" => [297, 420, 'mm'],
"A2" => [420, 594, 'mm'],
"A1" => [594, 841, 'mm'],
"A0" => [841, 1189, 'mm'],
"B10" => [32, 45, 'mm'],
"B9" => [45, 64, 'mm'],
"B8" => [64, 91, 'mm'],
"B7" => [91, 128, 'mm'],
"B6" => [128, 182, 'mm'],
"B5" => [182, 257, 'mm'],
"B4" => [257, 364, 'mm'],
"B3" => [364, 515, 'mm'],
"B2" => [515, 728, 'mm'],
"B1" => [728, 1030, 'mm'],
"B0" => [1030, 1456, 'mm']);
my $width = $paperdef{$papersize}[0];
my $height = $paperdef{$papersize}[1];
my $unit = $paperdef{$papersize}[2];
my $w = ($width * $magnification / 100) . $unit;
my $h = ($height * $magnification / 100) . $unit;
my $vb_w = $width * $resolution;
my $vb_h = $height * $resolution;
if ($unit eq 'mm') {
$vb_w = int($vb_w / 25.4);
$vb_h = int($vb_h / 25.4);
}
if ($orientation eq "Landscape") { # Landscape
return "width=\"$h\" height=\"$w\" viewBox=\"0 0 $vb_h $vb_w\"";
} else { # Portrait
return "width=\"$w\" height=\"$h\" viewBox=\"0 0 $vb_w $vb_h\"";
}
}
# converts FIG pen and fill colors into SVG value: #rrggbb
sub pen_fill_colors_to_rgb {
my ($color, $colors) = @_;
my %table =
(-1 => "#000000", # Default
0 => "#000000", # Black
1 => "#0000ff", # Blue
2 => "#00ff00", # Green
3 => "#00ffff", # Cyan
4 => "#ff0000", # Red
5 => "#ff00ff", # Magenta
6 => "#ffff00", # Yellow
7 => "#ffffff", # White
8 => "#000090", # Blue4
9 => "#0000b0", # Blue3
10 => "#0000d0", # Blue2
11 => "#87ceff", # LtBlue
12 => "#009000", # Green4
13 => "#00b000", # Green3
14 => "#00d000", # Green2
15 => "#009090", # Cyan4
16 => "#00b0b0", # Cyan3
17 => "#00d0d0", # Cyan2
18 => "#900000", # Red4
19 => "#b00000", # Red3
20 => "#d00000", # Red2
21 => "#900090", # Magenta4
22 => "#b000b0", # Magenta3
23 => "#d000d0", # Magenta2
24 => "#803000", # Brown4
25 => "#a04000", # Brown3
26 => "#c06000", # Brown2
27 => "#ff8080", # Pink4
28 => "#ffa0a0", # Pink3
29 => "#ffc0c0", # Pink2
30 => "#ffe0e0", # Pink
31 => "#ffd700"); # Gold
if ($color >= 32) { # user colors
for (0 .. scalar(@$colors)-1) {
if (@$colors[$_]->{color_number} == $color) {
return @$colors[$_]->{rgb};
}
}
} else {
return $table{$color};
}
}
# converts FIG area fill into SVG style: fill
sub area_fill_to_fill {
my ($area_fill, $color, $colors) = @_;
if ($color == 7) { # White
if ($area_fill == -1) { # not filled
return "fill: none";
} elsif ($area_fill == 0) { # black
return "fill: #000000";
} elsif (($area_fill >= 1) && ($area_fill <= 19)) { # shades
my $c = int((255/20)*$area_fill);
$c = sprintf "%02x", $c;
return "fill: #" . $c . $c . $c;
} elsif ($area_fill == 20) { # white
return "fill: #ffffff";
} elsif (($area_fill >= 21) && ($area_fill <= 40)) { # not used
return "fill: none";
} elsif (($area_fill >= 41) && ($area_fill <= 56)) { # patterns
return "fill: #ffffff";
}
} elsif (($color == 0) || ($color == -1)) { # Black or Default
if ($area_fill == -1) { # not filled
return "fill: none";
} elsif ($area_fill == 0) { # white
return "fill: #ffffff";
} elsif (($area_fill >= 1) && ($area_fill <= 19)) { # shades
my $c = int((-255/20)*$area_fill + 255);
$c = sprintf "%02x", $c;
return "fill: #" . $c . $c . $c;
} elsif ($area_fill == 20) { # black
return "fill: #000000";
} elsif (($area_fill >= 21) && ($area_fill <= 40)) { # not used
return "fill: none";
} elsif (($area_fill >= 41) && ($area_fill <= 56)) { # patterns
return "fill: #000000";
}
} else { # other colors
if ($area_fill == -1) { # not filled
return "fill: none";
} elsif ($area_fill == 0) { # black
return "fill: #000000";
} elsif (($area_fill >= 1) && ($area_fill <= 19)) { # shades
my $c = pen_fill_colors_to_rgb($color, $colors);
my $r = hex(substr($c, 1, 2));
my $g = hex(substr($c, 3, 2));
my $b = hex(substr($c, 5, 2));
$r = int(($r/20)*$area_fill);
$g = int(($g/20)*$area_fill);
$b = int(($b/20)*$area_fill);
$r = sprintf "%02x", $r;
$g = sprintf "%02x", $g;
$b = sprintf "%02x", $b;
return "fill: #" . $r . $g . $b;
} elsif ($area_fill == 20) { # full saturation
return "fill: " . pen_fill_colors_to_rgb($color, $colors);
} elsif (($area_fill >= 21) && ($area_fill <= 39)) { # tints
my $c = pen_fill_colors_to_rgb($color, $colors);
my $r = hex(substr($c, 1, 2));
my $g = hex(substr($c, 3, 2));
my $b = hex(substr($c, 5, 2));
$r = int(((255-$r)/20)*$area_fill + (2*$r - 255));
$g = int(((255-$g)/20)*$area_fill + (2*$g - 255));
$b = int(((255-$b)/20)*$area_fill + (2*$b - 255));
$r = sprintf "%02x", $r;
$g = sprintf "%02x", $g;
$b = sprintf "%02x", $b;
return "fill: #" . $r . $g . $b;
} elsif ($area_fill == 40) { # white
return "fill: #ffffff";
} elsif (($area_fill >= 41) && ($area_fill <= 56)) { # patterns
return "fill: " . pen_fill_colors_to_rgb($color, $colors);
}
}
}
# converts FIG line styles into SVG styles: stroke, stroke-dasharray
sub line_style_to_stroke {
my ($line_style, $style_val, $color, $colors) = @_;
if ($line_style == -1) {
return "stroke: black";
} elsif ($line_style == 0) {
return "stroke: " . pen_fill_colors_to_rgb($color, $colors);
} elsif ($line_style == 1) {
return
"stroke: " .
pen_fill_colors_to_rgb($color, $colors) .
"; " .
"stroke-dasharray: " .
thickness_to_value($style_val) . ", " .
thickness_to_value($style_val) . "; ";
} elsif ($line_style == 2) {
return
"stroke: " .
pen_fill_colors_to_rgb($color, $colors) .
"; " .
"stroke-dasharray: " .
1 . ", " .
thickness_to_value($style_val) . "; ";
} elsif ($line_style == 3) {
return
"stroke: " .
pen_fill_colors_to_rgb($color, $colors) .
"; " .
"stroke-dasharray: " .
thickness_to_value($style_val) . ", " .
thickness_to_value($style_val) / 2 . ", " .
1 . ", " .
thickness_to_value($style_val) / 2 . "; ";
} elsif ($line_style == 4) {
return
"stroke: " .
pen_fill_colors_to_rgb($color, $colors) .
"; " .
"stroke-dasharray: " .
thickness_to_value($style_val) . ", " .
thickness_to_value($style_val) / 2 . ", " .
1 . ", " .
thickness_to_value($style_val) / 2 . ", " .
1 . ", " .
thickness_to_value($style_val) / 2 . "; ";
} elsif ($line_style == 5) {
return
"stroke: " .
pen_fill_colors_to_rgb($color, $colors) .
"; " .
"stroke-dasharray: " .
thickness_to_value($style_val) . ", " .
thickness_to_value($style_val) / 2 . ", " .
1 . ", " .
thickness_to_value($style_val) / 2 . ", " .
1 . ", " .
thickness_to_value($style_val) / 2 . ", " .
1 . ", " .
thickness_to_value($style_val) / 2 . "; ";
}
}
# converts FIG thickness into SVG value
sub thickness_to_value {
my ($thickness) = @_;
return $thickness * 15;
}
# converts FIG line thickness into SVG style: stroke-width
sub thickness_to_stroke {
my ($thickness) = @_;
return
"stroke-width: " .
thickness_to_value($thickness);
}
# converts FIG join_style into SVG style: stroke-linejoin
sub join_style_to_linejoin {
my ($join_style) = @_;
if ($join_style == 0) {
return "stroke-linejoin: miter";
} elsif ($join_style == 1) {
return "stroke-linejoin: round";
} elsif ($join_style == 2) {
return "stroke-linejoin: bevel";
}
}
# converts FIG cap_style into SVG style: stroke-linecap
sub cap_style_to_linecap {
my ($cap_style) = @_;
if ($cap_style == 0) {
return "stroke-linecap: butt";
} elsif ($cap_style == 1) {
return "stroke-linecap: round";
} elsif ($cap_style == 2) {
return "stroke-linecap: square";
}
}
# converts rad into deg
sub rad_to_deg {
my ($rad) = @_;
return -1 * (180 / 3.14) * $rad;
}
# converts FIG arrows into SVG markers+paths
sub arrows_to_markers {
my ($arrow_name,
$direction,
$orientation,
$arrow_type,
$arrow_style,
$arrow_thickness,
$arrow_width,
$arrow_height,
$pen_color,
$colors) = @_;
my $width = int($arrow_height);
my $height = int($arrow_width);
my $thick = thickness_to_value($arrow_thickness);
my $id = "id=\"$arrow_name";
$id .= "\"";
my $markerUnits = "markerUnits=\"userSpaceOnUse\"";
my $orient = "orient=\"" . $orientation . "\"";
my $markerWidth = "markerWidth=\"" . ($width+2*$thick) . "\"";
my $markerHeight = "markerHeight=\"" . ($height+2*$thick) . "\"";
my $refX = "";
my $refY = "";
if ($direction == 1) {
$refX = "refX=\"" . ($thick+$width) . "\"";
} else {
$refX = "refX=\"" . $thick . "\"";
}
$refY = "refY=\"" . ($thick+$height/2) . "\"";
my $marker =
"<marker $id " .
"$markerUnits " .
"$orient " .
"$markerWidth " . "$markerHeight " .
"$refX " . "$refY " . ">\n";
# converts FIG arrows into SVG paths
my $d = "d=\"";
my $style = "style=\"";
$style .=
"stroke: " . pen_fill_colors_to_rgb($pen_color, $colors) .
"; " .
thickness_to_stroke($arrow_thickness) . "; ";
if ($arrow_type == 0) {
if ($direction == 1) {
$d .=
"M " . $thick . " " . ($thick+$height) . ", " .
"L " . ($thick+$width) . " " . int($thick+$height/2) . ", " .
"L " . $thick . " " . $thick;
} else {
$d .=
"M " . ($thick+$width) . " " . $thick . ", " .
"L " . $thick . " " . int($thick+$height/2) . ", " .
"L " . ($thick+$width) . " " . ($thick+$height);
}
} elsif($arrow_type == 1) {
if ($direction == 1) {
$d .=
"M " . $thick . " " . ($thick+$height) . ", " .
"L " . ($width+$thick) . " " . int($thick+$height/2) . ", " .
"L " . $thick . " " . $thick . ", " .
"Z";
} else {
$d .=
"M " . ($thick+$width) . " " . $thick . ", " .
"L " . $thick . " " . int($thick+$height/2) . ", " .
"L " . ($thick+$width) . " " . ($thick+$height) . ", " .
"Z";
}
} elsif($arrow_type == 2) {
if ($direction == 1) {
$d .=
"M " . $thick . " " . ($thick+$height) . ", " .
"L " . int($width+$thick) . " " . int($thick+$height/2) . ", " .
"L " . $thick . " " . $thick . ", " .
"L " . ($thick+$width/3) . " " . ($thick+$height/2) . ", " .
"Z";
} else {
$d .=
"M " . ($thick+$width) . " " . $thick . ", " .
"L " . $thick . " " . int($thick + $height/2) . ", " .
"L " . ($thick+$width) . " " . ($thick+$height) . ", " .
"L " . int($thick+2*$width/3) . " " . int($thick+$height/2) . ", " .
"Z";
}
} elsif($arrow_type == 3) {
if ($direction == 1) {
$d .=
"M " . int($thick+$width/3) . " " . ($thick+$height) . ", " .
"L " . int($width+$thick) . " " . int($thick+$height/2) . ", " .
"L " . int($thick+$width/3) . " " . $thick . ", " .
"L " . $thick . " " . int($thick+$height/2) . ", " .
"Z";
} else {
$d .=
"M " . int($thick+2*$width/3) . " " . $thick . ", " .
"L " . $thick . " " . int($thick+$height/2) . ", " .
"L " . int($thick+2*$width/3) . " " . ($thick+$height) . ", " .
"L " . ($thick+$width) . " " . int($thick+$height/2) . ", " .
"Z";
}
}
# fills arrow with pen color
if ($arrow_type == 0) {
$style .= "fill: none";
} else {
if ($arrow_style == 0) {
$style .= "fill: white";
} else {
$style .=
"fill: " .
pen_fill_colors_to_rgb($pen_color, $colors);
}
}
$d .= "\"";
$style .= "\"";
$marker .= "\t<path $d $style />\n";
$marker .= "</marker>\n";
return $marker;
}
# converts FIG font into SVG styles
sub font_flags_to_font {
my ($font_flags, $font) = @_;
my %postscript_fonts =
(0 => "serif",
1 => "serif",
2 => "serif",
3 => "serif",
4 => "'Avant Garde'",
5 => "'Avant Garde'",
6 => "'Avant Garde'",
7 => "'Avant Garde'",
8 => "Bookman",
9 => "Bookman",
10 => "Bookman",
11 => "Bookman",
12 => "monospace",
13 => "monospace",
14 => "monospace",
15 => "monospace",
16 => "sans-serif",
17 => "sans-serif",
18 => "sans-serif",
19 => "sans-serif",
20 => "sans-serif",
21 => "sans-serif",
22 => "sans-serif",
23 => "sans-serif",
24 => "'new century schoolbook'",
25 => "'new century schoolbook'",
26 => "'new century schoolbook'",
27 => "'new century schoolbook'",
28 => "Palatino",
29 => "Palatino",
30 => "Palatino",
31 => "Palatino",
32 => "Symbol",
33 => "cursive",
34 => "cursive");
my $font_flags_bit0 = $font_flags % 2;
my $font_flags_bit1 = int($font_flags/2) % 2;
my $font_flags_bit2 = int($font_flags/(2*2)) % 2;
my $font_flags_bit3 = int($font_flags/(2*2*2)) % 2;
my $svg_font = "";
if ($font_flags_bit2 == 0) { # LaTeX fonts
if ($font == 1) {
$svg_font = "font-family: serif; ";
} elsif ($font == 2) {
$svg_font .= "font-weight: bold";
} elsif ($font == 3) {
$svg_font .= "font-style: italic";
} elsif ($font == 4) {
$svg_font .= "font-family: sans-serif";
} elsif ($font == 5) {
$svg_font .= "font-family: monospace";
}
} else { # PostScript fonts
if (($font >= 1) && ($font <= 34)) {
$svg_font = "font-family: " . $postscript_fonts{$font} . "; ";
}
# Italic
if (($font == 1) ||
($font == 3) ||
($font == 9) ||
($font == 11) ||
($font == 25) ||
($font == 27) ||
($font == 29) ||
($font == 31) ||
($font == 33)) {
$svg_font .= "font-style: italic; ";
}
# Bold
if (($font == 2) ||
($font == 3) ||
($font == 14) ||
($font == 15) ||
($font == 18) ||
($font == 19) ||
($font == 22) ||
($font == 23) ||
($font == 26) ||
($font == 27) ||
($font == 30) ||
($font == 31)) {
$svg_font .= "font-weight: bold; ";
}
# Oblique
if (($font == 5) ||
($font == 7) ||
($font == 13) ||
($font == 15) ||
($font == 17) ||
($font == 19) ||
($font == 21) ||
($font == 23)) {
$svg_font .= "font-style: oblique; ";
}
# Narrow
if (($font == 20) ||
($font == 21) ||
($font == 22) ||
($font == 23)) {
$svg_font .= "font-stretch: narrower; ";
}
}
return $svg_font;
}
# return
1;