line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Text::Format::Screenplay; |
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
24347
|
use 5.008009; |
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
47
|
|
4
|
1
|
|
|
1
|
|
7
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
41
|
|
5
|
1
|
|
|
1
|
|
5
|
use warnings; |
|
1
|
|
|
|
|
8
|
|
|
1
|
|
|
|
|
53
|
|
6
|
1
|
|
|
1
|
|
1191
|
use File::Slurp qw(read_file); |
|
1
|
|
|
|
|
17851
|
|
|
1
|
|
|
|
|
83
|
|
7
|
1
|
|
|
1
|
|
1342
|
use PDF::Create; |
|
1
|
|
|
|
|
57694
|
|
|
1
|
|
|
|
|
51
|
|
8
|
1
|
|
|
1
|
|
2467
|
use Text::Wrap; |
|
1
|
|
|
|
|
3867
|
|
|
1
|
|
|
|
|
3270
|
|
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
our $VERSION = '0.01'; |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
my $DOUBLE_DIALOG_LINES = 0; |
13
|
|
|
|
|
|
|
my $SHOW_SCENE_NUMBERS = 0; |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
my $CHAR_WIDTH = 7; |
16
|
|
|
|
|
|
|
my $CHAR_HEIGHT = 12; |
17
|
|
|
|
|
|
|
my $PAGE_WIDTH = 612; |
18
|
|
|
|
|
|
|
my $PAGE_HEIGHT = 792; |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
# parse infile |
21
|
|
|
|
|
|
|
my $TITLE = ''; |
22
|
|
|
|
|
|
|
my @AUTHOR = (); |
23
|
|
|
|
|
|
|
my @CONTACT = (); |
24
|
|
|
|
|
|
|
my $DRAFT = ''; |
25
|
|
|
|
|
|
|
my $DATE = ''; |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
sub new |
28
|
|
|
|
|
|
|
{ |
29
|
1
|
|
|
1
|
1
|
12
|
my ($class, @args) = @_; |
30
|
1
|
|
|
|
|
3
|
my $self = bless {}, $class; |
31
|
1
|
|
|
|
|
5
|
return $self->_init(); |
32
|
|
|
|
|
|
|
} |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
sub _init |
35
|
|
|
|
|
|
|
{ |
36
|
1
|
|
|
1
|
|
3
|
my ($self, %opts) = @_; |
37
|
1
|
|
|
|
|
2
|
return $self; |
38
|
|
|
|
|
|
|
} |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
sub pdf |
41
|
|
|
|
|
|
|
{ |
42
|
1
|
|
|
1
|
1
|
18
|
my ($self, $filename, $outfile) = @_; |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
# structure of $scenes: each element: [ 'type', 'content' ] |
45
|
1
|
|
|
|
|
9
|
my $scenes = $self->_parse_infile( read_file($filename) ); |
46
|
|
|
|
|
|
|
|
47
|
1
|
|
|
|
|
11
|
$self->_create_outfile( $scenes, $outfile ); |
48
|
|
|
|
|
|
|
} |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
sub _parse_infile |
51
|
|
|
|
|
|
|
{ |
52
|
1
|
|
|
1
|
|
250
|
my ($self, @lines) = @_; |
53
|
1
|
|
|
|
|
2
|
my @sp; |
54
|
|
|
|
|
|
|
|
55
|
0
|
|
|
|
|
0
|
my $i; my $j; |
56
|
1
|
|
|
|
|
6
|
for ($i=0; $i
|
57
|
|
|
|
|
|
|
{ |
58
|
17
|
50
|
|
|
|
56
|
next if $lines[$i] =~ /^[\s\t\n\r]*$/; # ignore blank lines |
59
|
17
|
50
|
|
|
|
35
|
next if $lines[$i] =~ /^[\s\t\n\r]*\#/; # ignore comment lines |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
# parse next paragraph |
62
|
17
|
|
|
|
|
17
|
my $para = ''; |
63
|
17
|
|
|
|
|
39
|
for ($j=$i; $j
|
64
|
52
|
|
|
|
|
85
|
chomp($lines[$j]); |
65
|
52
|
50
|
|
|
|
104
|
next if $lines[$j] =~ /^[\s\t\n\r]*\#/; # ignore comment lines |
66
|
52
|
100
|
|
|
|
139
|
last if $lines[$j] =~ /^[\s\t\n\r]*$/; # ignore blank lines |
67
|
36
|
|
|
|
|
108
|
$para .= $lines[$j]; |
68
|
|
|
|
|
|
|
} |
69
|
17
|
|
|
|
|
23
|
$i = $j; |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
# split into pre-colon and post-colon parts |
72
|
17
|
|
|
|
|
72
|
my ($pre, $post) = $para =~ /^([^\:\~\>]*[\:\~\>]?)(.*)$/; |
73
|
17
|
100
|
|
|
|
48
|
$post = '' unless $post; |
74
|
|
|
|
|
|
|
|
75
|
17
|
100
|
|
|
|
102
|
if ($pre eq 'title:') { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
76
|
1
|
|
|
|
|
9
|
($TITLE) = uc($post) =~ /^[\s\t]*(.*)[\s\t\r\n]*$/; |
77
|
|
|
|
|
|
|
} elsif ($pre eq 'author:') { |
78
|
1
|
|
|
|
|
6
|
@AUTHOR = map { s/^[\s\t]*(.*)[\s\t\r\n]*$/$1/; $_ } split /;/, $post; |
|
1
|
|
|
|
|
7
|
|
|
1
|
|
|
|
|
7
|
|
79
|
|
|
|
|
|
|
} elsif ($pre eq 'contact:') { |
80
|
1
|
|
|
|
|
11
|
@CONTACT = map { s/^[\s\t]*(.*)[\s\t\r\n]*$/$1/; $_ } split /;/, $post; |
|
4
|
|
|
|
|
15
|
|
|
4
|
|
|
|
|
12
|
|
81
|
|
|
|
|
|
|
} elsif ($pre eq 'draft:') { |
82
|
1
|
|
|
|
|
4
|
$DRAFT = $post; |
83
|
|
|
|
|
|
|
} elsif ($pre eq 'date:') { |
84
|
1
|
|
|
|
|
12
|
$DATE = $post; |
85
|
|
|
|
|
|
|
} elsif ($pre eq ':') { |
86
|
3
|
|
|
|
|
13
|
push @sp, ['s', $post]; |
87
|
|
|
|
|
|
|
} elsif ($pre eq '>') { |
88
|
1
|
|
|
|
|
5
|
push @sp, ['t', $post]; |
89
|
|
|
|
|
|
|
} elsif ($pre eq '~') { |
90
|
1
|
|
|
|
|
6
|
push @sp, ['c', $post]; |
91
|
|
|
|
|
|
|
} elsif ($pre =~ /^.{1,20}\:$/) { |
92
|
2
|
|
|
|
|
8
|
$pre =~ s/\:$//; |
93
|
2
|
|
|
|
|
9
|
push @sp, [$pre, $post]; |
94
|
|
|
|
|
|
|
} else { |
95
|
5
|
|
|
|
|
22
|
push @sp, ['d', $pre]; |
96
|
|
|
|
|
|
|
} |
97
|
|
|
|
|
|
|
} |
98
|
|
|
|
|
|
|
|
99
|
1
|
|
|
|
|
9
|
return \@sp; |
100
|
|
|
|
|
|
|
} |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
sub _create_outfile |
103
|
|
|
|
|
|
|
{ |
104
|
1
|
|
|
1
|
|
31
|
my ($self, $sp, $outfile) = @_; |
105
|
|
|
|
|
|
|
|
106
|
1
|
|
|
|
|
17
|
my $pdf = new PDF::Create |
107
|
|
|
|
|
|
|
('filename' => $outfile, |
108
|
|
|
|
|
|
|
'Version' => 1.2, |
109
|
|
|
|
|
|
|
'PageMode' => 'UseOutlines', |
110
|
|
|
|
|
|
|
'Author' => join(', ', @AUTHOR), |
111
|
|
|
|
|
|
|
'Title' => $TITLE, |
112
|
|
|
|
|
|
|
); |
113
|
1
|
|
|
|
|
382
|
my $root = $pdf->new_page('Media-Box' => [0, $PAGE_WIDTH, 0, $PAGE_HEIGHT]); |
114
|
1
|
|
|
|
|
73
|
my $font = $pdf->font |
115
|
|
|
|
|
|
|
('Subtype' => 'Type1', |
116
|
|
|
|
|
|
|
'Encoding' => 'WinAnsiEncoding', |
117
|
|
|
|
|
|
|
'BaseFont' => 'CourierNew'); |
118
|
|
|
|
|
|
|
|
119
|
1
|
|
|
|
|
42
|
my $mid = sprintf "%.0f", ($PAGE_WIDTH / $CHAR_WIDTH / 2); |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
# |
122
|
|
|
|
|
|
|
# title page |
123
|
|
|
|
|
|
|
# |
124
|
1
|
|
|
|
|
4
|
my $page = $root->new_page; # inherit from root |
125
|
|
|
|
|
|
|
|
126
|
1
|
|
|
|
|
48
|
my $line = 25; |
127
|
1
|
|
|
|
|
5
|
$line = _put($page, $font, $TITLE, $line, _mid($mid,$TITLE)); |
128
|
1
|
|
|
|
|
2
|
$line += 4; |
129
|
1
|
|
|
|
|
3
|
$line = _put($page, $font, "written by", $line, _mid($mid,"written by")); |
130
|
1
|
|
|
|
|
1
|
$line++; |
131
|
1
|
|
|
|
|
2
|
foreach (@AUTHOR) { $line = _put($page, $font, $_, $line, _mid($mid,$_)) } |
|
1
|
|
|
|
|
10
|
|
132
|
1
|
|
|
|
|
5
|
_put($page, $font, join("\n",@CONTACT), 61-scalar(@CONTACT), 15); |
133
|
1
|
|
|
|
|
4
|
_put($page, $font, $DRAFT, 56, 62); |
134
|
1
|
|
|
|
|
3
|
_put($page, $font, $DATE, 60, 62); |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
# |
137
|
|
|
|
|
|
|
# script pages |
138
|
|
|
|
|
|
|
# |
139
|
1
|
|
|
|
|
2
|
my $pnum = 1; # page counter |
140
|
1
|
|
|
|
|
1
|
my $snum = 1; # scene counter |
141
|
|
|
|
|
|
|
|
142
|
1
|
|
|
|
|
4
|
$page = $root->new_page; |
143
|
1
|
|
|
|
|
55
|
_put($page, $font, sprintf("%10s", "$pnum."), 4, 62); |
144
|
1
|
|
|
|
|
2
|
$line = 6; |
145
|
1
|
|
|
|
|
3
|
for (my $e=0; $e<@{$sp}; $e++) |
|
13
|
|
|
|
|
28
|
|
146
|
|
|
|
|
|
|
{ |
147
|
12
|
|
|
|
|
19
|
my $type = $sp->[$e]->[0]; |
148
|
12
|
|
|
|
|
22
|
my $text = $sp->[$e]->[1]; |
149
|
|
|
|
|
|
|
|
150
|
12
|
100
|
|
|
|
44
|
if ($type !~ /^[stcd]$/) { $text =~ s/\(/\n\(/g; $text =~ s/\)/)\n/g } |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
5
|
|
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
# check if current page is full |
153
|
12
|
|
|
|
|
12
|
my $till = 0; # till what line the next element needs space |
154
|
12
|
100
|
100
|
|
|
48
|
if ($type eq 's') { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
155
|
|
|
|
|
|
|
# own + 1 line space + space for next part |
156
|
3
|
|
|
|
|
6
|
$till = $line + _sizeof($text,1000); |
157
|
3
|
|
|
|
|
4
|
$till += 10; |
158
|
|
|
|
|
|
|
} elsif ($type eq 't' || $type eq 'c') { |
159
|
|
|
|
|
|
|
# one line (+ 2 empty lines of not last line) |
160
|
2
|
|
|
|
|
3
|
$till = $line + 1; |
161
|
2
|
50
|
|
|
|
4
|
$till += 2 unless $till == 60; |
162
|
|
|
|
|
|
|
} elsif ($type eq 'd') { |
163
|
|
|
|
|
|
|
# own size (+ 1 empty line if not on last line) |
164
|
5
|
|
|
|
|
6
|
$till = $line + _sizeof($text,54); |
165
|
5
|
50
|
|
|
|
12
|
$till++ unless $till == 60; |
166
|
|
|
|
|
|
|
} else { |
167
|
|
|
|
|
|
|
# name line + dialog lines |
168
|
2
|
|
|
|
|
6
|
$till = $line + 1 + _sizeof($text,32); |
169
|
2
|
50
|
|
|
|
6
|
$till += _sizeof($text,32) if $DOUBLE_DIALOG_LINES; |
170
|
|
|
|
|
|
|
} |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
# create new page |
173
|
12
|
50
|
|
|
|
21
|
if ($till > 60) { |
174
|
0
|
|
|
|
|
0
|
$pnum++; |
175
|
0
|
|
|
|
|
0
|
$page = $root->new_page; |
176
|
0
|
|
|
|
|
0
|
_put($page, $font, sprintf("%10s", "$pnum."), 4, 62); |
177
|
0
|
|
|
|
|
0
|
$line = 6; |
178
|
0
|
|
|
|
|
0
|
next; |
179
|
|
|
|
|
|
|
} |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
# add current element + space to page |
182
|
12
|
100
|
|
|
|
37
|
if ($type eq 's') { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
183
|
3
|
50
|
|
|
|
5
|
if ($SHOW_SCENE_NUMBERS) { |
184
|
0
|
|
|
|
|
0
|
_put($page, $font, sprintf("%5s",$snum), $line, 13); |
185
|
0
|
|
|
|
|
0
|
_put($page, $font, $snum, $line, 74); |
186
|
0
|
|
|
|
|
0
|
$snum++; |
187
|
|
|
|
|
|
|
} |
188
|
3
|
|
|
|
|
5
|
$line = _put($page, $font, $text, $line, 19); |
189
|
3
|
|
|
|
|
4
|
$line++; |
190
|
|
|
|
|
|
|
} elsif ($type eq 't') { |
191
|
1
|
|
|
|
|
3
|
$line = _put($page, $font, $text, $line, 62); |
192
|
1
|
50
|
|
|
|
6
|
$line += 2 unless $line == 60; |
193
|
|
|
|
|
|
|
} elsif ($type eq 'c') { |
194
|
1
|
|
|
|
|
5
|
$line = _put($page, $font, $text, $line, _mid($mid,$text)); |
195
|
1
|
50
|
|
|
|
4
|
$line += 2 unless $line == 60; |
196
|
|
|
|
|
|
|
} elsif ($type eq 'd') { |
197
|
5
|
|
|
|
|
7
|
$line = _put($page, $font, _wrapit($text,54), $line, 19); |
198
|
5
|
100
|
100
|
|
|
7
|
if (($e+1 < scalar(@{$sp})) && |
|
5
|
|
33
|
|
|
49
|
|
199
|
|
|
|
|
|
|
($sp->[$e+1]->[0] eq 't' || $sp->[$e+1]->[0] eq 'c' || |
200
|
|
|
|
|
|
|
$sp->[$e+1]->[0] eq 's')) { |
201
|
3
|
50
|
|
|
|
10
|
$line += 2 unless $line == 60; |
202
|
|
|
|
|
|
|
} else { |
203
|
2
|
50
|
|
|
|
7
|
$line++ unless $line == 60; |
204
|
|
|
|
|
|
|
} |
205
|
|
|
|
|
|
|
} else { |
206
|
2
|
|
|
|
|
4
|
$line = _put($page, $font, $type, $line, 43); |
207
|
2
|
|
|
|
|
4
|
$text = _wrapit($text,32); $text =~ s/\(/ \(/g; |
|
2
|
|
|
|
|
5
|
|
208
|
2
|
50
|
|
|
|
6
|
if ($DOUBLE_DIALOG_LINES) { |
209
|
0
|
|
|
|
|
0
|
$text =~ s/\n/\n\n/g; $text = "\n$text" } |
|
0
|
|
|
|
|
0
|
|
210
|
2
|
|
|
|
|
3
|
$line = _put($page, $font, $text, $line, 29); |
211
|
2
|
50
|
33
|
|
|
3
|
if (($e+1 < scalar(@{$sp})) && ($sp->[$e+1]->[0] !~ /^stcd$/)) { |
|
2
|
|
|
|
|
15
|
|
212
|
2
|
50
|
|
|
|
6
|
$line++ unless $line == 60; |
213
|
|
|
|
|
|
|
} else { |
214
|
0
|
0
|
|
|
|
0
|
$line += 2 unless $line == 60; |
215
|
|
|
|
|
|
|
} |
216
|
|
|
|
|
|
|
} |
217
|
|
|
|
|
|
|
} |
218
|
|
|
|
|
|
|
|
219
|
1
|
|
|
|
|
5
|
$pdf->close; |
220
|
|
|
|
|
|
|
} |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
sub _sizeof |
223
|
|
|
|
|
|
|
{ |
224
|
10
|
|
|
10
|
|
12
|
my ($text, $width) = @_; |
225
|
10
|
|
|
|
|
15
|
$text = _wrapit($text, $width); |
226
|
10
|
|
|
|
|
28
|
my @lines = split /\n/, $text; |
227
|
10
|
|
|
|
|
20
|
return scalar(@lines); |
228
|
|
|
|
|
|
|
} |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
sub _wrapit |
231
|
|
|
|
|
|
|
{ |
232
|
17
|
|
|
17
|
|
19
|
my ($text, $width) = @_; |
233
|
17
|
|
|
|
|
15
|
$Text::Wrap::columns = $width; |
234
|
17
|
|
|
|
|
34
|
$text = Text::Wrap::wrap("", "", $text); |
235
|
17
|
|
|
|
|
4479
|
$text =~ s/\s*\n\s*/\n/g; |
236
|
17
|
|
|
|
|
54
|
$text =~ s/^\s*//g; |
237
|
17
|
|
|
|
|
33
|
return $text; |
238
|
|
|
|
|
|
|
} |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
sub _mid |
241
|
|
|
|
|
|
|
{ |
242
|
4
|
|
|
4
|
|
7
|
my ($mid, $str) = @_; |
243
|
4
|
|
|
|
|
38
|
return sprintf("%.0f", $mid - (length($str) / 2)); |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
# places a text block onto a page, starting at a certain position |
247
|
|
|
|
|
|
|
sub _put |
248
|
|
|
|
|
|
|
{ |
249
|
21
|
|
|
21
|
|
38
|
my ($page, $font, $text, $line, $column) = @_; |
250
|
21
|
|
|
|
|
56
|
foreach (split /\n/, $text) { |
251
|
41
|
|
|
|
|
124
|
$page->stringl($font, 10, |
252
|
|
|
|
|
|
|
($column * $CHAR_WIDTH), |
253
|
|
|
|
|
|
|
($PAGE_HEIGHT - ($line * $CHAR_HEIGHT)), $_); |
254
|
41
|
|
|
|
|
2620
|
$line++; |
255
|
|
|
|
|
|
|
} |
256
|
21
|
|
|
|
|
40
|
return $line; |
257
|
|
|
|
|
|
|
} |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
1; |
260
|
|
|
|
|
|
|
__END__ |