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 = "\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\n"; $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;