(unresolved tag redirect /toonbots/toon-o-matic-take2/)
| October 21, 2000 | Panel layout |
| October 28, 2000 | Caption layout |
| up to Nov 10 or so | Various panel and caption features |
| November 12, 2000 | Rudimentary character sizing and placement |
| December 2000 | A first stab at variant structures for characters |
| January 1, 2001 | The first drawing commands, definition of named points for reference, etc. |
| April 2001 | Conversion of the original much more baroque program into a single script which outputs SVG code for ImageMagick to convert all in one fell swoop. You don't want to know how it used to be. |
| April 28, 2001 | Rework of text handling to use XML font summaries generated by my new tool ttfx. Captions again! |
| #^7nbsp; | |
| October, 2006 | Take 2: total rewrite from scratch. |
use Workflow::wftk::XML;
$toon = $ARGV[0];
$toon = 'cartoon.xml' unless $toon;
open IN, $toon or die "Can't open $toon for reading";
$input = xml_read (*IN);
close IN;
$tag = xml_attrval ($input, "tag");
die "No tag specified in cartoon definition" unless $tag;
$dir = $tag; # TODO: perhaps something more flexible.
chomp($date = `date`);
chomp($cwd = `pwd`);
system "rm -rf $dir";
mkdir $dir or die "Can't make directory $dir";
system "cp $toon $dir/cartoon.xml";
$background = xml_attrval ($input, "background");
if ($background == '') {
$panel_steps = <<EOF;
panels.xml: instance.xml
perl $cwd/build_panels.pl instance.xml > new-panels.xml
perl $cwd/synch_up.pl panels.xml new-panels.xml
EOF
} else {
system "cp $background $dir/background.gif";
$panel_steps = <<EOF;
panels.xml: instance.xml background.gif.info
perl $cwd/build_panels.pl instance.xml > new-panels.xml
perl $cwd/synch_up.pl panels.xml new-panels.xml
background.gif: cartoon.xml
perl retrieve_background.pl instance.xml
background.gif.info: background.gif
identify -format \@$cwd/identify_format.txt background.gif > background.gif.info
EOF
}
open MAKEFILE, ">$dir/Makefile";
print MAKEFILE <<"END_MAKEFILE";
# Makefile generated $date by Toon-o-Matic t2
# Contains no serviceable parts. Void where prohibited.
TAG=$tag;
TOMDIR=$cwd;
all: $dir.gif
cartoon.svg: panels.svg
perl $cwd/merge_svg.pl panels.svg panel-*.svg > new-cartoon.svg
perl $cwd/synch_up.pl cartoon.svg new-cartoon.svg
$dir.gif: cartoon.svg
convert cartoon.svg $dir.gif
cp $dir.gif ../../vivtek/pages/toonbots/current_test.gif
panels.svg: panels.xml Makefile.panels
perl $cwd/draw_panels.pl panels.xml > new-panels.svg
perl $cwd/synch_up.pl panels.svg new-panels.svg
$panel_steps
instance.xml: cartoon.xml
perl $cwd/instantiate.pl cartoon.xml > new-instance.xml
perl $cwd/synch_up.pl instance.xml new-instance.xml
Makefile.panels: panels.xml
perl $cwd/build_panel_make.pl $cwd panels.xml > Makefile.panels
make -f Makefile.panels
END_MAKEFILE
close MAKEFILE;
chdir $dir;
system "make";
exit;
|
See The layout module See Drawing (by writing SVG) |
use Workflow::wftk::XML; $toon = $ARGV[0]; $toon = 'cartoon.xml' unless $toon; open IN, $toon or die "Can't open $toon for reading"; $input = xml_read (*IN); close IN; ## TODO: processing to, y'know, instantiate. This will massage the input XML in place. print xml_string ($input); print "\n"; |
make can go on
its merry way without doing extra work.
$existing = $ARGV[0];
$new = $ARGV[1];
unless (-e $existing) {
system "mv $new $existing";
exit;
}
$diff = `diff $existing $new`;
if ($diff eq '') {
print "No change to $existing.\n";
unlink $new;
} else {
system "mv $new existing";
}
|
use Workflow::wftk::XML;
$top = shift @ARGV;
open IN, $top or die "Cannot open $top for reading";
$svg = xml_read (*IN);
close IN;
foreach $file (@ARGV) {
open IN, $file or die "Cannot open $file for reading";
$f = xml_read (*IN);
close IN;
xml_append ($svg, $f);
xml_append ($svg, xml_createtext ("\n"));
}
print xml_string ($svg) . "\n";
|
<cartoon background="littlebkgd.bmp"> <panel/> <panel> <panel/> <panel/> </panel> <panel/> <panel/> </cartoon> | ![]() |
<cartoon background="littlebkgd.bmp" rowformat="2-2"> <panel/> <panel/> <panel/> <panel/> </cartoon> | ![]() |
<cartoon background="littlebkgd.bmp" rowformat="2-1"> <panel> <panel> <panel/> <panel/> </panel> <panel/> </panel> <panel/> <panel/> <panel/> <panel/> </cartoon> | ![]() |
cartoon.xml
in the main cartooning directory. This all is supposed to run in one directory, by the way,
for ease of planning.
use Workflow::wftk::XML;
$toon = $ARGV[0];
$toon = 'instance.xml' unless $toon;
open IN, $toon or die "Can't open $toon for reading";
$cartoon = xml_read (*IN);
close IN;
$panel_structure = xml_create ("cartoon");
|
if (xml_attrval ($cartoon, 'background') ne '') {
$background = 'background.gif';
die "Can't find background $background" if (!-e $background);
} else {
$background = "null:";
}
xml_set ($panel_structure, 'background', $background);
|
null: let's default to a white background.
if (xml_attrval ($cartoon, 'gradient') ne '') {
$background = "gradient:" . xml_attrval ($cartoon, 'gradient');
xml_set ($panel_structure, 'background', $background);
} elsif ($background eq 'null:') {
xml_set ($panel_structure, 'color', xml_attrval ($cartoon, 'color') eq '' ? 'white' : xml_attrval ($cartoon, 'color'));
}
|
cartoon.xml. After this phase of processing, we'll
write the resulting XML to panels.xml. (Or actually, just to stdout; the makefile will direct it to the right place.)
xml_set ($panel_structure, 'linestyle', xml_attrval ($cartoon, 'linestyle') eq '' ? 'simple' : xml_attrval ($cartoon, 'linestyle')); xml_set ($panel_structure, 'rowdir', xml_attrval ($cartoon, 'rowdir') eq '' ? 'horiz' : xml_attrval ($cartoon, 'rowdir')); xml_set ($panel_structure, 'rowformat', xml_attrval ($cartoon, 'rowformat') eq '' ? '1' : xml_attrval ($cartoon, 'rowformat')); xml_set ($panel_structure, 'border', xml_attrval ($cartoon, 'border') eq '' ? '1' : xml_attrval ($cartoon, 'border')); xml_set ($panel_structure, 'gutter', xml_attrval ($cartoon, 'gutter') eq '' ? '7' : xml_attrval ($cartoon, 'gutter')); |
identify program to glean the size of
the background (if the background is an image).
I do that in a function far below, but the results get used here.
xml_set ($panel_structure, 'panel-x', '0');
xml_set ($panel_structure, 'panel-y', '0');
if (xml_attrval ($cartoon, 'background') ne '') {
open IN, 'background.gif.info';
$info = xml_read (*IN);
close IN;
xml_set ($panel_structure, 'panel-w', xmlobj_get ($info, '', 'something')); # TODO: fix this -- even though I haven't used it in six years.
xml_set ($panel_structure, 'panel-h', xmlobj_get ($info, '', 'something'));
}
|
-size directive in the background specifier for convert to work with.
$height = 200;
$explicit_size = 0;
if (xml_attrval ($cartoon, 'height') ne '') {
$height = xml_attrval ($cartoon, 'height');
$explicit_size = 1;
}
xml_set ($panel_structure, 'panel-h', $height);
$width=500;
if (xml_attrval ($cartoon, 'width') ne '') {
$width = xml_attrval ($cartoon, 'width');
$explicit_size = 1;
}
xml_set ($panel_structure, 'panel-w', $width);
if ($explicit_size) {
$background = "-size ${width}x$height $background";
xml_set ($panel_structure, 'background', $background);
}
|
$panel_number = 0;
@panel_list = ();
# OK, scan for panels. Just to make the whole thing more baroque, I'm putting the recursive subroutine
# right in the middle of our script; more top-level processing goes on below this. Isn't that cool?
panel_scan ($cartoon, $panel_structure);
sub panel_scan {
my $parent = shift;
my $outparent = shift;
my @panels = ();
foreach (xml_elements($parent)) {
next if $$_{name} ne 'panel';
push @panels, $_;
push @panel_list, $_;
}
if (!@panels) { # There is no panel structure in this panel -- thus it is a content panel. Write it out.
open OUT, ">panel-" . xml_attrval ($outparent, 'tag') . ".xml";
print OUT xml_string ($parent) . "\n";
close OUT; # Sale on aisle 7.
return;
}
# Find actual row structure.
my @rowformat = split /-/, xml_attrval ($parent, 'rowformat');
my @actual = ($#panels + 1);
if (xml_attrval ($parent, 'rowformat')) {
my $rowoffset = 0;
my $actual_offset = 0;
$rowformat[$rowoffset] = 1 if !$rowformat[$rowoffset];
while ($actual[$actual_offset] > $rowformat[$rowoffset]) {
push @actual, $actual[$actual_offset] - $rowformat[$rowoffset];
$actual[$actual_offset] = $rowformat[$rowoffset];
$actual_offset++;
$rowoffset++;
$rowoffset = 0 if $rowoffset > $#rowformat;
$rowformat[$rowoffset] = 1 if !$rowformat[$rowoffset];
}
}
# Stash it for debugging and all-around baroqueness.
xml_set ($outparent, 'actual-rowformat', join ('-', @actual));
# Now parcel out horizontal and vertical space based on the actual row structure.
my ($row_coord, $row_width, $col_coord, $col_width);
if (xml_attrval ($parent, 'rowdir') =~ /^v/) {
$row_coord = 'panel-x';
$row_width = 'panel-w';
$col_coord = 'panel-y';
$col_width = 'panel-h';
} else {
$row_coord = 'panel-y';
$row_width = 'panel-h';
$col_coord = 'panel-x';
$col_width = 'panel-w';
}
my $rowpos = xml_attrval ($outparent, $row_coord) + xml_attrval ($outparent, 'border');
my $rowtotal = xml_attrval ($outparent, $row_width) - 2 * xml_attrval ($outparent, 'border') - 1
- (xml_attrval ($outparent, 'gutter') * (@actual - 1));
my $rowportion = $rowtotal / @actual;
my $row_len;
foreach $row_len (@actual) {
next if !$row_len;
my $colpos = xml_attrval ($outparent, $col_coord) + xml_attrval ($outparent, 'border');
my $coltotal = xml_attrval ($outparent, $col_width) - 2 * xml_attrval ($outparent, 'border') - 1
- (xml_attrval ($outparent, 'gutter') * ($row_len - 1));
my $colportion = $coltotal / $row_len;
for (my $i=0; $i < $row_len; $i++) { # Step along the row...
$r = $rowpos;
$c = $colpos;
$rowpos =~ s/\..*//; # Integer portion only -- IM doesn't render lines well if they span pixel boundaries.
$colpos =~ s/\..*//;
$r -= $rowpos;
$c -= $colpos;
my $panel = shift @panels;
my $outpanel = xml_create ("panel");
$rwidth = $rowportion + 1;
$cwidth = $colportion + 1;
$rwidth =~ s/\..*//;
$cwidth =~ s/\..*//;
if (xml_attrval ($outparent, 'rowdir') eq 'horiz') {
$max = xml_attrval ($outparent, $row_coord) + xml_attrval ($outparent, $row_width);
if ($rowpos + $rwidth > $max) { $rwidth = $max - $rowpos; }
$max = xml_attrval ($outparent, $col_coord) + xml_attrval ($outparent, $col_width);
if ($colpos + $cwidth > $max) { $cwidth = $max - $colpos; }
}
xml_set ($outpanel, $row_coord, $rowpos);
xml_set ($outpanel, $col_coord, $colpos);
xml_set ($outpanel, $row_width, $rwidth);
xml_set ($outpanel, $col_width, $cwidth);
xml_set ($outpanel, 'linestyle', xml_attrval ($panel, 'linestyle'));
xml_set ($outpanel, 'linestyle', xml_attrval ($outparent, 'linestyle')) if xml_attrval ($outpanel, 'linestyle') eq '';
xml_set ($outpanel, 'arrow', xml_attrval ($panel, 'arrow')); # Added 2006-10-25.
xml_set ($outpanel, 'fill', xml_attrval ($panel, 'fill')); # Added 2006-10-25.
xml_set ($outpanel, 'svg-transform', xml_attrval ($panel, 'svg-transform')); # Added 2006-10-29.
$panel_number++;
if (xml_attrval ($outpanel, 'name') eq '') {
xml_set ($outpanel, 'name', "panel$panel_number");
}
xml_set ($outpanel, 'tag', $panel_number);
xml_set ($outpanel, 'rowdir', xml_attrval ($panel, 'rowdir'));
if (!xml_attrval ($outpanel, 'rowdir')) {
if (xml_attrval ($outparent, 'rowdir') =~ /^v/) {
xml_set ($outpanel, 'rowdir', 'horiz');
} else {
xml_set ($outpanel, 'rowdir', 'vert');
}
}
xml_set ($outpanel, 'gutter', xml_attrval ($panel, 'gutter'));
xml_set ($outpanel, 'gutter', xml_attrval ($outparent, 'gutter')) if !xml_attrval ($outpanel, 'gutter');
xml_append_pretty ($outparent, $outpanel);
my $panel_list_length = $#panel_list;
panel_scan ($panel, $outpanel);
if ($panel_list_length != $#panel_list) {
# Using a side effect is baroque, isn't it?
xml_set ($outpanel, 'linestyle', 'none');
}
$colpos += $c + $colportion + xml_attrval ($outparent, 'gutter');
}
$rowpos += $r + $rowportion + xml_attrval ($outparent, 'gutter');
}
}
|
foreach $panel (@panel_list) {
# Background color or gradient.
$gradient = '';
if (xml_attrval ($panel, 'color') ne '') {
$gradient = xml_attrval ($panel, 'color') . '-' . xml_attrval ($panel, 'color');
}
if (xml_attrval ($panel, 'gradient') ne '') {
$gradient = xml_attrval ($panel, 'gradient');
}
next if $gradient eq '';
print "Creating background image for " . xml_attrval ($panel, 'name') . "\n";
xml_set ($panel, 'background', xml_attrval ($panel, 'name') . "-bg.gif");
system "convert -size " . xml_attrval ($panel, 'panel-w') . "x" . xml_attrval ($panel, 'panel-h') . " gradient:$gradient " . xml_attrval ($panel, 'background');
}
|
print xml_string ($panel_structure); print "\n"; |
use Workflow::wftk::XML; $cwd = $ARGV[0]; $toon = $ARGV[1]; $toon = 'instance.xml' unless $toon; open IN, $toon or die "Can't open $toon for reading"; $panels = xml_read (*IN); close IN; chomp($date = `date`); |
scan_panels ($panels);
sub scan_panels {
my $panel = shift;
foreach $elem (xml_elements ($panel)) {
next unless ($$elem{name} eq 'panel');
$x{xml_attrval ($elem, 'tag')} = xml_attrval ($elem, 'panel-x');
$y{xml_attrval ($elem, 'tag')} = xml_attrval ($elem, 'panel-y');
$w{xml_attrval ($elem, 'tag')} = xml_attrval ($elem, 'panel-w');
$h{xml_attrval ($elem, 'tag')} = xml_attrval ($elem, 'panel-h');
scan_panels ($elem);
}
}
@panel_list = sort { $a <=> $b } keys (%x);
|
$makes = '';
$panels_list = '';
foreach $panel (@panel_list) {
open IN, "panel-$panel.xml";
$pxml = xml_read (*IN);
close IN;
@svgs = ();
$caption_count = 0;
foreach $elem (xml_elements ($pxml)) {
if (xml_name ($elem) eq 'caption') {
$caption_count += 1;
$tag = "caption-$panel-$caption_count";
$rotate = 0;
$direction = xml_attrval ($elem, "direction");
if ($direction eq "up") {
$rotate = 270;
} elsif ($direction eq "down") {
$rotate = 90;
} elsif ($direction eq "inverted") {
$rotate = 180;
} else {
$rotate = xml_attrval ($elem, "rotate");
}
if ($rotate == 0) {
$makes .= <<"END_MAKE";
$tag.info: $tag.xml
perl $cwd/draw_caption.pl $tag.xml no-info $w{$panel} $h{$panel} 0 > $tag-raw.svg
convert -trim $tag-raw.svg $tag.gif
identify -format \@$cwd/identify_format.txt $tag.gif > $tag.info
$tag.svg: $tag.info
perl $cwd/draw_caption.pl $tag.xml $tag.info $w{$panel} $h{$panel} 0 > $tag.svg
END_MAKE
} else {
$makes .= <<"END_MAKE";
$tag.info: $tag.xml
perl $cwd/draw_caption.pl $tag.xml no-info $w{$panel} $h{$panel} 0 > $tag-raw.svg
convert -trim $tag-raw.svg $tag-raw.gif
identify -format \@$cwd/identify_format.txt $tag-raw.gif > $tag.info
$tag-r$rotate.info: $tag.xml $tag.info
perl $cwd/draw_caption.pl $tag.xml $tag.info 0 0 0 > $tag-boxed.svg
convert -trim $tag-boxed.svg $tag-boxed.gif
convert -rotate $rotate $tag-boxed.gif $tag-r$rotate.gif
identify -format \@$cwd/identify_format.txt $tag-r$rotate.gif > $tag-r$rotate.info
$tag.svg: $tag-r$rotate.info
perl $cwd/draw_caption.pl $tag.xml $tag-r$rotate.info $w{$panel} $h{$panel} $rotate > $tag.svg
END_MAKE
}
push @svgs, "$tag.svg";
open OUT, ">$tag.xml";
print OUT xml_string ($elem) . "\n";
close OUT;
}
}
next unless @svgs;
$panels_list .= " panel-$panel.svg";
$svg_makes = '';
foreach $s (@svgs) { $svg_makes .= " $s"; }
$makes .= <<"END_MAKE";
panel-$panel.svg: $svg_makes;
perl $cwd/build_panel_g.pl panel-$panel.xml $x{$panel} $y{$panel} > panel-$panel-g.svg
perl $cwd/merge_svg.pl panel-$panel-g.svg $svg_makes > new-panel-$panel.svg
perl $cwd/synch_up.pl panel-$panel.svg new-panel-$panel.svg
END_MAKE
}
|
print <<"END_MAKEFILE"; # Panel Makefile generated $date by Toon-o-Matic t2 # Contains no serviceable parts. Batteries not included. # Void in NH, VT, and U.S. Minor Outlying Islands. TOMDIR=$cwd; all: $panels_list $makes END_MAKEFILE |
$panel = $ARGV[0]; print " |
use Workflow::wftk::XML;
$in = $ARGV[0];
$in = 'panels.xml' unless $in;
open IN, $in or die "Can't open $in for reading";
$panels = xml_read (*IN);
close IN;
$svg = xml_create ("svg");
xml_append ($svg, xml_createtext("\n"));
xml_set ($svg, "height", xml_attrval ($panels, "panel-h"));
xml_set ($svg, "width", xml_attrval ($panels, "panel-w") + 2); # Note: adding 2 because of odd clipping behavior.
if (xml_attrval ($panels, "image") ne '') {
$cmd = xml_create ("image");
xml_set ($cmd, "xlink:href", xml_attrval ($panels, "image"));
xml_set ($cmd, "x", "0");
xml_set ($cmd, "y", "0");
xml_append ($svg, $cmd);
xml_append ($svg, xml_createtext("\n"));
} elsif (xml_attrval ($panels, "color") ne '') {
$cmd = xml_create ("rect");
xml_set ($cmd, "height", xml_attrval ($panels, "panel-h"));
xml_set ($cmd, "width", xml_attrval ($panels, "panel-w"));
xml_set ($cmd, "style", "fill: " . xml_attrval ($panels, 'color'));
xml_append ($svg, $cmd);
xml_append ($svg, xml_createtext("\n"));
}
|
$p{'dummy'} = '';
$s{'dummy'} = '';
$x{'dummy'} = 0;
$y{'dummy'} = 0;
$w{'dummy'} = 0;
$h{'dummy'} = 0;
$on_top_of{'dummy'} = 0;
scan_panels ($panels);
sub scan_panels {
my $panel = shift;
foreach $elem (xml_elements ($panel)) {
next unless ($$elem{name} eq 'panel');
$p{xml_attrval ($elem, 'tag')} = $elem;
$x{xml_attrval ($elem, 'tag')} = xml_attrval ($elem, 'panel-x');
$y{xml_attrval ($elem, 'tag')} = xml_attrval ($elem, 'panel-y');
$w{xml_attrval ($elem, 'tag')} = xml_attrval ($elem, 'panel-w');
$h{xml_attrval ($elem, 'tag')} = xml_attrval ($elem, 'panel-h');
$s{xml_attrval ($elem, 'tag')} = '';
$on_top_of{xml_attrval ($elem, 'tag')} = '';
scan_panels ($elem);
}
}
|
draw_panels ($panels);
sub draw_panels {
my $panel = shift;
foreach $elem (xml_elements ($panel)) {
next unless ($$elem{name} eq 'panel');
my $tag = xml_attrval ($elem, 'tag');
# Background image, if any.
if (xml_attrval ($elem, 'background') ne '') {
$cmd = xml_create ("image");
xml_set ($cmd, "xlink:href", xml_attrval ($elem, "background"));
xml_set ($cmd, "x", xml_attrval ($elem, 'panel-x'));
xml_set ($cmd, "y", xml_attrval ($elem, 'panel-y'));
xml_set ($cmd, "width", xml_attrval ($elem, 'panel-w'));
xml_set ($cmd, "height", xml_attrval ($elem, 'panel-h'));
xml_append ($svg, $cmd);
xml_append ($svg, xml_createtext("\n"));
}
# Now the panel's polyline, if any.
$line = ''; $fill = '';
$style = xml_attrval ($elem, 'color');
$fill = xml_attrval ($elem, 'fill');
$style = "fill:$fill" if $fill ne '';
$style = 'fill:none' if $fill eq 'none' || $fill eq '';
if (xml_attrval ($elem, 'linestyle') ne 'none') {
$style .= '; ' if $style ne '';
$color = xml_attrval ($elem, 'color');
$color = xml_attrval ($elem, 'stroke') if $color;
$color = 'black' if $color eq '';
$line = xml_attrval ($elem, 'line');
$line = xml_attrval ($elem, 'stroke-width') if $line eq '';
$line = '1' if $line eq '';
$style .= "stroke:$color; stroke-width:$line";
}
if ($style ne '') {
my $arrow = xml_attrval ($elem, "arrow");
my $x1 = xml_attrval ($elem, 'panel-x');
my $y1 = xml_attrval ($elem, 'panel-y');
my $w = xml_attrval ($elem, 'panel-w');
my $h = xml_attrval ($elem, 'panel-h');
my $x2 = $x1 + $w;
my $y2 = $y1 + $h;
if ($arrow eq 'next') {
if (!xml_is_element ($p{$tag+1})) {
$arrow = '';
} else {
$xdelta = $x{$tag+1} - $x{$tag};
$ydelta = $y{$tag+1} - $y{$tag};
if ($xdelta > 0 && $xdelta > $ydelta) {
$arrow = 'right';
} elsif ($xdelta < 0 && $xdelta < $ydelta) {
$arrow = 'left';
} elsif ($ydelta > 0) {
$arrow = 'bottom';
} elsif ($ydelta < 0) {
$arrow = 'top';
} else {
$arrow = '';
}
}
}
$cmd = xml_create ("polyline");
$s{$tag} = $cmd;
xml_set ($cmd, "transform", xml_attrval ($elem, 'svg-transform'));
xml_set ($cmd, 'style', $style);
xml_set ($cmd, 'arrow', $arrow);
$awidth = 50;
$alength = 50;
if ($arrow eq 'top') {
$midpoint = $x1 + $w/2;
$abase1 = $midpoint - $awidth/4;
$abase2 = $midpoint + $awidth/4;
$atip = $y1 - $alength;
$aflare = $y1 - $alength/2;
$aflank1 = $midpoint - $awidth/2;
$aflank2 = $midpoint + $awidth/2;
$atip_x = $midpoint;
$atip_y = $atip;
$points = "$x1,$y1 $abase1,$y1 $abase1,$aflare $aflank1,$aflare $midpoint,$atip ";
$points .= "$aflank2,$aflare $abase2,$aflare $abase2,$y1 $x2,$y1 $x2,$y2 $x1,$y2 $x1,$y1";
} elsif ($arrow eq 'bottom') {
$midpoint = $x1 + $w/2;
$abase1 = $midpoint - $awidth/4;
$abase2 = $midpoint + $awidth/4;
$atip = $y2 + $alength;
$aflare = $y2 + $alength/2;
$aflank1 = $midpoint - $awidth/2;
$aflank2 = $midpoint + $awidth/2;
$atip_x = $midpoint;
$atip_y = $atip;
$points = "$x1,$y1 $x2,$y1 $x2,$y2 $abase2,$y2 $abase2,$aflare $aflank2,$aflare ";
$points .= "$midpoint,$atip $aflank1,$aflare $abase1,$aflare $abase1,$y2 $x1,$y2 $x1,$y1";
} elsif ($arrow eq 'left') {
$midpoint = $y1 + $h/2;
$abase1 = $midpoint - $awidth/4;
$abase2 = $midpoint + $awidth/4;
$atip = $x1 - $alength;
$aflare = $x1 - $alength/2;
$aflank1 = $midpoint - $awidth/2;
$aflank2 = $midpoint + $awidth/2;
$atip_x = $atip;
$atip_y = $midpoint;
$points = "$x1,$y2 $x2,$y1 $x2,$y2 $x1,$y2 $x1,$abase2 $aflare,$abase2 $aflare,$aflank2 ";
$points .= "$atip,$midpoint $aflare,$aflank1 $aflare,$abase1 $x1,$abase1 $x1,$y1";
} elsif ($arrow eq 'right') {
$midpoint = $y1 + $h/2;
$abase1 = $midpoint - $awidth/4;
$abase2 = $midpoint + $awidth/4;
$atip = $x2 + $alength;
$aflare = $x2 + $alength/2;
$aflank1 = $midpoint - $awidth/2;
$aflank2 = $midpoint + $awidth/2;
$atip_x = $atip;
$atip_y = $midpoint;
$points = "$x1,$y1 $x2,$y1 $x2,$abase1 $aflare,$abase1 $aflare,$aflank1 $atip,$midpoint ";
$points .= "$aflare,$aflank2 $aflare,$abase2 $x2,$abase2 $x2,$y2 $x1,$y2 $x1,$y1";
} else {
$points = "$x1,$y1 $x2,$y1 $x2,$y2 $x1,$y2 $x1,$y1";
$atip_x = 0;
$atip_y = 0;
}
xml_set ($cmd, "points", $points);
if ($atip_x != 0 && $atip_y != 0) {
foreach $otag (keys(%p)) {
next if $tag eq $otag;
if ($atip_x > $x{$otag} &&
$atip_x < $x{$otag} + $w{$otag} &&
$atip_y > $y{$otag} &&
$atip_y < $y{$otag} + $h{$otag}) {
$on_top_of{$tag} .= " $otag ";
}
}
}
}
draw_panels ($elem); # Now we draw the panel's contents onto the panel.
}
}
|
sub on_top_of {
return 1 if $on_top_of{$a} =~ / $b /;
return -1 if $on_top_of{$b} =~ / $a /;
return 0;
}
foreach $tag (sort on_top_of keys(%s)) {
xml_append_pretty ($svg, $s{$tag}) if xml_is_element ($s{$tag});
}
print xml_string ($svg) . "\n";
|
use Workflow::wftk::XML;
$in = $ARGV[0];
$info = $ARGV[1];
$panel_w = $ARGV[2];
$panel_h = $ARGV[3];
$rotate = $ARGV[4];
open IN, $in or die "Can't open $in for reading";
$in = xml_read (*IN);
close IN;
$string = xml_stringcontent ($in);
$string =~ s/\n//g;
$string =~ s/<br\/>/\n/g;
sub make_style {
$color = xml_attrval ($in, 'color');
$color = xml_attrval ($in, 'fgcolor') unless $color;
$color = 'black' unless $color;
$size = xml_attrval ($in, 'size');
$size = 16 unless $size;
$stroke = xml_attrval ($in, 'stroke');
$stroke = 'none' unless $stroke;
$family = xml_attrval ($in, 'font');
$family = 'verdana' unless $family;
$style = xml_attrval ($in, 'style');
$style = "; $style" if $style;
foreach $attr ('text-decoration', 'font-weight', 'font-style') {
my $v = xml_attrval ($in, $attr);
if ($v) { $style .= "; $attr:" . $v; }
}
return "font-family:\@fonts/$family.ttf; font-size:$size; fill:$color; stroke:$stroke$style";
}
sub copy_text_attributes {
my ($text, $in) = @_;
foreach $attr ('text-decoration', 'font-weight', 'font-style') {
xml_set ($text, $attr, xml_attrval ($in, $attr));
}
}
if ($info eq 'no-info') {
# First run through.
$svg = xml_create ('svg');
xml_set ($svg, 'width', $panel_w);
xml_set ($svg, 'height', $panel_h);
$text = xml_create ('text');
xml_set ($text, 'x', '0');
xml_set ($text, 'y', '0');
xml_set ($text, 'style', make_style ($in));
#copy_text_attributes ($text, $in);
xml_append ($text, xml_createtext ($string));
xml_append_pretty ($svg, $text);
print xml_string ($svg) . "\n";
exit;
}
# Second or third run through, we have an info file from 'identify'.
open IN, $info or die "Can't open $info for reading";
$info = xml_read (*IN);
close IN;
if ($rotate) {
# if the info file is from a rotated graphic, third time through.
$h = xml_attrval ($info, 'height');
$w = xml_attrval ($info, 'width');
$svg = xml_create ('g');
$image = xml_create ('image');
xml_set ($image, 'x', '0');
xml_set ($image, 'y', '0');
xml_set ($image, 'height', $h);
xml_set ($image, 'width', $w);
xml_set ($image, 'xlink:href', xml_attrval ($info, 'file'));
if ($rotate == 90 || $rotate == 180 || $rotate == 270) {
# If the rotation is to a right angle, no need to clip. Just place the image and go on.
xml_append_pretty ($svg, $image);
} else {
# This is hard, so I'm not doing it yet. It requires trigonometry, and my brain hurts from it.
xml_append_pretty ($svg, $image);
}
} else {
# Second time through: draw text straight, with box.
$margin = xml_attrval ($in, 'box-margin');
$margin = 2 unless $margin;
$size = xml_attrval ($in, 'size');
$size = 16 unless $size;
$h = xml_attrval ($info, 'height') + $margin*2 + $size; # Font size correction because trimming cuts off at top as well...
$w = xml_attrval ($info, 'width') + $margin*2 + $size;
# Now build the SVG for the overall caption.
$svg = xml_create ('g');
$text = xml_create ('text');
xml_set ($text, 'x', $margin + $size/2);
xml_set ($text, 'y', $margin);
xml_set ($text, 'style', make_style ($in));
#copy_text_attributes ($text, $in);
xml_append ($text, xml_createtext ($string));
$box = xml_create ('rect');
xml_set ($box, 'x', '0');
xml_set ($box, 'y', '0');
xml_set ($box, 'width', $w);
xml_set ($box, 'height', $h);
$stroke = xml_attrval ($in, 'box-stroke');
$stroke = 'black' unless $stroke;
$width = xml_attrval ($in, 'box-line');
$width = '1' unless $width;
$fill = xml_attrval ($in, 'box-fill');
$fill = 'white' unless $fill;
$style = xml_attrval ($in, 'box-style');
$style = "; $style" if $style;
if (xml_attrval ($in, 'box') eq 'no') {
$stroke = 'none';
$fill = 'none';
}
xml_set ($box, 'style', "stroke:$stroke; stroke-width:$width; fill:$fill$style");
xml_append_pretty ($svg, $box);
xml_append_pretty ($svg, $text);
# If there is a direction, we rotate the text by a certain number of degrees and if the text is now vertical we need to
# swap its height and width for location calculation.
# November 1, 2006 - doesn't work due to IM bugs. Someday we might want to revisit this; it generates good SVG and SHOULD work.
#$direction = xml_attrval ($in, 'direction');
#$rotated = 0;
#$midpoint = ($w/2) . "," . ($h/2);
#$negmidpoint = (-$w/2) . "," . (-$h/2);
#if ($direction eq 'up') {
# ($h, $w) = ($w, $h);
# $rotated = 1;
# xml_set ($svg, 'transform', "translate($midpoint) rotate(-90) translate($negmidpoint)");
#} elsif ($direction eq 'down') {
# ($h, $w) = ($w, $h);
# $rotated = 1;
# xml_set ($svg, 'transform', "translate($midpoint) rotate(90) translate($negmidpoint)");
#} elsif ($direction eq 'inverted') {
# $rotated = 1;
# xml_set ($svg, 'transform', "translate($midpoint) rotate(180) translate($negmidpoint)");
#}
#
#if (xml_attrval ($in, 'rotate')) { # Arbitrary rotation -- doesn't affect placement (I don't care about it *that* much)
# $rotated = 1;
# $rotation = xml_attrval ($in, 'rotate');
#
# $svg = transform_svg ($svg, "translate($negmidpoint)");
# $svg = transform_svg ($svg, "rotate($rotation)");
# $svg = transform_svg ($svg, "translate($midpoint)");
#}
#
#if ($rotated) {
# $midgroup = $svg;
# $svg = xml_create ('g');
# xml_append_pretty ($svg, $midgroup);
#}
}
# Now figure out the location on the panel and set a transformation on the overall 'g' (group) tag, and output that puppy, it's done.
# Caveat: if the panel width and height are 0, then this is the second time through and there will be a third time. Act accordingly.
if ($panel_h == 0 && $panel_w == 0) {
$g = $svg;
xml_set ($g, 'transform', 'translate(5,5)');
$svg = xml_create ("svg");
xml_set ($svg, 'height', $h+10);
xml_set ($svg, 'width', $w+10);
xml_append_pretty ($svg, $g);
} else {
xml_set ($svg, 'transform', "translate(" . calculate_location (xml_attrval ($in, 'location'), $h, $w, $panel_h, $panel_w) . ")");
}
print xml_string ($svg) . "\n";
sub transform_svg {
my ($svg, $t) = @_;
my $s = xml_create ("g");
xml_append_pretty ($s, $svg);
xml_set ($s, 'transform', $t);
return $s;
}
sub calculate_location {
my ($location, $h, $w, $panel_h, $panel_w) = @_;
if ($panel_h == 0 && $panel_w == 0) { return "0,0"; }
my $x;
my $y;
my @loc = split /,/, $location;
if ($loc[0] =~ /^top/) {
$y = 0;
} elsif ($loc[0] =~ /^middle/ || $loc[0] =~ /^center/) {
$y = int(($panel_h - $h) / 2);
} else {
$y = $panel_h - $h;
}
if ($loc[0] =~ /right$/) {
$x = $panel_w - $w;
} elsif ($loc[0] =~ /middle$/ || $loc[0] =~ /center$/) {
$x = int(($panel_w - $w) / 2);
} else {
$x = 0;
}
shift @loc;
foreach my $offset (@loc) {
$offset =~ s/^ *//;
my @o = split / /, $offset;
if ($o[0] eq 'up') {
$y -= $o[1];
} elsif ($o[0] eq 'down') {
$y += $o[1];
} elsif ($o[0] eq 'left') {
$x -= $o[1];
} elsif ($o[0] eq 'right') {
$x += $o[1];
}
}
return "$x,$y";
}
|
| This code and documentation are released under the terms of the GNU license. They are additionally copyright (c) 2001-2006, Vivtek. All rights reserved except those explicitly granted under the terms of the GNU license. This presentation prepared using LPML. Try literate programming. You'll like it. |