#!/usr/bin/perl -w

# Default parameter
# Pattern
my ($asp_x, $asp_y, $par_x, $par_y, $cont_x, $cont_y, $prot_x, $prot_y, $b_top) = 
   ( 4,      3,      1,      1,      0,       0,       0,       0,       0    );
# Style
my ($b_sub, $height, $stroke, $style, $shade, $margin) = 
   ( 0,      270,     4,       "DVB",  12.5,   4     );

# Parse command line arguments
while (my $arg = shift) {
    if ($arg =~/^-/) { # Option starting with a minus
        if ($arg eq '-v') {
            print "$0 V2.1 – 2023-12-11\n";
            exit 0;
        } elsif (($arg eq '-?') || ($arg eq '-help')) {
            print <<END; # Help text

Generate SVG vector graphics files to illustrate various Active Format Aspect Ratio cases.

Usage: $0 [-h <height>] [-s <stroke>] [-asp <h> <v>] [-cont <h> <v>] [-prot <h> <v>] [-t] [-style <style>]
Command line options:
	-?: This help
	-v: Version info
    Image parameter:
	-asp <x> <y>: Coded Frame Aspect Ratio, integers. Default 4 : 3
	-par <x> <y>: Pixel Aspect Ratio, integers. Default: 1 : 1 (square pixel)
	  Note: Since SVG shows anamorphic pixel as square ones, the diagram will illustrate the anamorphic distortion.
	-cont <x> <y>: Active Content Aspect Ratio, integers. Default: full frame
	-top: Place content at top of frame. Default: centered in frame
	-prot <x> <y>: Shoot\&Protect Aspect Ratio, integers. Default: same as Content AR
	-sub: Add two lines of subtitles, 2nd in letterbox bar (if applicable)
	SVG graphics parameter:
	-h <height>: SVG diagram height, integer. Default: 270
	    The SVG diagram width is calculated based on -asp and -par options
	-s <stroke>: Stroke width (SVG line width), decimal fraction. Default: 4.0
	-style <style>: Select the AFD diagram style, either 'DVB' or 'ATSC'. Default: DVB
	-shade <grey percentage>: Select the shading, 0 (white) to 100 (black). Default: 12.5
	-margin <pixel>: Add a margin of the specified width around the diagram, 0 to disable. Default: 4 pixel

Questions \& comments:  Christian.Wolff\@dolby.com

END
            exit 0;
        } elsif ($arg eq '-h') {
            $height = shift || die "-h requires a value";
        } elsif ($arg eq '-s') {
            $stroke = shift || die "-s requires a value";
        } elsif ($arg eq '-asp') {
            $asp_x = shift || die "-asp requires two values";
            $asp_y = shift || die "-asp requires two values";
        } elsif ($arg eq '-par') {
            $par_x = shift || die "-par requires two values";
            $par_y = shift || die "-par requires two values";
        } elsif ($arg eq '-cont') {
            $cont_x = shift || die "-cont requires two values";
            $cont_y = shift || die "-cont requires two values";
        } elsif ($arg eq '-prot') {
            $prot_x = shift || die "-prot requires two values";
            $prot_y = shift || die "-prot requires two values";
        } elsif (($arg eq '-t') || ($arg eq '-top')) {
            $b_top = 1;
        } elsif ($arg eq '-sub') {
            $b_sub = 1;
        } elsif ($arg eq '-style') {
            $style = shift || die "-style requires a value";
            $style = uc($style);
            die "Unsupported style: '${style}'" if (($style!~/^DVB$/) && ($style!~/^ATSC$/));
        } elsif ($arg eq '-shade') {
            $shade = shift || die "-shade requires a value";
        } elsif ($arg eq '-margin') {
            $margin = shift || die "-margin requires a value";
        } else {
            die "Unknown option: '${arg}', help: -?";
        }
    }
}

# Debug
#print "Params: -h $height -s $stroke -asp $asp_x $asp_y -par $par_x $par_y -cont $cont_x $cont_y -prot $prot_x $prot_y " . ($b_top ? "-t " : '') . "-style $style\n";

# Returns lesser of two values
sub min 
{
    my ($a, $b) = @_;
    
    if ($a < $b) {
        return $a;
    } else {
        return $b;
    }
}

# Total Frame
my $width = $height * $asp_x / $asp_y * $par_y / $par_x;

# File Name and SVG prep
my $s2 = $stroke / 2; # Half of the SVG line width
my $filename = "AFD_${asp_x}x${asp_y}" .
    ((($cont_x > 0) && ($cont_y > 0)) ? '_' . $cont_x . 'x' . $cont_y . ($b_top ? 'top' : '') : '_full') .
    ((($prot_x > 0) && ($prot_y > 0)) ? '_' . $prot_x . 'x' . $prot_y : '') .
    ((($par_x != 1) || ($par_y != 1)) ? '_par' . $par_x . 'x' . $par_y : '') .
    '_' . $height . 'p' . $stroke . '.svg';
my $svg_filename = $style . '_' . $filename;
my $svg = '';

print "Generating SVG '${svg_filename}'\n";



#
# SVG graphics macros
#

# By default, shapes are shrunk so that the entire line width stays within the confines of the shape.
# Optionally, the shape can be grown on selected sides so that the entire line width is just outside of the confines.

# Returns a vertical SVG Line. Uses global $stroke variable.
sub svg_vertline 
{
    # adj is either 'l' or 'r', to shift to resp. side.
    # length is shrunk to keep line within confines.
    
    my ($x, $y1, $y2, $adj) = @_;
    
    # Shift horizontally
    if ($adj=~/l/) {
        $x -= $s2;
    } elsif ($adj=~/r/) {
        $x += $s2;
    }
    
    # Shrink vertically
    $y1 += $s2;
    $y2 -= $s2;
    
    return 
        '<line' . 
        ' x1="' . $x . '" y1="' . $y1 . '"' . 
        ' x2="' . $x . '" y2="' . $y2 . '"' . 
        ' />';
}

# Returns a SVG Rectangle. Uses global $stroke variable.
sub svg_rect 
{
    # adj is combo of l,r,t,b chars, to grow on resp. side to keep line outside of confines.
    # default is to shrink to keep line within confines.
    # fill is grey percentage, 0 (white) to 100 (black), or -1 for no fill
    # b_stroke_fill, if not zero, sets stroke color to same as fill color, or white, if no fill
    
    my ($x, $y, $w, $h, $adj, $fill, $b_stroke_fill) = @_;
    
    # Shrink / grow horizontally
    if ($adj=~/l/) {
        $x -= $s2;
        $w += $s2;
    } else {
        $x += $s2;
        $w -= $s2;
    }
    if ($adj=~/r/) {
        $w += $s2;
    } else {
        $w -= $s2;
    }
    
    # Shrink / grow vertically
    if ($adj=~/t/) {
        $y -= $s2;
        $h += $s2;
    } else {
        $y += $s2;
        $h -= $s2;
    }
    if ($adj=~/b/) {
        $h += $s2;
    } else {
        $h -= $s2;
    }
    
    my $fillrgb = int((255 * (100 - ($fill >= 0 ? $fill : 0)) + 99) / 100);
    return 
        '<rect' . 
        ' x="' . $x . '" y="' . $y . '"' . 
        ' width="' . $w . '" height="' . $h . '"' . 
        ($fill >= 0 ? ' fill="rgb(' . "${fillrgb},${fillrgb},${fillrgb}" . ')"' : '') . 
        ($b_stroke_fill ? ' stroke="rgb(' . "${fillrgb},${fillrgb},${fillrgb}" . ')"' : '') . 
        ' />';
}

# Returns a SVG Oval (Circle or Ellipse). Uses global $stroke variable.
sub svg_oval 
{
    # adj is combo of l,r,t,b chars, to grow on resp. side to keep line outside of confines.
    # default is to shrink to keep line within confines.
    # fill is grey percentage, 0 (white) to 100 (black), or -1 for no fill
    
    my ($x, $y, $rx, $ry, $adj, $fill) = @_;
    
    # Default shrink
    $rx -= $s2;
    $ry -= $s2;
    
    my $error = 0;
    
    # Grow horizontally
    if ($adj=~/l/) {
        $x -= $s2;
        $rx += $s2;
        $ry += $s2; # maintain shape
        $error ++;
    }
    if ($adj=~/r/) {
        $x += $s2;
        $rx += $s2;
        $ry += $s2; # maintain shape
        $error ++;
    }
    
    # Grow vertically
    if ($adj=~/t/) {
        $y -= $s2;
        if ($error) {
            $error--; # ry was already increased by l or r
        } else {
            $ry += $s2;
            $rx += $s2; # maintain shape
        }
    }
    if ($adj=~/b/) {
        $y += $s2;
        if ($error) {
            $error--; # ry was already increased by l or r
        } else {
            $ry += $s2;
            $rx += $s2; # maintain shape
        }
    }
    
    my $fillrgb = int((255 * (100 - $fill) + 99) / 100);
    return 
        '<' . ($rx == $ry ? 'circle' : 'ellipse') . 
        ' cx="' . $x . '" cy="' . $y . '"' . 
        ($rx == $ry ? 
            ' r="' . $rx . '"' : 
            ' rx="' . $rx . '" ry="' . $ry . '"'
        ) . 
        ($fill >= 0 ? ' fill="rgb(' . "${fillrgb},${fillrgb},${fillrgb}" . ')"' : '') . 
        ' />';
}

# Line of text, centered on x/y/w/h rectangle
sub svg_text
{
    # adj is combo of l,r,t,b chars, to grow on resp. side to keep line outside of confines.
    # default is to shrink to keep line within confines.
    # fill is grey percentage, 0 (white) to 100 (black), or -1 for no fill
    # b_stroke_fill, if not zero, sets stroke color to same as fill color, or white, if no fill
    
    my ($text, $x, $y, $w, $h, $adj, $fill) = @_;
    
    # Shrink / grow horizontally
    if ($adj=~/l/) {
        $x -= $s2;
        $w += $s2;
    } else {
        $x += $s2;
        $w -= $s2;
    }
    if ($adj=~/r/) {
        $w += $s2;
    } else {
        $w -= $s2;
    }
    
    # Shrink / grow vertically
    if ($adj=~/t/) {
        $y -= $s2;
        $h += $s2;
    } else {
        $y += $s2;
        $h -= $s2;
    }
    if ($adj=~/b/) {
        $h += $s2;
    } else {
        $h -= $s2;
    }
    
    my $fillrgb = int((255 * (100 - ($fill >= 0 ? $fill : 0)) + 99) / 100);
    return 
        '<text' . 
        ' x="' . ($x + $w / 2) . '" y="' . ($y + $h / 2) . '"' . 
        ' font-size="' . ($h * 7 / 8) . 'px"' . 
        ' letter-spacing="' . ((int($par_y * 100 / $par_x) - 100) / 200) . 'em"' . 
        ($fill >= 0 ? ' fill="rgb(' . "${fillrgb},${fillrgb},${fillrgb}" . ')" ' : '') . 
        ' stroke-width="3" paint-order="stroke" dominant-baseline="middle" text-anchor="middle">' . 
        $text . '</text>';
}

# Returns the SVG header
sub svg_header 
{
    # fill is grey percentage, 0 (white) to 100 (black), or -1 for no fill
    
    my $fill = shift;
    
    my $fillrgb = int((255 * (100 - $fill) + 99) / 100);
    return 
        '<?xml version="1.0" encoding="UTF-8" standalone="no"?>' . "\n" .
        '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">' . "\n" .
        '<svg width="' . $width . '" height="' . $height . '" ' . 
        ($margin > 0 ? 'viewBox="-' . $margin . ' -' . $margin . ' ' . ($width + 2 * $margin) . ' ' . ($height + 2 * $margin) . '" ' : '') . 
        'xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">' . "\n" .
        "\t<g fill=" . ($fill >= 0 ? '"rgb(' . "${fillrgb},${fillrgb},${fillrgb}" . ')"' : '"none"') . 
            ' stroke="rgb(0,0,0)" stroke-width="' . $stroke . '" stroke-linecap="round" stroke-linejoin="round">' . "\n" . 
        ($margin > 0 ? "\t\t" . svg_rect(-$margin, -$margin, $width + 2 * $margin, $height + 2 * $margin, '', -1, 1) . "\n" : '');
}

# Returns the SVG footer
sub svg_footer 
{
    return 
        "\t</g>\n" .
        "</svg>\n\n";
}



#
# Area Dimensions
#

# Full (Total) Frame
my $frame_w = $width;
my $frame_h = $height;

# Active Content (relative to total frame)
my $cont_w = $frame_w;
my $cont_h = $frame_h;
if (($cont_x > 0) && ($cont_y > 0)) {
    $cont_w = min($frame_w, $frame_h * $cont_x / $cont_y * $par_y / $par_x);
    $cont_h = min($frame_h, $frame_w * $cont_y / $cont_x * $par_x / $par_y);
}

# Shoot & Protect (relative to active content)
my $prot_w = $cont_w;
my $prot_h = $cont_h;
if (($prot_x > 0) && ($prot_y > 0)) {
    $prot_w = min($cont_w, $cont_h * $prot_x / $prot_y * $par_y / $par_x);
    $prot_h = min($cont_h, $cont_w * $prot_y / $prot_x * $par_x / $par_y);
}

# Bars (Outside of active content)
my $bar_w = ($frame_w - $cont_w) / 2;
my $bar_h = ($frame_h - $cont_h) / 2;

# Optional Crop (Outside of "Shoot & Protect", but inside active content)
my $opt_w = ($cont_w - $prot_w) / 2;
my $opt_h = ($cont_h - $prot_h) / 2;

# 4:3 Area
my $cont43_w = min($cont_w, $cont_h * 4 / 3);
my $cont43_h = $cont_h;

# 14:9 Area
my $cont149_w = min($cont_w, $cont_h * 14 / 9);
my $cont149_h = $cont_h;

# 16:9 Area
my $cont169_w = min($cont_w, $cont_h * 16 / 9);
my $cont169_h = $cont_h;

# 64:27 Area
my $cont6427_w = min($cont_w, $cont_h * 64 / 27);
my $cont6427_h = $cont_h;



#
# DVB Style
#

if ($style=~/^DVB$/) {
    
    # Active Rectangle
    my $dvb_active_rect_x = $bar_w;
    my $dvb_active_rect_y = ($b_top ? 0 : $bar_h);
    my $dvb_active_rect_w = $cont_w;
    my $dvb_active_rect_h = $cont_h;
    my $dvb_active_rect_adj = ($bar_w > 0 ? 'lr' : '') . ($bar_h > 0 ? ($b_top ? 'b' : 'tb') : '');
    
    # Main Circle
    my $dvb_main_circ_cx = $frame_w / 2;
    my $dvb_main_circ_cy = $frame_h / 2 - ($b_top ? $bar_h : 0);
    my $dvb_main_circ_ry = $prot_h / 2;
    my $dvb_main_circ_rx = $dvb_main_circ_ry * $par_y / $par_x;
    my $dvb_main_circ_adj = '';
    my $dvb_main_circ_rep = 0;
    
    # Side Circles / Repetitions of Main Circle
    my $dvb_side_circ_rx = ($prot_w / 2 - $dvb_main_circ_rx) / 2;
    while ($dvb_side_circ_rx > $dvb_main_circ_rx) {
        $dvb_side_circ_rx -= $dvb_main_circ_rx;
        $dvb_main_circ_rep++;
    }
    my $dvb_side_circ_ry = $dvb_side_circ_rx * $par_x / $par_y;
    
    # Left Circle
    my $dvb_left_circ_rx = $dvb_side_circ_rx;
    my $dvb_left_circ_ry = $dvb_side_circ_ry;
    my $dvb_left_circ_cx = $dvb_main_circ_cx - ($dvb_main_circ_rx * (1 + $dvb_main_circ_rep * 2)) - $dvb_left_circ_rx;
    my $dvb_left_circ_cy = $dvb_main_circ_cy;
    my $dvb_left_circ_adj = 'r';
    
    # Right Circle
    my $dvb_right_circ_rx = $dvb_side_circ_rx;
    my $dvb_right_circ_ry = $dvb_side_circ_ry;
    my $dvb_right_circ_cx = $dvb_main_circ_cx + ($dvb_main_circ_rx * (1 + $dvb_main_circ_rep * 2)) + $dvb_right_circ_rx;
    my $dvb_right_circ_cy = $dvb_main_circ_cy;
    my $dvb_right_circ_adj = 'l';
    
    # Left / Top Bar
    my $dvb_lt_bar_x = 0;
    my $dvb_lt_bar_y = 0;
    my $dvb_lt_bar_w = ($bar_h > 0 ? ($b_top ? 0 : $frame_w) : $bar_w);
    my $dvb_lt_bar_h = ($bar_w > 0 ? $frame_h : ($b_top ? 0 : $bar_h));
    my $dvb_lt_bar_adj = '';
    
    # Right / Bottom Bar
    my $dvb_rb_bar_x = ($bar_w > 0 ? $bar_w + $cont_w : 0);
    my $dvb_rb_bar_y = ($bar_h > 0 ? ($b_top ? $cont_h : $bar_h + $cont_h) : 0);
    my $dvb_rb_bar_w = ($bar_h > 0 ? $frame_w : $bar_w);
    my $dvb_rb_bar_h = ($bar_w > 0 ? $frame_h : ($b_top ? $bar_h * 2 : $bar_h));
    my $dvb_rb_bar_adj = '';
    
    # DVB File Content
    $svg = svg_header(0);
    $svg .= "\t\t" . svg_rect($dvb_active_rect_x, $dvb_active_rect_y, $dvb_active_rect_w, $dvb_active_rect_h, $dvb_active_rect_adj, $shade) . "\n";
    $svg .= "\t\t" . svg_oval($dvb_main_circ_cx, $dvb_main_circ_cy, $dvb_main_circ_rx, $dvb_main_circ_ry, $dvb_main_circ_adj, -1) . "\n";
    for (my $i = 0; $i < $dvb_main_circ_rep; $i++) {
        $svg .= "\t\t" . svg_oval($dvb_main_circ_cx - ($i + 1) * 2 * $dvb_main_circ_rx, $dvb_main_circ_cy, $dvb_main_circ_rx, $dvb_main_circ_ry - $s2, $dvb_left_circ_adj, -1) . "\n";
        $svg .= "\t\t" . svg_oval($dvb_main_circ_cx + ($i + 1) * 2 * $dvb_main_circ_rx, $dvb_main_circ_cy, $dvb_main_circ_rx, $dvb_main_circ_ry - $s2, $dvb_right_circ_adj, -1) . "\n";
    }
    $svg .= "\t\t" . svg_oval($dvb_left_circ_cx, $dvb_left_circ_cy, $dvb_left_circ_rx, $dvb_left_circ_ry, $dvb_left_circ_adj, -1) . "\n";
    $svg .= "\t\t" . svg_oval($dvb_right_circ_cx, $dvb_right_circ_cy, $dvb_right_circ_rx, $dvb_right_circ_ry, $dvb_right_circ_adj, -1) . "\n";
    if (($dvb_lt_bar_w > 0) && ($dvb_lt_bar_h > 0)) {
        $svg .= "\t\t" . svg_rect($dvb_lt_bar_x, $dvb_lt_bar_y, $dvb_lt_bar_w, $dvb_lt_bar_h, $dvb_lt_bar_adj, 100) . "\n";
    }
    if (($dvb_rb_bar_w > 0) && ($dvb_rb_bar_h > 0)) {
        $svg .= "\t\t" . svg_rect($dvb_rb_bar_x, $dvb_rb_bar_y, $dvb_rb_bar_w, $dvb_rb_bar_h, $dvb_rb_bar_adj, 100) . "\n";
    }
    if ($b_sub) {
        my $sub_area_h = $dvb_active_rect_h + min($bar_h, $frame_h / 8);
        $svg .= "\t\t" . svg_text('Subtitles First Line', $dvb_active_rect_x, $dvb_active_rect_y + $sub_area_h * 6 / 8, $dvb_active_rect_w, $sub_area_h / 8, $dvb_active_rect_adj, $shade * 3) . "\n";
        $svg .= "\t\t" . svg_text('Subtitles Second Line', $dvb_active_rect_x, $dvb_active_rect_y + $sub_area_h * 7 / 8, $dvb_active_rect_w, $sub_area_h / 8, $dvb_active_rect_adj, $shade * 3) . "\n";
    }
    $svg .= svg_footer();
}



#
# ATSC Style
#

elsif ($style=~/^ATSC$/) {
    
    # Active Rectangle
    my $atsc_active_rect_x = $bar_w;
    my $atsc_active_rect_y = ($b_top ? 0 : $bar_h);
    my $atsc_active_rect_w = $cont_w;
    my $atsc_active_rect_h = $cont_h;
    my $atsc_active_rect_adj = ($bar_w > 0 ? 'lr' : '') . ($bar_h > 0 ? ($b_top ? 'b' : 'tb') : '');
    
    # Left / Top Shading
    my $atsc_lt_shade_x = $atsc_active_rect_x;
    my $atsc_lt_shade_y = $atsc_active_rect_y;
    my $atsc_lt_shade_w = ($opt_h > 0 ? $cont_w : $opt_w);
    my $atsc_lt_shade_h = ($opt_w > 0 ? $cont_h : $opt_h);
    my $atsc_lt_shade_adj = 
        ($bar_w > 0 ? 'lr' : ($opt_w > 0 ? 'r' : '')) . 
        (((! $b_top) && ($bar_h > 0)) ? ($opt_h > 0 ? 't' : 'tb') : ($opt_h > 0 ? 'b' : ''));
    
    # Right / Bottom Shading
    my $atsc_rb_shade_x = ($opt_w > 0 ? $bar_w + $cont_w - $opt_w : $atsc_active_rect_x);
    my $atsc_rb_shade_y = ($opt_h > 0 ? $atsc_active_rect_y + $atsc_active_rect_h - $opt_h : $atsc_active_rect_y);
    my $atsc_rb_shade_w = ($opt_h > 0 ? $cont_w : $opt_w);
    my $atsc_rb_shade_h = ($opt_w > 0 ? $cont_h : $opt_h);
    my $atsc_rb_shade_adj = 
        ($bar_w > 0 ? 'lr' : ($opt_w > 0 ? 'l' : '')) . 
        ($opt_h > 0 ? 't' : ($bar_h > 0 ? 'tb' : ''));
    
    # Main Circle
    my $atsc_main_circ_ry = $cont_h / 2;
    my $atsc_main_circ_rx = $atsc_main_circ_ry * $par_y / $par_x;
    my $atsc_main_circ_cx = $frame_w / 2;
    my $atsc_main_circ_cy = $frame_h / 2 - ($b_top ? $bar_h : 0);
    my $atsc_main_circ_adj = '';
    my $atsc_main_circ_rep = 0;
    
    # Left Circle
    my $atsc_left_circ_rx = ($cont43_w / 2 - $atsc_main_circ_rx) / 2;
    my $atsc_left_circ_ry = $atsc_left_circ_rx * $par_x / $par_y;
    my $atsc_left_circ_cx = $atsc_main_circ_cx - $atsc_main_circ_rx - $atsc_left_circ_rx;
    my $atsc_left_circ_cy = $atsc_main_circ_cy;
    my $atsc_left_circ_adj = 'r';
    
    # Right Circle
    my $atsc_right_circ_rx = $atsc_left_circ_rx;
    my $atsc_right_circ_ry = $atsc_left_circ_ry;
    my $atsc_right_circ_cx = $atsc_main_circ_cx + $atsc_main_circ_rx + $atsc_right_circ_rx;
    my $atsc_right_circ_cy = $atsc_main_circ_cy;
    my $atsc_right_circ_adj = 'l';
    
    # Left 14:9 Circle
    my $atsc_left149_circ_rx = ($cont149_w - $cont43_w) / 4;
    my $atsc_left149_circ_ry = $atsc_left149_circ_rx * $par_x / $par_y;
    my $atsc_left149_circ_cx = ($atsc_left149_circ_rx > 0 ? $atsc_left_circ_cx - $atsc_left_circ_rx - $atsc_left149_circ_rx : 0);
    my $atsc_left149_circ_cy = ($atsc_left149_circ_ry > 0 ? $atsc_main_circ_cy : 0);
    my $atsc_left149_circ_adj = 'r';
    
    # Left 14:9 Line
    my $atsc_left149_line_y2 = ($atsc_left149_circ_ry > 0 ? $atsc_active_rect_y + $atsc_active_rect_h : 0);
    my $atsc_left149_line_x = ($atsc_left149_line_y2 > 0 ? $atsc_active_rect_x + ($cont_w - $cont43_w) / 2 : 0);
    my $atsc_left149_line_y1 = ($atsc_left149_line_y2 > 0 ? $atsc_active_rect_y : 0);
    my $atsc_left149_line_adj = 'r';
    
    # Right 14:9 Circle
    my $atsc_right149_circ_rx = $atsc_left149_circ_rx;
    my $atsc_right149_circ_ry = $atsc_left149_circ_ry;
    my $atsc_right149_circ_cx = ($atsc_right149_circ_rx > 0 ? $atsc_right_circ_cx + $atsc_right_circ_rx + $atsc_right149_circ_rx : 0);
    my $atsc_right149_circ_cy = ($atsc_right149_circ_ry > 0 ? $atsc_main_circ_cy : 0);
    my $atsc_right149_circ_adj = 'l';
    
    # Right 14:9 Line
    my $atsc_right149_line_y2 = ($atsc_right149_circ_ry > 0 ? $atsc_active_rect_y + $atsc_active_rect_h : 0);
    my $atsc_right149_line_x = ($atsc_right149_line_y2 > 0 ? $atsc_active_rect_x + $atsc_active_rect_w - ($cont_w - $cont43_w) / 2 : 0);
    my $atsc_right149_line_y1 = ($atsc_right149_line_y2 > 0 ? $atsc_active_rect_y : 0);
    my $atsc_right149_line_adj = 'l';
    
    # Left 16:9 Circle
    my $atsc_left169_circ_rx = ($cont169_w - $cont149_w) / 4;
    my $atsc_left169_circ_ry = $atsc_left169_circ_rx * $par_x / $par_y;
    my $atsc_left169_circ_cx = ($atsc_left169_circ_rx > 0 ? $atsc_left149_circ_cx - $atsc_left149_circ_rx - $atsc_left169_circ_rx : 0);
    my $atsc_left169_circ_cy = ($atsc_left169_circ_ry > 0 ? $atsc_main_circ_cy : 0);
    my $atsc_left169_circ_adj = 'r';
    
    # Left 16:9 Line
    my $atsc_left169_line_y2 = ($atsc_left169_circ_ry > 0 ? $atsc_active_rect_y + $atsc_active_rect_h : 0);
    my $atsc_left169_line_x = ($atsc_left169_line_y2 > 0 ? $atsc_active_rect_x + ($cont_w - $cont149_w) / 2 : 0);
    my $atsc_left169_line_y1 = ($atsc_left169_line_y2 > 0 ? $atsc_active_rect_y : 0);
    my $atsc_left169_line_adj = 'r';
    
    # Right 16:9 Circle
    my $atsc_right169_circ_rx = $atsc_left169_circ_rx;
    my $atsc_right169_circ_ry = $atsc_left169_circ_ry;
    my $atsc_right169_circ_cx = ($atsc_right169_circ_rx > 0 ? $atsc_right149_circ_cx + $atsc_right149_circ_rx + $atsc_right169_circ_rx : 0);
    my $atsc_right169_circ_cy = ($atsc_right169_circ_ry > 0 ? $atsc_main_circ_cy : 0);
    my $atsc_right169_circ_adj = 'l';
    
    # Right 16:9 Line
    my $atsc_right169_line_y2 = ($atsc_right169_circ_ry > 0 ? $atsc_active_rect_y + $atsc_active_rect_h : 0);
    my $atsc_right169_line_x = ($atsc_right169_line_y2 > 0 ? $atsc_active_rect_x + $atsc_active_rect_w - ($cont_w - $cont149_w) / 2 : 0);
    my $atsc_right169_line_y1 = ($atsc_right169_line_y2 > 0 ? $atsc_active_rect_y : 0);
    my $atsc_right169_line_adj = 'l';
    
    # Left 64:27 Circle
    my $atsc_left6427_circ_rx = ($cont6427_w - $cont169_w) / 4;
    my $atsc_left6427_circ_ry = $atsc_left6427_circ_rx * $par_x / $par_y;
    my $atsc_left6427_circ_cx = ($atsc_left6427_circ_rx > 0 ? $atsc_left169_circ_cx - $atsc_left169_circ_rx - $atsc_left6427_circ_rx : 0);
    my $atsc_left6427_circ_cy = ($atsc_left6427_circ_ry > 0 ? $atsc_main_circ_cy : 0);
    my $atsc_left6427_circ_adj = 'r';
    
    # Left 64:27 Line
    my $atsc_left6427_line_y2 = ($atsc_left6427_circ_ry > 0 ? $atsc_active_rect_y + $atsc_active_rect_h : 0);
    my $atsc_left6427_line_x = ($atsc_left6427_line_y2 > 0 ? $atsc_active_rect_x + ($cont_w - $cont169_w) / 2 : 0);
    my $atsc_left6427_line_y1 = ($atsc_left6427_line_y2 > 0 ? $atsc_active_rect_y : 0);
    my $atsc_left6427_line_adj = 'r';
    
    # Right 64:27 Circle
    my $atsc_right6427_circ_rx = $atsc_left6427_circ_rx;
    my $atsc_right6427_circ_ry = $atsc_left6427_circ_ry;
    my $atsc_right6427_circ_cx = ($atsc_right6427_circ_rx > 0 ? $atsc_right169_circ_cx + $atsc_right169_circ_rx + $atsc_right6427_circ_rx : 0);
    my $atsc_right6427_circ_cy = ($atsc_right6427_circ_ry > 0 ? $atsc_main_circ_cy : 0);
    my $atsc_right6427_circ_adj = 'l';
    
    # Right 64:27 Line
    my $atsc_right6427_line_y2 = ($atsc_right6427_circ_ry > 0 ? $atsc_active_rect_y + $atsc_active_rect_h : 0);
    my $atsc_right6427_line_x = ($atsc_right6427_line_y2 > 0 ? $atsc_active_rect_x + $atsc_active_rect_w - ($cont_w - $cont169_w) / 2 : 0);
    my $atsc_right6427_line_y1 = ($atsc_right6427_line_y2 > 0 ? $atsc_active_rect_y : 0);
    my $atsc_right6427_line_adj = 'l';
    
    # Side Circles / Repetitions of Main Circle
    my $atsc_side_circ_rx = ($cont_w - $cont6427_w) / 4;
    while ($atsc_side_circ_rx > $atsc_main_circ_rx) {
        $atsc_side_circ_rx -= $atsc_main_circ_rx;
        $atsc_main_circ_rep++;
    }
    my $atsc_side_circ_ry = $atsc_side_circ_rx * $par_x / $par_y;
    
    # Left Full Circle
    my $atsc_leftfull_circ_rx = $atsc_side_circ_rx;
    my $atsc_leftfull_circ_ry = $atsc_side_circ_ry;
    my $atsc_leftfull_circ_cx = ($atsc_leftfull_circ_rx > 0 ? $atsc_left6427_circ_cx - $atsc_left6427_circ_rx - ($atsc_main_circ_rx * $atsc_main_circ_rep * 2) - $atsc_leftfull_circ_rx : 0);
    my $atsc_leftfull_circ_cy = ($atsc_leftfull_circ_ry > 0 ? $atsc_main_circ_cy : 0);
    my $atsc_leftfull_circ_adj = 'r';
    
    # Left Full Line
    my $atsc_leftfull_line_y2 = ($atsc_leftfull_circ_ry > 0 ? $atsc_active_rect_y + $atsc_active_rect_h : 0);
    my $atsc_leftfull_line_x = ($atsc_leftfull_line_y2 > 0 ? $atsc_active_rect_x + ($cont_w - $cont6427_w) / 2 : 0);
    my $atsc_leftfull_line_y1 = ($atsc_leftfull_line_y2 > 0 ? $atsc_active_rect_y : 0);
    my $atsc_leftfull_line_adj = 'r';
    
    # Right Full Circle
    my $atsc_rightfull_circ_rx = $atsc_side_circ_rx;
    my $atsc_rightfull_circ_ry = $atsc_side_circ_ry;
    my $atsc_rightfull_circ_cx = ($atsc_rightfull_circ_rx > 0 ? $atsc_right6427_circ_cx + $atsc_right6427_circ_rx + ($atsc_main_circ_rx * $atsc_main_circ_rep * 2) + $atsc_rightfull_circ_rx : 0);
    my $atsc_rightfull_circ_cy = ($atsc_rightfull_circ_ry > 0 ? $atsc_main_circ_cy : 0);
    my $atsc_rightfull_circ_adj = 'l';
    
    # Right Full Line
    my $atsc_rightfull_line_y2 = ($atsc_rightfull_circ_ry > 0 ? $atsc_active_rect_y + $atsc_active_rect_h : 0);
    my $atsc_rightfull_line_x = ($atsc_rightfull_line_y2 > 0 ? $atsc_active_rect_x + $atsc_active_rect_w - ($cont_w - $cont6427_w) / 2 : 0);
    my $atsc_rightfull_line_y1 = ($atsc_rightfull_line_y2 > 0 ? $atsc_active_rect_y : 0);
    my $atsc_rightfull_line_adj = 'l';
    
    # Left / Top Bar
    my $atsc_lt_bar_x = 0;
    my $atsc_lt_bar_y = 0;
    my $atsc_lt_bar_w = ($bar_h > 0 ? ($b_top ? 0 : $frame_w) : $bar_w);
    my $atsc_lt_bar_h = ($bar_w > 0 ? $frame_h : ($b_top ? 0 : $bar_h));
    my $atsc_lt_bar_adj = '';
    
    # Right / Bottom Bar
    my $atsc_rb_bar_x = ($bar_w > 0 ? $bar_w + $cont_w : 0);
    my $atsc_rb_bar_y = ($bar_h > 0 ? ($b_top ? $cont_h : $bar_h + $cont_h) : 0);
    my $atsc_rb_bar_w = ($bar_h > 0 ? $frame_w : $bar_w);
    my $atsc_rb_bar_h = ($bar_w > 0 ? $frame_h : ($b_top ? $bar_h * 2 : $bar_h));
    my $atsc_rb_bar_adj = '';
    
    # ATSC File Content
    $svg = svg_header(-1);
    $svg .= "\t\t" . svg_rect($atsc_active_rect_x, $atsc_active_rect_y, $atsc_active_rect_w, $atsc_active_rect_h, $atsc_active_rect_adj, 0) . "\n";
    if (($atsc_lt_shade_w > 0) && ($atsc_lt_shade_h > 0)) {
        $svg .= "\t\t" . svg_rect($atsc_lt_shade_x, $atsc_lt_shade_y, $atsc_lt_shade_w, $atsc_lt_shade_h, $atsc_lt_shade_adj, $shade) . "\n";
    }
    if (($atsc_rb_shade_w > 0) && ($atsc_rb_shade_h > 0)) {
        $svg .= "\t\t" . svg_rect($atsc_rb_shade_x, $atsc_rb_shade_y, $atsc_rb_shade_w, $atsc_rb_shade_h, $atsc_rb_shade_adj, $shade) . "\n";
    }
    $svg .= "\t\t" . svg_oval($atsc_main_circ_cx, $atsc_main_circ_cy, $atsc_main_circ_rx, $atsc_main_circ_ry, $atsc_main_circ_adj, -1) . "\n";
    $svg .= "\t\t" . svg_oval($atsc_left_circ_cx, $atsc_left_circ_cy, $atsc_left_circ_rx, $atsc_left_circ_ry, $atsc_left_circ_adj, -1) . "\n";
    $svg .= "\t\t" . svg_oval($atsc_right_circ_cx, $atsc_right_circ_cy, $atsc_right_circ_rx, $atsc_right_circ_ry, $atsc_right_circ_adj, -1) . "\n";
    if ($atsc_left149_line_y2 > 0) {
        $svg .= "\t\t" . svg_vertline($atsc_left149_line_x, $atsc_left149_line_y1, $atsc_left149_line_y2, $atsc_left149_line_adj) . "\n";
    }
    if ($atsc_left149_circ_rx > 0) {
        $svg .= "\t\t" . svg_oval($atsc_left149_circ_cx, $atsc_left149_circ_cy, $atsc_left149_circ_rx, $atsc_left149_circ_ry, $atsc_left149_circ_adj, -1) . "\n";
    }
    if ($atsc_right149_line_y2 > 0) {
        $svg .= "\t\t" . svg_vertline($atsc_right149_line_x, $atsc_right149_line_y1, $atsc_right149_line_y2, $atsc_right149_line_adj) . "\n";
    }
    if ($atsc_right149_circ_rx > 0) {
        $svg .= "\t\t" . svg_oval($atsc_right149_circ_cx, $atsc_right149_circ_cy, $atsc_right149_circ_rx, $atsc_right149_circ_ry, $atsc_right149_circ_adj, -1) . "\n";
    }
    if ($atsc_left169_line_y2 > 0) {
        $svg .= "\t\t" . svg_vertline($atsc_left169_line_x, $atsc_left169_line_y1, $atsc_left169_line_y2, $atsc_left169_line_adj) . "\n";
    }
    if ($atsc_left169_circ_rx > 0) {
        $svg .= "\t\t" . svg_oval($atsc_left169_circ_cx, $atsc_left169_circ_cy, $atsc_left169_circ_rx, $atsc_left169_circ_ry, $atsc_left169_circ_adj, -1) . "\n";
    }
    if ($atsc_right169_line_y2 > 0) {
        $svg .= "\t\t" . svg_vertline($atsc_right169_line_x, $atsc_right169_line_y1, $atsc_right169_line_y2, $atsc_right169_line_adj) . "\n";
    }
    if ($atsc_right169_circ_rx > 0) {
        $svg .= "\t\t" . svg_oval($atsc_right169_circ_cx, $atsc_right169_circ_cy, $atsc_right169_circ_rx, $atsc_right169_circ_ry, $atsc_right169_circ_adj, -1) . "\n";
    }
    if ($atsc_left6427_line_y2 > 0) {
        $svg .= "\t\t" . svg_vertline($atsc_left6427_line_x, $atsc_left6427_line_y1, $atsc_left6427_line_y2, $atsc_left6427_line_adj) . "\n";
    }
    if ($atsc_left6427_circ_rx > 0) {
        $svg .= "\t\t" . svg_oval($atsc_left6427_circ_cx, $atsc_left6427_circ_cy, $atsc_left6427_circ_rx, $atsc_left6427_circ_ry, $atsc_left6427_circ_adj, -1) . "\n";
    }
    if ($atsc_right6427_line_y2 > 0) {
        $svg .= "\t\t" . svg_vertline($atsc_right6427_line_x, $atsc_right6427_line_y1, $atsc_right6427_line_y2, $atsc_right6427_line_adj) . "\n";
    }
    if ($atsc_right6427_circ_rx > 0) {
        $svg .= "\t\t" . svg_oval($atsc_right6427_circ_cx, $atsc_right6427_circ_cy, $atsc_right6427_circ_rx, $atsc_right6427_circ_ry, $atsc_right6427_circ_adj, -1) . "\n";
    }
    if ($atsc_leftfull_line_y2 > 0) {
        $svg .= "\t\t" . svg_vertline($atsc_leftfull_line_x, $atsc_leftfull_line_y1, $atsc_leftfull_line_y2, $atsc_leftfull_line_adj) . "\n";
    }
    if ($atsc_leftfull_circ_rx > 0) {
        $svg .= "\t\t" . svg_oval($atsc_leftfull_circ_cx, $atsc_leftfull_circ_cy, $atsc_leftfull_circ_rx, $atsc_leftfull_circ_ry, $atsc_leftfull_circ_adj, -1) . "\n";
    }
    if ($atsc_rightfull_line_y2 > 0) {
        $svg .= "\t\t" . svg_vertline($atsc_rightfull_line_x, $atsc_rightfull_line_y1, $atsc_rightfull_line_y2, $atsc_rightfull_line_adj) . "\n";
    }
    if ($atsc_rightfull_circ_rx > 0) {
        $svg .= "\t\t" . svg_oval($atsc_rightfull_circ_cx, $atsc_rightfull_circ_cy, $atsc_rightfull_circ_rx, $atsc_rightfull_circ_ry, $atsc_rightfull_circ_adj, -1) . "\n";
    }
    for (my $i = 0; $i < $atsc_main_circ_rep; $i++) {
        $svg .= "\t\t" . svg_oval($atsc_leftfull_circ_cx + $atsc_leftfull_circ_rx + ($i * 2 + 1) * $atsc_main_circ_rx, $atsc_main_circ_cy, $atsc_main_circ_rx, $atsc_main_circ_ry - $s2, $atsc_leftfull_circ_adj, -1) . "\n";
        $svg .= "\t\t" . svg_oval($atsc_rightfull_circ_cx - $atsc_rightfull_circ_rx - ($i * 2 + 1) * $atsc_main_circ_rx, $atsc_main_circ_cy, $atsc_main_circ_rx, $atsc_main_circ_ry - $s2, $atsc_rightfull_circ_adj, -1) . "\n";
    }
    if (($atsc_lt_bar_w > 0) && ($atsc_lt_bar_h > 0)) {
        $svg .= "\t\t" . svg_rect($atsc_lt_bar_x, $atsc_lt_bar_y, $atsc_lt_bar_w, $atsc_lt_bar_h, $atsc_lt_bar_adj, 100) . "\n";
    }
    if (($atsc_rb_bar_w > 0) && ($atsc_rb_bar_h > 0)) {
        $svg .= "\t\t" . svg_rect($atsc_rb_bar_x, $atsc_rb_bar_y, $atsc_rb_bar_w, $atsc_rb_bar_h, $atsc_rb_bar_adj, 100) . "\n";
    }
    if ($b_sub) {
        my $sub_area_h = $atsc_active_rect_h + min($bar_h, $frame_h / 8);
        $svg .= "\t\t" . svg_text('Subtitles First Line', $atsc_active_rect_x, $atsc_active_rect_y + $sub_area_h * 6 / 8, $atsc_active_rect_w, $sub_area_h / 8, $atsc_active_rect_adj, $shade * 3) . "\n";
        $svg .= "\t\t" . svg_text('Subtitles Second Line', $atsc_active_rect_x, $atsc_active_rect_y + $sub_area_h * 7 / 8, $atsc_active_rect_w, $sub_area_h / 8, $atsc_active_rect_adj, $shade * 3) . "\n";
    }
    $svg .= svg_footer();
} 

#
# Implement other styles here
#

else {
    die "Style ${style} not implemented!";
}

# Validation only: Adjust quote to match Excel files
#$svg =~s/"/'/g;

# Save file to current directory
open SVG, ">$svg_filename";
print SVG $svg;
close SVG;

