[svg-comic commit] r2 - in trunk: . lib lib/SVG lib/SVG/Comic lib/SVG/Comic/Character t

2 views
Skip to first unread message

codesite...@google.com

unread,
Mar 18, 2008, 3:59:04 PM3/18/08
to svg-...@googlegroups.com
Author: jacob.silvia
Date: Fri Mar 14 13:59:29 2008
New Revision: 2

Added:
trunk/Changes
trunk/MANIFEST
trunk/Makefile.PL
trunk/README
trunk/lib/
trunk/lib/SVG/
trunk/lib/SVG/Comic/
trunk/lib/SVG/Comic.pm
trunk/lib/SVG/Comic/Character/
trunk/lib/SVG/Comic/Character.pm
trunk/lib/SVG/Comic/Character/Dick.scc
trunk/lib/SVG/Comic/Character/Generic.scc
trunk/lib/SVG/Comic/Character/Jane.scc
trunk/lib/SVG/Comic/Panel.pm
trunk/t/
trunk/t/SVG-Comic.t

Log:
initial src'

Added: trunk/Changes
==============================================================================
--- (empty file)
+++ trunk/Changes Fri Mar 14 13:59:29 2008
@@ -0,0 +1,6 @@
+Revision history for Perl extension SVG::Comic.
+
+0.01 Tue Mar 11 19:09:04 2008
+ - original version; created by h2xs 1.23 with options
+ -X -n SVG::Comic
+

Added: trunk/MANIFEST
==============================================================================
--- (empty file)
+++ trunk/MANIFEST Fri Mar 14 13:59:29 2008
@@ -0,0 +1,6 @@
+Changes
+Makefile.PL
+MANIFEST
+README
+t/SVG-Comic.t
+lib/SVG/Comic.pm

Added: trunk/Makefile.PL
==============================================================================
--- (empty file)
+++ trunk/Makefile.PL Fri Mar 14 13:59:29 2008
@@ -0,0 +1,12 @@
+use 5.010000;
+use ExtUtils::MakeMaker;
+# See lib/ExtUtils/MakeMaker.pm for details of how to influence
+# the contents of the Makefile that is written.
+WriteMakefile(
+ NAME => 'SVG::Comic',
+ VERSION_FROM => 'lib/SVG/Comic.pm', # finds $VERSION
+ PREREQ_PM => {}, # e.g., Module::Name => 1.1
+ ($] >= 5.005 ? ## Add these new keywords supported since 5.005
+ (ABSTRACT_FROM => 'lib/SVG/Comic.pm', # retrieve abstract from module
+ AUTHOR => 'A. U. Thor <a.u....@a.galaxy.far.far.away>') : ()),
+);

Added: trunk/README
==============================================================================
--- (empty file)
+++ trunk/README Fri Mar 14 13:59:29 2008
@@ -0,0 +1,40 @@
+SVG-Comic version 0.01
+======================
+
+The README is used to introduce the module and provide instructions on
+how to install the module, any machine dependencies it may have (for
+example C compilers and installed libraries) and any other information
+that should be provided before the module is installed.
+
+A README file is required for CPAN modules since CPAN extracts the
+README file from a module distribution so that people browsing the
+archive can use it get an idea of the modules uses. It is usually a
+good idea to provide version information here so that people can
+decide whether fixes for the module are worth downloading.
+
+INSTALLATION
+
+To install this module type the following:
+
+ perl Makefile.PL
+ make
+ make test
+ make install
+
+DEPENDENCIES
+
+This module requires these other modules and libraries:
+
+ blah blah blah
+
+COPYRIGHT AND LICENCE
+
+Put the correct copyright and licence information here.
+
+Copyright (C) 2008 by A. U. Thor
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself, either Perl version 5.10.0 or,
+at your option, any later version of Perl 5 you may have available.
+
+

Added: trunk/lib/SVG/Comic.pm
==============================================================================
--- (empty file)
+++ trunk/lib/SVG/Comic.pm Fri Mar 14 13:59:29 2008
@@ -0,0 +1,473 @@
+package SVG::Comic;
+
+use warnings;
+use strict;
+use vars qw($VERSION $AUTOLOAD);
+use Carp;
+use SVG::Comic::Panel;
+
+=head1 NAME
+
+SVG::Comic - Generate SVG Comics on the Fly!
+
+=head1 VERSION
+
+Version 0.1.1
+
+=cut
+
+$VERSION = '0.1.1';
+
+my %fields = (
+ height => 233,
+ width => 610,
+ bgcolor => 'black',
+ title => undef,
+ author => undef,
+ subtitle => undef,
+ copyright => undef,
+ fontsize => 10,
+ textcolor => 'white',
+ gutter => 5,
+ panels => [],
+);
+
+sub new ($;@) {
+ my ($this, %attrs) = @_;
+ my $class = ref $this || $this;
+ my $self;
+
+ foreach my $attr (keys %fields) {
+ $attrs{$attr} ||= $fields{$attr};
+ }
+
+ $self = {
+ _permitted => \%fields,
+ %attrs,
+ };
+
+ bless $self, $class;
+
+ $self->initialize();
+
+ return $self;
+}
+
+sub initialize {
+ my $self = shift;
+
+ my $count = @{$self->panels};
+
+ unless ($count) {
+ $self->panels([
+ new SVG::Comic::Panel,
+ new SVG::Comic::Panel,
+ new SVG::Comic::Panel,
+ ]);
+ }
+}
+
+=head1 SYNOPSIS
+
+The SVG::Comic module will take an input text (see the Formatting instructions), and generate
+an SVG Comic out of it.
+
+The intent of this was to allow those with no comic-drawing skillz, but severe humor tendencies,
+to create a comic, and let Perl do all the artwork. There are several side effects, such as
+simple webcomic creation using CGI and just another way to have fun with the Internet and Perl.
+
+ use SVG::Comic;
+
+ my $sc = SVG::Comic->new(
+ title => "A Very Funny Webcomic",
+ author => "Jacob P. Silvia",
+ subtitle => '"Lorem Ipsum"',
+ copyright => "(c) 2007, Jacob P. Silvia. All Rights Reserved.",
+ );
+
+ $sc->panels->[0]->dialogue([
+ Dick => "Lorem ipsum dolor sit amet, consectetuer adipiscing elit.",
+ Jane => "",
+ ]);
+
+ $sc->panels->[1]->dialogue([
+ Jane => "Sed blandit dui sit amet turpis mollis vulputae.",
+ Dick => "Maecenas sodales.",
+ ]);
+
+ $sc->panels->[2]->dialogue([
+ Jane => "Phasellus tritique urna a tortor.",
+ Dick => "",
+ ]);
+
+ $sc->display;
+
+=head1 INPUT FILE
+
+You may be wondering if instead, you can use an input file? Not yet. But soon.
+Below is my potential specification for such a file.
+
+The input file requires a certain format to work correctly. Reading comics should
+show you that spacing makes or breaks a particular comic, that is why we leave the
+humor bit up to you. Once Humor::Sense is perfected, this will no longer be an issue.
+
+Within your comic, you have speakers, dialogue, and panels. Here's a sample of
+how to write your input files to take all these into consideration:
+
+ #TITLE A Very Funny Webcomic
+ #SUBTITLE "Lorem Ipsum"
+ #BYLINE Jacob P. Silvia
+ #COPYRIGHT (c) 2007, Jacob P. Silvia. All rights reserved.
+ Dick: Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
+ Jane:
+ ===
+ Jane: Sed blandit dui sit amet turpis mollis vulputae.
+ Dick: Maecenas sodales.
+ # I want this note to appear as a comment in the SVG code.
+ ===
+ Jane: Phasellus tritique urna a tortor.
+ Dick:
+
+What this sample will do is generate a three panel comic featuring Dick and Jane.
+In the first panel, Dick will say his line. In the second panel, Jane will say her
+line and then Dick will say his. Finally, in the third and last panel, Jane will
+utter her stinger of a punchline!
+
+Until more features are implemented, it's like this:
+
+#TITLE is the title of the series. "Calvin and Hobbes" is an example of a #TITLE.
+(Note: I am not endorsing using "Calvin and Hobbes" as the title of your comic.) Default value is blank.
+
+#SUBTITLE is the title of the epsiode. For example, if the particular comic shown (that is, the
+episode), features the regular cast performing musical numbers where no musical numbers would
+normally be performed within said series, you could entitle the episode "Once Again With Feeling", or
+some such similar phrase. Default value is blank.
+
+#BYLINE is the pen-name of the author. If your name is Wolfgang Quincy Greencastle, and you don't
+find that this name suits the motif of your comic, you may intead adopt a moniker, such as Modus
+Pwn4g3, and use that as the byline. Default value is blank. Was going to be "Anonymous" (that person who wrote
+I<Beowulf>, I<Go Ask Alice> and I<Primary Colors>), but I decided against it.
+
+#COPYRIGHT is the applicable copyright. (c)'s will be magically translated into copyright signs.
+At this time, that is the only magic performed here. Please keep in mind that whatever you do decide
+to put here only applies if it is, in fact, true. If you use SVG::Comic to make comics in which you
+are not the sole owner of the material involved (where material is the media output by SVG::Comic),
+you may not want to say that the comic is necessarily owned by you. The default copyright statement is
+
+ (c) $year, $byline. All rights reserved. All other material copyright its resepctive owner.
+
+If you would like a blank copyright statement, do the following:
+
+ #COPYRIGHT
+
+(That is, a blank line after #COPYRIGHT).
+
+A word (\w+) followed by a colon (:) sets off the speaker. This looks to a library
+of character models. If there is no model with that name, it selects a random one
+and sticks with it throughout the rest of the comic. Further, this initiates any
+characters in the comic. If you need to have characters be present, but not speak
+the entire time, declare them in the first panel (ex. Jane:). Until I make the
+script spec language a little more verbose, characters once named will be in every
+panel of the comic. Please don't specify more than two characters, as currently, any
+characters appearing after the first two are just lost somewhere along the way. Until
+someone adds support for more than two characters, dialogue will remain just that,
+dialogue.
+
+The remainder of the line after the first colon is the dialogue. It will be in a word
+bubble above the speakers head. Huzzah. If there is no dialogue (\s*), then the speaker
+in question will just be standing there.
+
+A set of three equal signs (=) sets off a panel. The total number of panels from the
+input text context is determined by the number of ==='s + 1. Think of these as the gutters.
+If you have two adjacent lines (disregarding empty lines) of ==='s, then the panel in
+question will have the speakers just standing there, as if they said nothing.
+
+Anything not recognized as a #WORD will be translated into an SVG comment.
+
+A note: if the first panel is to be without dialogue and empty, you must do this:
+
+ ===
+ Dick: This is panel 2.
+ ===
+ Jane: That's weird
+
+=head1 FUNCTIONS
+
+=head2 display
+
+ $sc->display(); # outputs the SVG code to STDOUT!
+
+=cut
+
+sub display {
+ my $self = shift;
+
+ use SVG;
+
+ my $svg = SVG->new(
+ width => $self->width,
+ height => $self->height,
+ );
+
+ my $comic = $svg->group(
+ x => 0,
+ y => 0,
+ fill => $self->bgcolor,
+ id => "comic",
+ );
+
+ my $background = $comic->rect(
+ x => 0,
+ y => 0,
+ width => $self->width,
+ height => $self->height,
+ fill => $self->bgcolor,
+ id => "background",
+ );
+
+ my $pans = $self->panels->[0]->get_count();
+ my $prev_widths = 0;
+ my $special_width = $self->panels->[0]->get_special_width();
+ my $specials = $self->panels->[0]->get_special_count();
+
+ foreach my $p (0..$pans-1) {
+ my $panel = $self->panels->[$p];
+ unless ($panel->width) {
+ $panel->width(($self->width - 2 * $self->gutter - ($pans - 1) * $self->gutter - $special_width) / ($pans - $specials)
+ );
+ }
+ $panel->x($self->gutter + $prev_widths + $p * $self->gutter);
+ $panel->y($self->gutter + $self->fontsize + 1);
+ $panel->height($self->height - 2 * $self->gutter - 2 * $self->fontsize - 1);
+ $panel->display($comic);
+
+ $comic->rect(
+ id => 'gutter' . $p . '_0',
+ x => $panel->x - $self->gutter,
+ y => $panel->y,
+ width => $self->gutter,
+ height => $panel->height,
+ fill => $self->bgcolor,
+ );
+
+ $comic->rect(
+ id => 'gutter' . $p . '_1',
+ x => $panel->x + $panel->width,
+ y => $panel->y,
+ width => $self->gutter,
+ height => $panel->height,
+ fill => $self->bgcolor,
+ );
+
+ $prev_widths += $panel->width;
+ }
+
+ $comic->rect(
+ id => 'top',
+ x => 0,
+ y => 0,
+ height => $self->gutter + $self->fontsize + 1,
+ width => $self->width,
+ fill => $self->bgcolor,
+ );
+
+ $comic->rect(
+ id => 'bot',
+ x => 0,
+ y => $self->height - $self->fontsize - $self->gutter,
+ height => $self->gutter + $self->fontsize + 1,
+ width => $self->width,
+ fill => $self->bgcolor,
+ );
+
+ my $title = $comic->text(
+ id => 'title',
+ x => $self->gutter,
+ y => $self->fontsize * 2/3 + $self->gutter,
+ fill => $self->textcolor,
+ 'font-size' => $self->fontsize,
+ )->cdata(
+ $self->title,
+ );
+
+ my $author = $comic->text(
+ id => 'author',
+ x => $self->width - $self->gutter,
+ y => $self->fontsize * 2/3 + $self->gutter,
+ fill => $self->textcolor,
+ 'text-anchor' => 'end',
+ 'font-size' => $self->fontsize,
+ )->cdata(
+ $self->author,
+ );
+
+ my $subtitle = $comic->text(
+ id => 'subtitle',
+ x => $self->gutter,
+ y => $self->height - $self->gutter,
+ fill => $self->textcolor,
+ 'font-size' => $self->fontsize,
+ )->cdata(
+ $self->subtitle,
+ );
+
+ my $copyright = $svg->text(
+ id => 'copyright',
+ x => $self->width - $self->gutter,
+ y => $self->height - $self->gutter,
+ fill => $self->textcolor,
+ 'text-anchor' => 'end',
+ 'font-size' => $self->fontsize,
+# )->cdata(
+ )->cdata_noxmlesc(
+ &_cr_magic($self->copyright),
+ );
+
+ my $comment = $svg->comment(
+ "\n\t" . $self->copyright . "\n",
+ "\n\tGenerated using the Perl " . ref($self) . " Module V" . $VERSION .
+ "\n\tby Jacob P. Silvia." .
+ "\n\tInfo: http://jacob.silvia.googlepages.com/\n",
+ );
+
+ print $svg->xmlify;
+}
+
+sub _cr_magic {
+ my $copyright = shift;
+
+# $copyright =~ s/\(c\)/�/ig;
+ $copyright =~ s/\(c\)/&#169;/ig;
+
+ return $copyright;
+}
+
+=head1 AUTHOR
+
+Jacob P. Silvia, C<< <jacob.silvia+cpan at gmail.com> >>
+
+=head1 BUGS
+
+Please report any bugs or feature requests to
+C<bug-svg-comic at rt.cpan.org>, or through the web interface at
+L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=SVG-Comic>.
+I will be notified, and then you'll automatically be notified of progress on
+your bug as I make changes.
+
+=head1 TODO
+
+Since I am only 1336, I am not able to implement all the neat features I'd want in order
+to turn your computer or web server into Frank Miller. Here are some thoughts about future
+implementations:
+
+=item * More than two characters?
+
+Currently, I only support two characters. I still need to
+consider a way to have more than two people there but at the same time, keep it from looking
+ugly.
+
+=item * Emots?
+
+Would it be possible to scan the line of dialogue for emot-words and thus change
+Dick's grin to a sad face? Or give someone a angry steam cloud or relieved sweat drop? More on
+this later.
+
+=item * Actions?
+
+I'm thinking of adding to the format language [actions]. Bascially, if you want
+someone to enter a scene, say Jane: [enters] when she does, and Jane: [leaves] when she does. This
+will limit the usage of []'s unless it's more like [[enters]] and [[leaves]]. Comments are
+appreciated. This could also be merged with the emot item: [[relieved]], [[angry]], [[etc.]]
+(not sure what that one'll do...).
+
+=item * Backgrounds?
+
+First, to make a background library similar to the character library. Second,
+to allow one to specify the background of the panel. Maybe if you said =Pub= as a gutter, it would
+mean that the next panel would take place in a pub. Or maybe === Pub. Additionally, specifying color
+for a blank background would be nice. Either do that by saying =Color(blue)= or === Color(blue).
+Unless I'm digging myself into a hole, gradients could be either Color(blue, black, nw) or Gradient(blue, black, nw) and applied to whichever gutter language ($@%&*!) I decide is better.
+
+=item * N x M?
+
+Currently, it supports 1 row with N columns. It would be nice to have it try to
+draw the comic nicely in an N x M sort of way, such that N x M looks nice on a computer screen.
+
+=head1 SUPPORT
+
+You can find documentation for this module with the perldoc command.
+
+ perldoc SVG::Comic
+
+You can also look for information at:
+
+=over 4
+
+=item * AnnoCPAN: Annotated CPAN documentation
+
+L<http://annocpan.org/dist/SVG-Comic>
+
+=item * CPAN Ratings
+
+L<http://cpanratings.perl.org/d/SVG-Comic>
+
+=item * RT: CPAN's request tracker
+
+L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=SVG-Comic>
+
+=item * Search CPAN
+
+L<http://search.cpan.org/dist/SVG-Comic>
+
+=back
+
+=head1 ACKNOWLEDGEMENTS
+
+Ronan Oger (Creator of SVG module). W3C (defined SVG standard). My wife (for putting up with me).
+
+=head1 COPYRIGHT & LICENSE
+
+Copyright 2007 Jacob P. Silvia, all rights reserved.
+
+This program is free software; you can redistribute it and/or modify it
+under the same terms as Perl itself.
+
+Characters drawn are copyright their respective creators and subject to their demands. Dialogue
+written copyright its respective writer and is subject to his/her demands. Keep that in mind when
+generating comics using this tool.
+
+The outputted SVG file may contain the following information as an SVG comment: the fact that the
+comic in question was generated using SVG::Comic version blah, written by Jacob P. Silvia (et al.),
+and that the featured characters are property of their respective owners and subject to the COPYRIGHT
+& LICENSE information found within their respective files.
+
+=cut
+
+sub AUTOLOAD {
+ my $self = shift;
+ my $type = ref($self)
+ or croak "$self is not an object.";
+
+ my $name = $AUTOLOAD;
+ $name =~ s/.*://;
+
+ unless (exists $self->{_permitted}->{$name}) {
+ croak "Can't acces `$name' field in class $type";
+ }
+
+ if (@_) {
+ return $self->{$name} = shift;
+ } else {
+ return $self->{$name};
+ }
+}
+
+sub DESTROY {
+ my $self = shift;
+
+ foreach (keys %fields) {
+ $self->$_(undef);
+ }
+}
+
+1; # End of SVG::Comic

Added: trunk/lib/SVG/Comic/Character.pm
==============================================================================
--- (empty file)
+++ trunk/lib/SVG/Comic/Character.pm Fri Mar 14 13:59:29 2008
@@ -0,0 +1,125 @@
+package SVG::Comic::Character;
+
+use strict;
+use warnings;
+use Carp;
+use vars qw($VERSION $AUTOLOAD);
+
+$VERSION = '0.1.1';
+
+my %fields = (
+ character => 'Generic',
+ chardata => undef,
+ x => undef,
+ y => undef,
+ z => 0,
+ pan_width => undef,
+ pan_height => undef,
+ char_width => undef,
+);
+
+sub new ($;@) {
+ my ($this, %attrs) = @_;
+ my $class = ref $this || $this;
+ my $self;
+
+ foreach my $attr (keys %fields) {
+ $attrs{$attr} ||= $fields{$attr};
+ }
+
+ $self = {
+ _permitted => \%fields,
+ %attrs,
+ };
+
+ bless $self, $class;
+
+ $self->initialize();
+
+ return $self;
+}
+
+sub initialize {
+ my $self = shift;
+
+}
+
+sub display {
+ my $self = shift;
+ my $svg = shift;
+
+ my $path = ref($self);
+ $path =~ s/::/\//g;
+
+ my $character_file;
+ my $generic_file;
+
+ foreach (sort @INC) {
+ my $full_path = $_ . "/" . $path . "/";
+ my $generic_path = $full_path . "Generic.scc";
+ my $character_path = $full_path . $self->character . ".scc";
+ if (-e $generic_path) {
+ $generic_file = $generic_path;
+ }
+ if (-e $character_path) {
+ $character_file = $character_path;
+ last;
+ }
+ }
+
+ $character_file ||= $generic_file;
+
+ print STDERR $character_file, "\n";
+
+ open CHARACTER, "<$character_file"
+ or die "Cannot open $character_file: $!";
+
+ my $chardata = join("", <CHARACTER>);
+
+ close CHARACTER;
+
+ $self->chardata($chardata) unless $self->chardata;
+
+ eval $self->chardata or die "Cannot eval " . $self->chardata . ": $!";
+
+}
+
+sub _set_x {
+ my $self = shift;
+
+ my $x = $self->x + (-1) ** ($self->z/2) * 10 + (1 + (-1) ** ($self->z/2+1)) * ($self->pan_width - $self->char_width) / 2;
+
+ if ($self->z/2 % 2) { # if odd...
+ $x = $self->pan_width + $self->x - 10;
+ } else {
+ $x = $self->x + 10
+ }
+
+ return $x;
+}
+
+sub AUTOLOAD {
+ my $self = shift;
+
+ my $type = ref($self)
+ or croak "$self is not an object.";
+
+ my $name = $AUTOLOAD;
+ $name =~ s/.*://;
+
+ unless (exists $self->{_permitted}->{$name}) {
+ croak "Can't acces `$name' field in class $type";
+ }
+
+ if (@_) {
+ return $self->{$name} = shift;
+ } else {
+ return $self->{$name};
+ }
+}
+
+sub DESTROY {
+ my $self = shift;
+}
+
+1;
\ No newline at end of file

Added: trunk/lib/SVG/Comic/Character/Dick.scc
==============================================================================
--- (empty file)
+++ trunk/lib/SVG/Comic/Character/Dick.scc Fri Mar 14 13:59:29 2008
@@ -0,0 +1,47 @@
+# Dick
+
+print STDERR "Hello, Dick!\n";
+
+$self->char_width(50);
+
+my $x = $self->_set_x;
+
+my $xform = $svg->group(
+ );
+
+#my $y = $self->y + $self->pan_height - 102;
+
+$xform->path(
+ d => join(" ",
+ 'm', $x, $self->y + $self->pan_height - 102,
+ 'h', (-1) ** ($self->z/2) * 50,
+ 'v', 100,
+ 'h', (-1) ** ($self->z/2) * -50,
+ 'z',
+ ),
+ fill => 'red',
+ id => 'dick_body_' . $x,
+ );
+
+$xform->circle(
+ cx => $x + (-1) ** ($self->z/2) * 30,
+ cy => $self->y + $self->pan_height - 90,
+ fill => 'black',
+ r => 5,
+ id => 'dick_left_eye_' . $x,
+
+ );
+
+$xform->circle(
+ cx => $x + (-1) ** ($self->z/2) * 43,
+ cy => $self->y + $self->pan_height - 90,
+ fill => 'black',
+ r => 5,
+ id => 'dick_right_eye_' . $x,
+ );
+
+$xform->comment(
+ "\n\tDick character is available for fair use.\n"
+ );
+
+1;
\ No newline at end of file

Added: trunk/lib/SVG/Comic/Character/Generic.scc
==============================================================================
--- (empty file)
+++ trunk/lib/SVG/Comic/Character/Generic.scc Fri Mar 14 13:59:29 2008
@@ -0,0 +1,44 @@
+# Generic
+
+print STDERR "Hello, Generic!\n";
+
+$self->char_width(50);
+
+my $x = $self->_set_x;
+my $xform = $svg->group(
+ );
+#my $y = $self->y + $self->pan_height - 102;
+
+$xform->path(
+ d => join(" ",
+ 'm', $x, $self->y + $self->pan_height - 102,
+ 'h', (-1) ** ($self->z/2) * 50,
+ 'v', 100,
+ 'h', (-1) ** ($self->z/2) * -50,
+ 'z',
+ ),
+ fill => 'black',
+ id => 'generic_body_' . $x,
+);
+
+$xform->circle(
+ cx => $x + (-1) ** ($self->z/2) * 30,
+ cy => $self->y + $self->pan_height - 90,
+ fill => 'white',
+ r => 5,
+ id => 'generic_left_eye_' . $x,
+);
+
+$xform->circle(
+ cx => $x + (-1) ** ($self->z/2) * 43,
+ cy => $self->y + $self->pan_height - 90,
+ fill => 'white',
+ r => 5,
+ id => 'generic_right_eye_' . $x,
+);
+
+$xform->comment(
+ "\n\tGeneric character is available for fair use.\n"
+);
+
+1;
\ No newline at end of file

Added: trunk/lib/SVG/Comic/Character/Jane.scc
==============================================================================
--- (empty file)
+++ trunk/lib/SVG/Comic/Character/Jane.scc Fri Mar 14 13:59:29 2008
@@ -0,0 +1,42 @@
+# Jane
+
+print STDERR "Hello, Jane!\n";
+
+$self->char_width(50);
+
+my $x = $self->_set_x;
+
+$svg->path(
+ d => join(" ",
+ 'm', $x, $self->y + $self->pan_height - 102,
+ 'h', (-1) ** ($self->z/2) * 50,
+ 'v', 100,
+ 'h', (-1) ** ($self->z/2) * -50,
+ 'z',
+ ),
+ fill => 'blue',
+ id => 'jane_body_' . $x,
+ );
+
+$svg->circle(
+ cx => $x + (-1) ** ($self->z/2) * 30,
+ cy => $self->y + $self->pan_height - 90,
+ fill => 'orange',
+ r => 5,
+ id => 'jane_left_eye_' . $x,
+
+ );
+
+$svg->circle(
+ cx => $x + (-1) ** ($self->z/2) * 43,
+ cy => $self->y + $self->pan_height - 90,
+ fill => 'orange',
+ r => 5,
+ id => 'dick_right_eye_' . $x,
+ );
+
+$svg->comment(
+ "\n\tJane character is available for fair use.\n"
+ );
+
+1;
\ No newline at end of file

Added: trunk/lib/SVG/Comic/Panel.pm
==============================================================================
--- (empty file)
+++ trunk/lib/SVG/Comic/Panel.pm Fri Mar 14 13:59:29 2008
@@ -0,0 +1,285 @@
+package SVG::Comic::Panel;
+
+use strict;
+use warnings;
+use Carp;
+use vars qw($VERSION $AUTOLOAD);
+use SVG::Comic::Character;
+
+$VERSION = '0.1.1';
+
+my %fields = (
+ height => undef,
+ width => undef,
+ bgcolor => 'white',
+ textcolor => 'black',
+ fontsize => 10,
+ dialogue => [],
+ id => 0,
+ x => 0,
+ y => 0,
+);
+
+my $_COUNT;
+my $_SPECIAL_WIDTH;
+my $_SPECIAL_COUNT;
+my %_CHARACTERS;
+
+sub new ($;@) {
+ my ($this, %attrs) = @_;
+ my $class = ref $this || $this;
+ my $self;
+
+ foreach my $attr (keys %fields) {
+ $attrs{$attr} ||= $fields{$attr};
+ }
+
+ $self = {
+ _permitted => \%fields,
+ %attrs,
+ };
+
+ bless $self, $class;
+
+ $self->initialize();
+
+ return $self;
+}
+
+sub initialize {
+ my $self = shift;
+
+ $SVG::Comic::Panel::_COUNT += 1;
+ $SVG::Comic::Panel::_SPECIAL_WIDTH += $self->width || 0;
+ $SVG::Comic::Panel::_SPECIAL_COUNT += 1 if $self->width;
+ $self->id($SVG::Comic::Panel::_COUNT);
+}
+
+sub get_count {
+ return $SVG::Comic::Panel::_COUNT || 0;
+}
+
+sub get_special_width {
+ return $SVG::Comic::Panel::_SPECIAL_WIDTH || 0;
+}
+
+sub get_special_count {
+ return $SVG::Comic::Panel::_SPECIAL_COUNT || 0;
+}
+
+sub add_dialogue {
+ my $self = shift;
+ my $line = shift;
+
+ push (@{$self->dialogue}, $line);
+}
+
+sub display {
+ my $self = shift;
+ my $svg = shift;
+
+ my $pane_g = $svg->group(
+ id => 'panel' . $self->id,
+ x => $self->x,
+ y => $self->y,
+ width => $self->width,
+ height => $self->height,
+ maskUnits => 'userSpaceOnUse',
+ );
+
+ my $panel = $pane_g->rect(
+ x => $self->x,
+ y => $self->y,
+ height => $self->height,
+ width => $self->width,
+ fill => $self->bgcolor,
+ );
+
+ my $lines = @{$self->dialogue};
+
+ my $y = 0;
+
+ my $char_iter = 0;
+
+ foreach (my $i = 0; $i < $lines; $i += 2) {
+ my $char_name = $self->dialogue->[$i];
+ print STDERR $char_name, " $i\n";
+ unless ($_CHARACTERS{$char_name}) {
+ $_CHARACTERS{$char_name} = $char_iter ;
+ $char_iter += 2;
+ }
+ my $character = SVG::Comic::Character->new(
+ character => $char_name,
+ x => $self->x,
+ y => $self->y,
+ z => $_CHARACTERS{$char_name},
+ pan_width => $self->width,
+ pan_height => $self->height,
+ );
+ $character->display($pane_g);
+ my $dialogue = $self->dialogue->[$i+1];
+ my $extra = $self->_display_line($pane_g, $dialogue, $y, $_CHARACTERS{$char_name});
+ $y += $extra + 1;
+ }
+
+ $svg->comment(
+ "\n\tGenerated using the Perl " . ref($self) . " Module V" . $VERSION .
+ "\n\tby Jacob P. Silvia." .
+ "\n\tInfo: http://jacob.silvia.googlepages.com/\n",
+ );
+}
+
+sub _display_line {
+ my $self = shift;
+ my $svg = shift;
+ my $dialogue = shift;
+ my $y = shift;
+ my $z = shift;
+
+ my @dialogue = split(/\s+/, $dialogue);
+
+ my $new_dialogue;
+ my $total_len = 0;
+
+ my $extra = 1;
+
+ while (my $word = shift @dialogue) {
+ my $len = $self->_text_length($word) + 1;
+ if ($total_len + $len > $self->width) {
+ $extra += $self->_display_line($svg, join(" ", $word, @dialogue), $y+1, $z);
+ last;
+ } else {
+ $total_len += $len;
+ $new_dialogue .= $word . " ";
+ }
+ }
+
+ my $ta = '';
+ my $xp = 0;
+
+ if ($z/2 % 2) {
+ $ta = 'end';
+ $xp = $self->width - 2;
+ }
+
+ my $line = $svg->text(
+ x => $self->x + 1 + $xp,
+ y => $self->y + $self->fontsize + $y * $self->fontsize + 1,
+ 'font-size' => $self->fontsize,
+ fill => $self->textcolor,
+ 'text-anchor' => $ta,
+ )->cdata(
+ $new_dialogue,
+ );
+
+ return $extra;
+}
+
+# _text_length borrowed from Graph::Easy::SVG
+sub _text_length {
+ use utf8;
+
+ my $self = shift;
+ my $text = shift;
+
+ my $em = $self->fontsize;
+ my $count = length($text);
+ my $len = 0;
+ my $match;
+
+ $match = $text =~ tr/'`//;
+ $len += $match * 0.25 * $em;
+ $count -= $match;
+
+ $match = $text =~ tr/Iijl~.,;:\|//;
+ $len += $match * 0.33 * $em;
+ $count -= $match;
+
+ $match = $text =~ tr/"Jft\(\)\[\]\{\}//;
+ $len += $match * 0.4 * $em;
+ $count -= $match;
+
+ $match = $text =~ tr/?//;
+ $len += $match * 0.5 * $em;
+ $count -= $match;
+
+ $match = $text =~ tr/crs_//;
+ $len += $match * 0.55 * $em;
+ $count -= $match;
+
+ $match = $text =~ tr/ELPaäevyz//;
+ $len += $match * 0.6 * $em;
+ $count -= $match;
+
+ $match = $text =~ tr/BZFbdghknopqux~üö//;
+ $len += $match * 0.65 * $em;
+ $count -= $match;
+
+ $match = $text =~ tr/KCVXY%//;
+ $len += $match * 0.7 * $em;
+ $count -= $match;
+
+ $match = $text =~ tr/§€//;
+ $len += $match * 0.75 * $em;
+ $count -= $match;
+
+ $match = $text =~ tr/ÜÖÄßHGDSNQU$&//;
+ $len += $match * 0.8 * $em;
+ $count -= $match;
+
+ $match = $text =~ tr/AwO=+<>//;
+ $len += $match * 0.85 * $em;
+ $count -= $match;
+
+ $match = $text =~ tr/W//;
+ $len += $match * 0.9 * $em;
+ $count -= $match;
+
+ $match = $text =~ tr/M//;
+ $len += $match * 0.95 * $em;
+ $count -= $match;
+
+ $match = $text =~ tr/m//;
+ $len += $match * 1.03 * $em;
+ $count -= $match;
+
+ $match = $text =~ tr/@//;
+ $len += $match * 1.15 * $em;
+ $count -= $match;
+
+ $match = $text =~ tr/æ//;
+ $len += $match * 1.25 * $em;
+ $count -= $match;
+
+ $len += $count * $em;
+
+ return $len;
+}
+
+sub AUTOLOAD {
+ my $self = shift;
+
+ my $type = ref($self)
+ or croak "$self is not an object.";
+
+ my $name = $AUTOLOAD;
+ $name =~ s/.*://;
+
+ unless (exists $self->{_permitted}->{$name}) {
+ croak "Can't acces `$name' field in class $type";
+ }
+
+ if (@_) {
+ return $self->{$name} = shift;
+ } else {
+ return $self->{$name};
+ }
+}
+
+sub DESTROY {
+ my $self = shift;
+
+ $SVG::Comic::Panel::_COUNT -= 1;
+}
+
+1;
\ No newline at end of file

Added: trunk/t/SVG-Comic.t
==============================================================================
--- (empty file)
+++ trunk/t/SVG-Comic.t Fri Mar 14 13:59:29 2008
@@ -0,0 +1,15 @@
+# Before `make install' is performed this script should be runnable with
+# `make test'. After `make install' it should work as `perl SVG-Comic.t'
+
+#########################
+
+# change 'tests => 1' to 'tests => last_test_to_print';
+
+use Test::More tests => 1;
+BEGIN { use_ok('SVG::Comic') };
+
+#########################
+
+# Insert your test code below, the Test::More module is use()ed here so read
+# its man page ( perldoc Test::More ) for help writing this test script.
+

Reply all
Reply to author
Forward
0 new messages