line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# $Id: AxPoint.pm,v 1.49 2005/10/19 16:43:48 matt Exp $ |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
package XML::Handler::AxPoint; |
4
|
2
|
|
|
2
|
|
37595
|
use strict; |
|
2
|
|
|
|
|
8
|
|
|
2
|
|
|
|
|
119
|
|
5
|
|
|
|
|
|
|
|
6
|
2
|
|
|
2
|
|
2433
|
use XML::SAX::Writer; |
|
2
|
|
|
|
|
119660
|
|
|
2
|
|
|
|
|
66
|
|
7
|
2
|
|
|
2
|
|
1879
|
use Text::Iconv; |
|
2
|
|
|
|
|
7306
|
|
|
2
|
|
|
|
|
125
|
|
8
|
2
|
|
|
2
|
|
15
|
use File::Spec; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
46
|
|
9
|
2
|
|
|
2
|
|
11
|
use File::Basename; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
178
|
|
10
|
2
|
|
|
2
|
|
2230
|
use Data::Dumper; |
|
2
|
|
|
|
|
15038
|
|
|
2
|
|
|
|
|
150
|
|
11
|
2
|
|
|
2
|
|
11710
|
use PDFLib 0.13; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
use POSIX qw(ceil acos); |
13
|
|
|
|
|
|
|
use Time::Piece; |
14
|
|
|
|
|
|
|
use Carp qw(carp verbose); |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
use vars qw($VERSION); |
17
|
|
|
|
|
|
|
$VERSION = '1.5'; |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
sub new { |
20
|
|
|
|
|
|
|
my $class = shift; |
21
|
|
|
|
|
|
|
my $opt = (@_ == 1) ? { %{shift()} } : {@_}; |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
$opt->{Output} ||= *{STDOUT}{IO}; |
24
|
|
|
|
|
|
|
return bless $opt, $class; |
25
|
|
|
|
|
|
|
} |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
sub set_document_locator { |
28
|
|
|
|
|
|
|
my ($self, $locator) = @_; |
29
|
|
|
|
|
|
|
$self->{locator} = $locator; |
30
|
|
|
|
|
|
|
} |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
sub start_document { |
33
|
|
|
|
|
|
|
my ($self, $doc) = @_; |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
# setup consumer |
36
|
|
|
|
|
|
|
my $ref = ref $self->{Output}; |
37
|
|
|
|
|
|
|
if ($ref eq 'SCALAR') { |
38
|
|
|
|
|
|
|
$self->{Consumer} = XML::SAX::Writer::StringConsumer->new($self->{Output}); |
39
|
|
|
|
|
|
|
} |
40
|
|
|
|
|
|
|
elsif ($ref eq 'ARRAY') { |
41
|
|
|
|
|
|
|
$self->{Consumer} = XML::SAX::Writer::ArrayConsumer->new($self->{Output}); |
42
|
|
|
|
|
|
|
} |
43
|
|
|
|
|
|
|
elsif ($ref eq 'GLOB' or UNIVERSAL::isa($self->{Output}, 'IO::Handle')) { |
44
|
|
|
|
|
|
|
$self->{Consumer} = XML::SAX::Writer::HandleConsumer->new($self->{Output}); |
45
|
|
|
|
|
|
|
} |
46
|
|
|
|
|
|
|
elsif (not $ref) { |
47
|
|
|
|
|
|
|
local *FH; |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
open FH, '> ' . $self->{Output} or |
50
|
|
|
|
|
|
|
XML::SAX::Writer::Exception->throw( Message => "Error opening '" . |
51
|
|
|
|
|
|
|
$self->{Output} . "': $!" ); |
52
|
|
|
|
|
|
|
binmode FH; |
53
|
|
|
|
|
|
|
$self->{Consumer} = XML::SAX::Writer::HandleConsumer->new(*FH); |
54
|
|
|
|
|
|
|
} |
55
|
|
|
|
|
|
|
elsif (UNIVERSAL::can($self->{Output}, 'output')) { |
56
|
|
|
|
|
|
|
$self->{Consumer} = $self->{Output}; |
57
|
|
|
|
|
|
|
} |
58
|
|
|
|
|
|
|
else { |
59
|
|
|
|
|
|
|
XML::SAX::Writer::Exception->throw({ Message => 'Unknown option for Output' }); |
60
|
|
|
|
|
|
|
} |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
$self->{Encoder} = XML::SAX::Writer::NullConverter->new(); |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
$self->{text_encoder} = Text::Iconv->new('utf-8', 'ISO-8859-1'); |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
# create PDF and set defaults |
67
|
|
|
|
|
|
|
$self->{pdf} = PDFLib->new(); |
68
|
|
|
|
|
|
|
$self->{pdf}->papersize("slides"); |
69
|
|
|
|
|
|
|
$self->{pdf}->set_border_style("solid", 0); |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
$self->{headline_font} = "Helvetica"; |
72
|
|
|
|
|
|
|
$self->{headline_size} = 18.0; |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
$self->{title_font} = "Helvetica-Bold"; |
75
|
|
|
|
|
|
|
$self->{title_size} = 24.0; |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
$self->{subtitle_font} = "Helvetica-Bold"; |
78
|
|
|
|
|
|
|
$self->{subtitle_size} = 20.0; |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
$self->{normal_font} = "Helvetica"; |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
$self->{todo} = []; |
83
|
|
|
|
|
|
|
$self->{bookmarks} = []; |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
$self->{default_transition} = []; |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
$self->{gathered_text} = ''; |
88
|
|
|
|
|
|
|
$self->{bullets} = [ ' ', 'l', 'u', 'p', 'n', 'm', 'F' ]; |
89
|
|
|
|
|
|
|
$self->{numbers} = [ ' ', '$1.', '$a)', '$i.', '$A)', '$I' ]; |
90
|
|
|
|
|
|
|
$self->{captions} = []; |
91
|
|
|
|
|
|
|
$self->{list_index} = []; |
92
|
|
|
|
|
|
|
$self->{values} = { 'current-slide' => 0 }; |
93
|
|
|
|
|
|
|
$self->{slide_index} = [ 0 ]; |
94
|
|
|
|
|
|
|
$self->{boxtransition} = []; |
95
|
|
|
|
|
|
|
$self->{fill} = 1; |
96
|
|
|
|
|
|
|
$self->{stroke} = 0; |
97
|
|
|
|
|
|
|
$self->{coords} = 'svg'; |
98
|
|
|
|
|
|
|
} |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
sub run_todo { |
101
|
|
|
|
|
|
|
my $self = shift; |
102
|
|
|
|
|
|
|
while (my $todo = shift(@{$self->{todo}})) { |
103
|
|
|
|
|
|
|
$todo->(); |
104
|
|
|
|
|
|
|
} |
105
|
|
|
|
|
|
|
} |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
sub push_todo { |
108
|
|
|
|
|
|
|
my $self = shift; |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
push @{$self->{todo}}, shift; |
111
|
|
|
|
|
|
|
} |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
sub push_bookmark { |
114
|
|
|
|
|
|
|
my $self = shift; |
115
|
|
|
|
|
|
|
# warn("push_bookmark($_[0]) from ", caller, "\n"); |
116
|
|
|
|
|
|
|
push @{$self->{bookmarks}}, shift; |
117
|
|
|
|
|
|
|
} |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
sub top_bookmark { |
120
|
|
|
|
|
|
|
my $self = shift; |
121
|
|
|
|
|
|
|
return $self->{bookmarks}[-1]; |
122
|
|
|
|
|
|
|
} |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
sub pop_bookmark { |
125
|
|
|
|
|
|
|
my $self = shift; |
126
|
|
|
|
|
|
|
# warn("pop_bookmark() from ", caller, "\n"); |
127
|
|
|
|
|
|
|
pop @{$self->{bookmarks}}; |
128
|
|
|
|
|
|
|
} |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
sub end_document { |
131
|
|
|
|
|
|
|
my ($self) = @_; |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
$self->{pdf}->finish; |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
$self->{Consumer}->output( $self->{pdf}->get_buffer ); |
136
|
|
|
|
|
|
|
$self->{Consumer}->finalize; |
137
|
|
|
|
|
|
|
} |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
sub new_page { |
140
|
|
|
|
|
|
|
my $self = shift; |
141
|
|
|
|
|
|
|
my ($trans,$type) = @_; |
142
|
|
|
|
|
|
|
$type ||= 'normal'; |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
$self->{pdf}->start_page; |
145
|
|
|
|
|
|
|
$self->{values}->{'current-slide'}++ unless $self->{transitional}; |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
my $transition = $trans || $self->get_transition || 'replace'; |
148
|
|
|
|
|
|
|
$transition = 'replace' if $transition eq 'none'; |
149
|
|
|
|
|
|
|
$transition = 'replace' if $self->{PrintMode}; |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
$self->{pdf}->set_parameter(transition => lc($transition)); |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
if ($type ne 'empty') { |
154
|
|
|
|
|
|
|
if (my $bg = $self->{bg}) { |
155
|
|
|
|
|
|
|
my @scale = split(/\*/,$bg->{scale}); |
156
|
|
|
|
|
|
|
my $imgw = $self->get_scale($scale[0],0,$self->{pdf}->get_value("imagewidth", $bg->{image}->img),$self->{pdf}->get_value("resx", $bg->{image}->img)); |
157
|
|
|
|
|
|
|
my $imgh = $self->get_scale($scale[1]||$scale[0],1,$self->{pdf}->get_value("imageheight", $bg->{image}->img),$self->{pdf}->get_value("resy", $bg->{image}->img)); |
158
|
|
|
|
|
|
|
$self->{pdf}->add_image(img => $bg->{image}, x => 0, y => 0, w => $imgw, h => $imgh); |
159
|
|
|
|
|
|
|
} |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
if (my $logo = $self->{logo}) { |
162
|
|
|
|
|
|
|
my @scale = split(/\*/,$logo->{scale}); |
163
|
|
|
|
|
|
|
my $imgw = $self->get_scale($scale[0],0,$self->{pdf}->get_value("imagewidth", $logo->{image}->img),$self->{pdf}->get_value("resx", $logo->{image}->img)); |
164
|
|
|
|
|
|
|
my $imgh = $self->get_scale($scale[1]||$scale[0],1,$self->{pdf}->get_value("imageheight", $logo->{image}->img),$self->{pdf}->get_value("resy", $logo->{image}->img)); |
165
|
|
|
|
|
|
|
$self->{pdf}->add_image(img => $logo->{image}, x => 612 - $imgw - $logo->{x}, y => $logo->{y}, w => $imgw, h => $imgh); |
166
|
|
|
|
|
|
|
} |
167
|
|
|
|
|
|
|
} |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
$self->{pagetype} = $type || 'normal'; |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
$self->process_css_styles("font-family:".$self->{headline_font}.";font-size:".$self->{headline_size}.";stroke:none;fill:black;font-weight:normal;font-style:normal;"); |
172
|
|
|
|
|
|
|
pop @{$self->{font_stack}}; |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
$self->{xindent} = []; |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
$self->{pdf}->set_text_pos(80, 300); |
177
|
|
|
|
|
|
|
} |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
sub get_node_transition { |
180
|
|
|
|
|
|
|
my $self = shift; |
181
|
|
|
|
|
|
|
my ($node) = @_; |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
if (exists($node->{Attributes}{"{}transition"})) { |
184
|
|
|
|
|
|
|
return $node->{Attributes}{"{}transition"}{Value}; |
185
|
|
|
|
|
|
|
} |
186
|
|
|
|
|
|
|
return; |
187
|
|
|
|
|
|
|
} |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
sub get_scale { |
190
|
|
|
|
|
|
|
my ($self, $spec, $vertical, $rel, $res) = @_; |
191
|
|
|
|
|
|
|
$res = 72 if ($res <= 0); # substitute sensible fallback |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
my ($num, $unit) = ($spec =~ m/^\s*([0-9]*(?:\.[0-9]+)?)\s*(em|ex|pt|px|line|page|)\s*$/); |
194
|
|
|
|
|
|
|
die "unknown scale specifier: $spec" if !defined $unit; |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
my $pdf = $self->{bb} || $self->{pdf}; # don't use 'line' outside of a slide, will return "0". |
197
|
|
|
|
|
|
|
if ($unit eq 'em') { |
198
|
|
|
|
|
|
|
if ($vertical) { |
199
|
|
|
|
|
|
|
return $num*$pdf->get_value('capheight')*$pdf->get_value('fontsize'); |
200
|
|
|
|
|
|
|
} else { |
201
|
|
|
|
|
|
|
return $num*$pdf->string_width(text => 'M'); |
202
|
|
|
|
|
|
|
} |
203
|
|
|
|
|
|
|
} elsif ($unit eq 'ex') { |
204
|
|
|
|
|
|
|
if ($vertical) { |
205
|
|
|
|
|
|
|
# FIXME: (probably unfixable) this uses an estimation, not the real value |
206
|
|
|
|
|
|
|
return $num*$pdf->get_value('ascender')*2/3*$pdf->get_value('fontsize'); |
207
|
|
|
|
|
|
|
} else { |
208
|
|
|
|
|
|
|
return $num*$pdf->string_width(text => 'x'); |
209
|
|
|
|
|
|
|
} |
210
|
|
|
|
|
|
|
} elsif ($unit eq 'pt') { |
211
|
|
|
|
|
|
|
return $num; |
212
|
|
|
|
|
|
|
} elsif ($unit eq 'px') { |
213
|
|
|
|
|
|
|
return $num*72/$res; |
214
|
|
|
|
|
|
|
} elsif ($unit eq 'line') { |
215
|
|
|
|
|
|
|
if ($vertical) { |
216
|
|
|
|
|
|
|
return $num*$pdf->get_value('leading'); |
217
|
|
|
|
|
|
|
} else { |
218
|
|
|
|
|
|
|
return $num*($pdf->{w} || $self->{extents}[0]{w}); |
219
|
|
|
|
|
|
|
} |
220
|
|
|
|
|
|
|
} elsif ($unit eq 'page') { |
221
|
|
|
|
|
|
|
if ($vertical) { |
222
|
|
|
|
|
|
|
return $num*$pdf->get_value('pageheight'); |
223
|
|
|
|
|
|
|
} else { |
224
|
|
|
|
|
|
|
return $num*$pdf->get_value('pagewidth'); |
225
|
|
|
|
|
|
|
} |
226
|
|
|
|
|
|
|
} else { |
227
|
|
|
|
|
|
|
return $num*$rel*72/$res; |
228
|
|
|
|
|
|
|
} |
229
|
|
|
|
|
|
|
die "unknown unit: $unit"; |
230
|
|
|
|
|
|
|
} |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
sub get_transition { |
233
|
|
|
|
|
|
|
my $self = shift; |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
my $node = $self->{SlideCurrent} || $self->{Current}; |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
my $transition; |
238
|
|
|
|
|
|
|
while ($node && !($transition = $self->get_node_transition($node))) { |
239
|
|
|
|
|
|
|
$node = $node->{Parent}; |
240
|
|
|
|
|
|
|
} |
241
|
|
|
|
|
|
|
return $transition; |
242
|
|
|
|
|
|
|
} |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
sub playback_cache { |
245
|
|
|
|
|
|
|
my $self = shift; |
246
|
|
|
|
|
|
|
$self->{cache_trash} = []; |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
while (@{$self->{cache}}) { |
249
|
|
|
|
|
|
|
my $thing = shift @{$self->{cache}}; |
250
|
|
|
|
|
|
|
my ($method, $node) = @$thing; |
251
|
|
|
|
|
|
|
$self->$method($node); |
252
|
|
|
|
|
|
|
push @{$self->{cache_trash}}, $thing; |
253
|
|
|
|
|
|
|
} |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
delete $self->{cache_trash}; |
256
|
|
|
|
|
|
|
} |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
sub start_element { |
259
|
|
|
|
|
|
|
my ($self, $el) = @_; |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
my $parent = $el->{Parent} = $self->{Current}; |
262
|
|
|
|
|
|
|
$self->{Current} = $el; |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
if ($self->{cache_until}) { |
265
|
|
|
|
|
|
|
push @{$self->{cache}}, ["slide_start_element", $el]; |
266
|
|
|
|
|
|
|
} |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
my $name = $el->{LocalName}; |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
# warn("start_ $name\n"); |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
if ($name eq 'slideshow') { |
273
|
|
|
|
|
|
|
$self->push_todo(sub { $self->new_page(undef,$el->{Attributes}{"{}type"}{Value}) }); |
274
|
|
|
|
|
|
|
if (exists($el->{Attributes}{"{}default-transition"})) { |
275
|
|
|
|
|
|
|
unshift @{$self->{default_transition}}, $el->{Attributes}{"{}default-transition"}{Value}; |
276
|
|
|
|
|
|
|
} |
277
|
|
|
|
|
|
|
if (exists($el->{Attributes}{"{}coordinates"})) { |
278
|
|
|
|
|
|
|
$self->{coords} = $el->{Attributes}{"{}coordinates"}{Value}; |
279
|
|
|
|
|
|
|
if ($self->{coords} !~ /^(svg|old)$/) { |
280
|
|
|
|
|
|
|
Carp::croak("Unknown coordinate system: $self->{coords}"); |
281
|
|
|
|
|
|
|
} |
282
|
|
|
|
|
|
|
} |
283
|
|
|
|
|
|
|
} |
284
|
|
|
|
|
|
|
elsif ($name eq 'title') { |
285
|
|
|
|
|
|
|
$self->gathered_text; # reset |
286
|
|
|
|
|
|
|
} |
287
|
|
|
|
|
|
|
elsif ($name eq 'metadata') { |
288
|
|
|
|
|
|
|
} |
289
|
|
|
|
|
|
|
elsif ($name eq 'total-slides') { |
290
|
|
|
|
|
|
|
$self->gathered_text; # reset |
291
|
|
|
|
|
|
|
} |
292
|
|
|
|
|
|
|
elsif ($name eq 'speaker') { |
293
|
|
|
|
|
|
|
$self->gathered_text; # reset |
294
|
|
|
|
|
|
|
} |
295
|
|
|
|
|
|
|
elsif ($name eq 'email') { |
296
|
|
|
|
|
|
|
$self->gathered_text; # reset |
297
|
|
|
|
|
|
|
} |
298
|
|
|
|
|
|
|
elsif ($name eq 'organisation') { |
299
|
|
|
|
|
|
|
$self->gathered_text; # reset |
300
|
|
|
|
|
|
|
} |
301
|
|
|
|
|
|
|
elsif ($name eq 'link') { |
302
|
|
|
|
|
|
|
$self->gathered_text; # reset |
303
|
|
|
|
|
|
|
} |
304
|
|
|
|
|
|
|
elsif ($name eq 'logo') { |
305
|
|
|
|
|
|
|
if (exists($el->{Attributes}{"{}scale"})) { |
306
|
|
|
|
|
|
|
$self->{logo}{scale} = $el->{Attributes}{"{}scale"}{Value}; |
307
|
|
|
|
|
|
|
} |
308
|
|
|
|
|
|
|
if (exists($el->{Attributes}{"{}x"})) { |
309
|
|
|
|
|
|
|
$self->{logo}{x} = $el->{Attributes}{"{}x"}{Value}; |
310
|
|
|
|
|
|
|
} |
311
|
|
|
|
|
|
|
if (exists($el->{Attributes}{"{}y"})) { |
312
|
|
|
|
|
|
|
$self->{logo}{y} = $el->{Attributes}{"{}y"}{Value}; |
313
|
|
|
|
|
|
|
} |
314
|
|
|
|
|
|
|
$self->{logo}{x} ||= 0; |
315
|
|
|
|
|
|
|
$self->{logo}{y} ||= 0; |
316
|
|
|
|
|
|
|
$self->{logo}{scale} ||= 1.0; |
317
|
|
|
|
|
|
|
$self->gathered_text; # reset |
318
|
|
|
|
|
|
|
} |
319
|
|
|
|
|
|
|
elsif ($name eq 'background') { |
320
|
|
|
|
|
|
|
if (exists($el->{Attributes}{"{}scale"})) { |
321
|
|
|
|
|
|
|
$self->{bg}{scale} = $el->{Attributes}{"{}scale"}{Value}; |
322
|
|
|
|
|
|
|
} |
323
|
|
|
|
|
|
|
$self->{bg}{scale} ||= 1.0; |
324
|
|
|
|
|
|
|
$self->gathered_text; # reset |
325
|
|
|
|
|
|
|
} |
326
|
|
|
|
|
|
|
elsif ($name eq 'bullet' or $name eq 'numbers') { |
327
|
|
|
|
|
|
|
$self->gathered_text; # reset |
328
|
|
|
|
|
|
|
} |
329
|
|
|
|
|
|
|
elsif ($name eq 'slideset') { |
330
|
|
|
|
|
|
|
$self->run_todo; |
331
|
|
|
|
|
|
|
$self->{slide_index}[0]++; |
332
|
|
|
|
|
|
|
unshift @{$self->{slide_index}}, 0; |
333
|
|
|
|
|
|
|
if (exists($el->{Attributes}{"{}default-transition"})) { |
334
|
|
|
|
|
|
|
unshift @{$self->{default_transition}}, $el->{Attributes}{"{}default-transition"}{Value}; |
335
|
|
|
|
|
|
|
} |
336
|
|
|
|
|
|
|
$self->new_page(undef,$el->{Attributes}{"{}type"}{Value}) unless ($el->{Attributes}{"{}type"}{Value}||'normal') eq 'empty'; |
337
|
|
|
|
|
|
|
} |
338
|
|
|
|
|
|
|
elsif ($name eq 'subtitle') { |
339
|
|
|
|
|
|
|
} |
340
|
|
|
|
|
|
|
elsif ($name eq 'slide') { |
341
|
|
|
|
|
|
|
$self->run_todo; # might need to create slideset here. |
342
|
|
|
|
|
|
|
$self->{pdf}->end_page; |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
$self->{slide_index}[0]++; |
345
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
if (exists($el->{Attributes}{"{}default-transition"})) { |
347
|
|
|
|
|
|
|
unshift @{$self->{default_transition}}, $el->{Attributes}{"{}default-transition"}{Value}; |
348
|
|
|
|
|
|
|
} |
349
|
|
|
|
|
|
|
$self->{images} = []; |
350
|
|
|
|
|
|
|
# cache these events now... |
351
|
|
|
|
|
|
|
$self->{cache_until} = $el->{Name}; |
352
|
|
|
|
|
|
|
$self->{cache} = [["slide_start_element", $el]]; |
353
|
|
|
|
|
|
|
} |
354
|
|
|
|
|
|
|
elsif ($name eq 'image') { |
355
|
|
|
|
|
|
|
$self->gathered_text; |
356
|
|
|
|
|
|
|
if (exists($el->{Attributes}{"{http://www.w3.org/1999/xlink}href"})) { |
357
|
|
|
|
|
|
|
# uses xlink, not characters |
358
|
|
|
|
|
|
|
$self->characters({ Data => $el->{Attributes}{"{http://www.w3.org/1999/xlink}href"}{Value}}); |
359
|
|
|
|
|
|
|
} elsif (exists($el->{Attributes}{"{}href"})) { |
360
|
|
|
|
|
|
|
# workaround for XML::LibXML::SAX problem |
361
|
|
|
|
|
|
|
$self->characters({ Data => $el->{Attributes}{"{}href"}{Value}}); |
362
|
|
|
|
|
|
|
} |
363
|
|
|
|
|
|
|
} |
364
|
|
|
|
|
|
|
elsif ($name =~ /^(source[_-]code|box|table|list|point|plain|value|i|b|u|colou?r|row|col|rect|circle|ellipse|polyline|line|path|text|g|span|variable)$/) { |
365
|
|
|
|
|
|
|
# passthrough to allow these types |
366
|
|
|
|
|
|
|
} |
367
|
|
|
|
|
|
|
else { |
368
|
|
|
|
|
|
|
warn("Unknown tag: $name"); |
369
|
|
|
|
|
|
|
} |
370
|
|
|
|
|
|
|
} |
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
sub end_element { |
373
|
|
|
|
|
|
|
my ($self, $el) = @_; |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
if ($self->{cache_until}) { |
376
|
|
|
|
|
|
|
push @{$self->{cache}}, ["slide_end_element", $el]; |
377
|
|
|
|
|
|
|
if ($el->{Name} eq $self->{cache_until}) { |
378
|
|
|
|
|
|
|
delete $self->{cache_until}; |
379
|
|
|
|
|
|
|
$self->playback_cache; |
380
|
|
|
|
|
|
|
} |
381
|
|
|
|
|
|
|
} |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
$el = $self->{Current}; |
384
|
|
|
|
|
|
|
my $parent = $self->{Current} = $el->{Parent}; |
385
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
my $name = $el->{LocalName}; |
387
|
|
|
|
|
|
|
# warn("end_ $name\n"); |
388
|
|
|
|
|
|
|
if ($name eq 'slideshow') { |
389
|
|
|
|
|
|
|
$self->run_todo; |
390
|
|
|
|
|
|
|
if (exists($el->{Attributes}{"{}default-transition"})) { |
391
|
|
|
|
|
|
|
shift @{$self->{default_transition}}; |
392
|
|
|
|
|
|
|
} |
393
|
|
|
|
|
|
|
$self->pop_bookmark; |
394
|
|
|
|
|
|
|
} |
395
|
|
|
|
|
|
|
elsif ($name eq 'title') { |
396
|
|
|
|
|
|
|
if ($parent->{LocalName} eq 'slideshow') { |
397
|
|
|
|
|
|
|
my $title = $self->gathered_text; |
398
|
|
|
|
|
|
|
$self->{values}->{'slideshow-title'} = $title; |
399
|
|
|
|
|
|
|
$self->push_todo(sub { |
400
|
|
|
|
|
|
|
$self->{pdf}->set_font(face => $self->{title_font}, size => $self->{title_size}); |
401
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
$self->push_bookmark( $self->{pdf}->add_bookmark(text => "Title", open => 1) ); |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
if ($self->{pagetype} ne 'empty') { |
405
|
|
|
|
|
|
|
$self->{pdf}->print_boxed( |
406
|
|
|
|
|
|
|
$title, |
407
|
|
|
|
|
|
|
x => 20, y => 50, w => 570, h => 300, mode => "center"); |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
$self->{pdf}->print_line("") for (1..4); |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
my ($x, $y) = $self->{pdf}->get_text_pos(); |
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
$self->{pdf}->set_font(face => $self->{subtitle_font}, size => $self->{subtitle_size}); |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
# speaker |
416
|
|
|
|
|
|
|
if ($self->{metadata}{speaker}) { |
417
|
|
|
|
|
|
|
$self->{pdf}->add_link(link => "mailto:" . $self->{metadata}{email}, |
418
|
|
|
|
|
|
|
x => 20, y => $y - 10, w => 570, h => 24) |
419
|
|
|
|
|
|
|
if defined $self->{metadata}{email}; |
420
|
|
|
|
|
|
|
$self->{pdf}->print_boxed( |
421
|
|
|
|
|
|
|
$self->{metadata}{speaker}, |
422
|
|
|
|
|
|
|
x => 20, y => 40, w => 570, h => $y - 24, mode => "center"); |
423
|
|
|
|
|
|
|
} |
424
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
$self->{pdf}->print_line(""); |
426
|
|
|
|
|
|
|
(undef, $y) = $self->{pdf}->get_text_pos(); |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
# organisation |
429
|
|
|
|
|
|
|
if ($self->{metadata}{organisation}) { |
430
|
|
|
|
|
|
|
$self->{pdf}->add_link( |
431
|
|
|
|
|
|
|
link => $self->{metadata}{link}, |
432
|
|
|
|
|
|
|
x => 20, y => $y - 10, w => 570, h => 24); |
433
|
|
|
|
|
|
|
$self->{pdf}->print_boxed( |
434
|
|
|
|
|
|
|
$self->{metadata}{organisation}, |
435
|
|
|
|
|
|
|
x => 20, y => 40, w => 570, h => $y - 24, mode => "center"); |
436
|
|
|
|
|
|
|
} |
437
|
|
|
|
|
|
|
} |
438
|
|
|
|
|
|
|
}); |
439
|
|
|
|
|
|
|
} |
440
|
|
|
|
|
|
|
elsif ($parent->{LocalName} eq 'slideset') { |
441
|
|
|
|
|
|
|
my $title = $self->gathered_text; |
442
|
|
|
|
|
|
|
$self->push_bookmark( |
443
|
|
|
|
|
|
|
$self->{pdf}->add_bookmark( |
444
|
|
|
|
|
|
|
text => $title, |
445
|
|
|
|
|
|
|
level => 2, |
446
|
|
|
|
|
|
|
parent_of => $self->top_bookmark, |
447
|
|
|
|
|
|
|
open => 1, |
448
|
|
|
|
|
|
|
) |
449
|
|
|
|
|
|
|
); |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
$self->{pdf}->set_font(face => $self->{title_font}, size => $self->{title_size}); |
452
|
|
|
|
|
|
|
if ($self->{pagetype} ne 'empty') { |
453
|
|
|
|
|
|
|
$self->{pdf}->print_boxed( |
454
|
|
|
|
|
|
|
$title, |
455
|
|
|
|
|
|
|
x => 20, y => 50, w => 570, h => 200, mode => "center"); |
456
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
my ($x, $y) = $self->{pdf}->get_text_pos(); |
458
|
|
|
|
|
|
|
$self->{pdf}->add_link( |
459
|
|
|
|
|
|
|
link => $el->{Attributes}{"{}href"}{Value}, |
460
|
|
|
|
|
|
|
x => 20, y => $y - 5, w => 570, h => 24) if exists($el->{Attributes}{"{}href"}); |
461
|
|
|
|
|
|
|
} |
462
|
|
|
|
|
|
|
} |
463
|
|
|
|
|
|
|
} |
464
|
|
|
|
|
|
|
elsif ($name eq 'metadata') { |
465
|
|
|
|
|
|
|
$self->run_todo; |
466
|
|
|
|
|
|
|
} |
467
|
|
|
|
|
|
|
elsif ($name eq 'total-slides') { |
468
|
|
|
|
|
|
|
$self->{metadata}{'total-slides'} = $self->gathered_text; |
469
|
|
|
|
|
|
|
} |
470
|
|
|
|
|
|
|
elsif ($name eq 'speaker') { |
471
|
|
|
|
|
|
|
$self->{metadata}{speaker} = $self->gathered_text; |
472
|
|
|
|
|
|
|
} |
473
|
|
|
|
|
|
|
elsif ($name eq 'email') { |
474
|
|
|
|
|
|
|
$self->{metadata}{email} = $self->gathered_text; |
475
|
|
|
|
|
|
|
} |
476
|
|
|
|
|
|
|
elsif ($name eq 'organisation') { |
477
|
|
|
|
|
|
|
$self->{metadata}{organisation} = $self->gathered_text; |
478
|
|
|
|
|
|
|
} |
479
|
|
|
|
|
|
|
elsif ($name eq 'link') { |
480
|
|
|
|
|
|
|
$self->{metadata}{link} = $self->gathered_text; |
481
|
|
|
|
|
|
|
} |
482
|
|
|
|
|
|
|
elsif ($name eq 'logo') { |
483
|
|
|
|
|
|
|
my $logo_file = |
484
|
|
|
|
|
|
|
File::Spec->rel2abs( |
485
|
|
|
|
|
|
|
$self->gathered_text, |
486
|
|
|
|
|
|
|
File::Basename::dirname($self->{locator}{SystemId} || '') |
487
|
|
|
|
|
|
|
); |
488
|
|
|
|
|
|
|
my $type = get_filetype($logo_file); |
489
|
|
|
|
|
|
|
my $logo = $self->{pdf}->load_image( |
490
|
|
|
|
|
|
|
filename => $logo_file, |
491
|
|
|
|
|
|
|
filetype => $type, |
492
|
|
|
|
|
|
|
) || die "Couldn't load $logo_file"; |
493
|
|
|
|
|
|
|
if (!$logo) { |
494
|
|
|
|
|
|
|
$self->{pdf}->finish; |
495
|
|
|
|
|
|
|
die "Cannot load image $logo_file!"; |
496
|
|
|
|
|
|
|
} |
497
|
|
|
|
|
|
|
$self->{logo}{image} = $logo; |
498
|
|
|
|
|
|
|
} |
499
|
|
|
|
|
|
|
elsif ($name eq 'background') { |
500
|
|
|
|
|
|
|
my $bg_file = |
501
|
|
|
|
|
|
|
File::Spec->rel2abs( |
502
|
|
|
|
|
|
|
$self->gathered_text, |
503
|
|
|
|
|
|
|
File::Basename::dirname($self->{locator}{SystemId} || '') |
504
|
|
|
|
|
|
|
); |
505
|
|
|
|
|
|
|
my $type = get_filetype($bg_file); |
506
|
|
|
|
|
|
|
my $bg = $self->{pdf}->load_image( |
507
|
|
|
|
|
|
|
filename => $bg_file, |
508
|
|
|
|
|
|
|
filetype => $type, |
509
|
|
|
|
|
|
|
) || die "Couldn't load $bg_file"; |
510
|
|
|
|
|
|
|
if (!$bg) { |
511
|
|
|
|
|
|
|
$self->{pdf}->finish; |
512
|
|
|
|
|
|
|
die "Cannot load image $bg_file!"; |
513
|
|
|
|
|
|
|
} |
514
|
|
|
|
|
|
|
$self->{bg}{image} = $bg; |
515
|
|
|
|
|
|
|
} |
516
|
|
|
|
|
|
|
elsif ($name eq 'bullet') { |
517
|
|
|
|
|
|
|
die "need 'level' attribute for bullet tag" if (!exists($el->{Attributes}{"{}level"})); |
518
|
|
|
|
|
|
|
die "'level' attribute of bullet tag must be an integer > 1" if (int($el->{Attributes}{"{}level"}) < 1); |
519
|
|
|
|
|
|
|
my $bullet = $self->gathered_text; |
520
|
|
|
|
|
|
|
die "bullet text must be a single character" if length($bullet) != 1; |
521
|
|
|
|
|
|
|
$self->{bullets}[int($el->{Attributes}{"{}level"}{Value})] = $bullet; |
522
|
|
|
|
|
|
|
} |
523
|
|
|
|
|
|
|
elsif ($name eq 'numbers') { |
524
|
|
|
|
|
|
|
die "need 'level' attribute for numbers tag" if (!exists($el->{Attributes}{"{}level"})); |
525
|
|
|
|
|
|
|
die "'level' attribute of numbers tag must be an integer > 1" if (int($el->{Attributes}{"{}level"}) < 1); |
526
|
|
|
|
|
|
|
my $num = $self->gathered_text; |
527
|
|
|
|
|
|
|
$self->{numbers}[int($el->{Attributes}{"{}level"}{Value})] = $num; |
528
|
|
|
|
|
|
|
} |
529
|
|
|
|
|
|
|
elsif ($name eq 'slideset') { |
530
|
|
|
|
|
|
|
$self->pop_bookmark; |
531
|
|
|
|
|
|
|
shift @{$self->{slide_index}}; |
532
|
|
|
|
|
|
|
if (exists($el->{Attributes}{"{}default-transition"})) { |
533
|
|
|
|
|
|
|
shift @{$self->{default_transition}}; |
534
|
|
|
|
|
|
|
} |
535
|
|
|
|
|
|
|
} |
536
|
|
|
|
|
|
|
elsif ($name eq 'subtitle') { |
537
|
|
|
|
|
|
|
if ($parent->{LocalName} eq 'slideset') { |
538
|
|
|
|
|
|
|
$self->{pdf}->set_font(face => $self->{subtitle_font}, size => $self->{subtitle_size}); |
539
|
|
|
|
|
|
|
if ($self->{pagetype} ne 'empty') { |
540
|
|
|
|
|
|
|
$self->{pdf}->print_boxed( |
541
|
|
|
|
|
|
|
$self->gathered_text, |
542
|
|
|
|
|
|
|
x => 20, y => 20, w => 570, h => 200, mode => "center"); |
543
|
|
|
|
|
|
|
if (exists($el->{Attributes}{"{}href"})) { |
544
|
|
|
|
|
|
|
my ($x, $y) = $self->{pdf}->get_text_pos(); |
545
|
|
|
|
|
|
|
$self->{pdf}->add_link( |
546
|
|
|
|
|
|
|
link => $el->{Attributes}{"{}href"}{Value}, |
547
|
|
|
|
|
|
|
x => 20, y => $y - 5, w => 570, h => 18); |
548
|
|
|
|
|
|
|
} |
549
|
|
|
|
|
|
|
} |
550
|
|
|
|
|
|
|
} |
551
|
|
|
|
|
|
|
} |
552
|
|
|
|
|
|
|
elsif ($name eq 'slide') { |
553
|
|
|
|
|
|
|
$self->run_todo; |
554
|
|
|
|
|
|
|
if (exists($el->{Attributes}{"{}default-transition"})) { |
555
|
|
|
|
|
|
|
shift @{$self->{default_transition}}; |
556
|
|
|
|
|
|
|
} |
557
|
|
|
|
|
|
|
} |
558
|
|
|
|
|
|
|
elsif ($name eq 'image') { |
559
|
|
|
|
|
|
|
my $image = |
560
|
|
|
|
|
|
|
File::Spec->rel2abs( |
561
|
|
|
|
|
|
|
$self->gathered_text, |
562
|
|
|
|
|
|
|
File::Basename::dirname($self->{locator}{SystemId} || '') |
563
|
|
|
|
|
|
|
); |
564
|
|
|
|
|
|
|
my $image_ref = $self->{pdf}->load_image( |
565
|
|
|
|
|
|
|
filename => $image, |
566
|
|
|
|
|
|
|
filetype => get_filetype($image), |
567
|
|
|
|
|
|
|
) || die "Couldn't load $image"; |
568
|
|
|
|
|
|
|
my $scale = $el->{Attributes}{"{}scale"}{Value} || 1.0; |
569
|
|
|
|
|
|
|
my $href = $el->{Attributes}{"{}href"}{Value}; |
570
|
|
|
|
|
|
|
my $x = $el->{Attributes}{"{}x"}{Value}; |
571
|
|
|
|
|
|
|
my $y = $el->{Attributes}{"{}y"}{Value}; |
572
|
|
|
|
|
|
|
my $width = $el->{Attributes}{"{}width"}{Value}; |
573
|
|
|
|
|
|
|
my $height = $el->{Attributes}{"{}height"}{Value}; |
574
|
|
|
|
|
|
|
|
575
|
|
|
|
|
|
|
push @{$self->{images}}, |
576
|
|
|
|
|
|
|
{ |
577
|
|
|
|
|
|
|
scale => $scale, |
578
|
|
|
|
|
|
|
image_ref => $image_ref, |
579
|
|
|
|
|
|
|
href => $href, |
580
|
|
|
|
|
|
|
x => $x, |
581
|
|
|
|
|
|
|
y => $y, |
582
|
|
|
|
|
|
|
width => $width, |
583
|
|
|
|
|
|
|
height => $height, |
584
|
|
|
|
|
|
|
}; |
585
|
|
|
|
|
|
|
} |
586
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
$self->{Current} = $parent; |
588
|
|
|
|
|
|
|
} |
589
|
|
|
|
|
|
|
|
590
|
|
|
|
|
|
|
sub characters { |
591
|
|
|
|
|
|
|
my ($self, $chars) = @_; |
592
|
|
|
|
|
|
|
|
593
|
|
|
|
|
|
|
if ($self->{cache_until}) { |
594
|
|
|
|
|
|
|
push @{$self->{cache}}, ["slide_characters", $chars]; |
595
|
|
|
|
|
|
|
} |
596
|
|
|
|
|
|
|
|
597
|
|
|
|
|
|
|
$self->{gathered_text} .= $self->{text_encoder}->convert($chars->{Data}); |
598
|
|
|
|
|
|
|
} |
599
|
|
|
|
|
|
|
|
600
|
|
|
|
|
|
|
sub invalid_parent { |
601
|
|
|
|
|
|
|
my $self = shift; |
602
|
|
|
|
|
|
|
warn("Invalid tag nesting: <$self->{Current}{Parent}{LocalName}> <$self->{Current}{LocalName}>"); |
603
|
|
|
|
|
|
|
} |
604
|
|
|
|
|
|
|
|
605
|
|
|
|
|
|
|
sub gathered_text { |
606
|
|
|
|
|
|
|
my $self = shift; |
607
|
|
|
|
|
|
|
return substr($self->{gathered_text}, 0, length($self->{gathered_text}), ''); |
608
|
|
|
|
|
|
|
} |
609
|
|
|
|
|
|
|
|
610
|
|
|
|
|
|
|
sub image { |
611
|
|
|
|
|
|
|
my ($self, $scale, $file_handle, $href) = @_; |
612
|
|
|
|
|
|
|
my $pdf = $self->{pdf}; |
613
|
|
|
|
|
|
|
|
614
|
|
|
|
|
|
|
$pdf->print_line(""); |
615
|
|
|
|
|
|
|
|
616
|
|
|
|
|
|
|
my ($x, $y) = $pdf->get_text_pos; |
617
|
|
|
|
|
|
|
|
618
|
|
|
|
|
|
|
my @scale = split(/\*/,$scale); |
619
|
|
|
|
|
|
|
my $imgw = $self->get_scale($scale[0],0,$pdf->get_value("imagewidth", $file_handle->img),$pdf->get_value("resx", $file_handle->img)); |
620
|
|
|
|
|
|
|
my $imgh = $self->get_scale($scale[1]||$scale[0],1,$pdf->get_value("imageheight", $file_handle->img),$pdf->get_value("resy", $file_handle->img)); |
621
|
|
|
|
|
|
|
|
622
|
|
|
|
|
|
|
my $xpos = (($self->{extents}[0]{x} + ($self->{extents}[0]{w} / 2)) |
623
|
|
|
|
|
|
|
- ($imgw / 2)); |
624
|
|
|
|
|
|
|
my $ypos = ($y - $imgh); |
625
|
|
|
|
|
|
|
|
626
|
|
|
|
|
|
|
# warn("image: ($xpos,$ypos) $imgw x $imgh"); |
627
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
$pdf->add_image(img => $file_handle, |
629
|
|
|
|
|
|
|
x => $xpos, |
630
|
|
|
|
|
|
|
y => $ypos, |
631
|
|
|
|
|
|
|
w => $imgw, |
632
|
|
|
|
|
|
|
h => $imgh); |
633
|
|
|
|
|
|
|
$pdf->add_link(link => $href, x => $xpos, y => $ypos, w => $imgw, h => $imgh) if $href; |
634
|
|
|
|
|
|
|
|
635
|
|
|
|
|
|
|
$pdf->set_text_pos($x, $ypos); |
636
|
|
|
|
|
|
|
} |
637
|
|
|
|
|
|
|
|
638
|
|
|
|
|
|
|
sub bullet { |
639
|
|
|
|
|
|
|
my ($self, $el) = @_; |
640
|
|
|
|
|
|
|
|
641
|
|
|
|
|
|
|
my $pdf = $self->{pdf}; |
642
|
|
|
|
|
|
|
|
643
|
|
|
|
|
|
|
my ($char, $size); |
644
|
|
|
|
|
|
|
|
645
|
|
|
|
|
|
|
my $level = $el->{Attributes}{"{}level"}{Value} || @{$self->{list_index}} || 1; |
646
|
|
|
|
|
|
|
my ($x, $y) = $pdf->get_text_pos; |
647
|
|
|
|
|
|
|
|
648
|
|
|
|
|
|
|
if (@{$self->{xindent}} && $level <= $self->{xindent}[0]{level}) { |
649
|
|
|
|
|
|
|
my $last; |
650
|
|
|
|
|
|
|
while ($last = shift @{$self->{xindent}}) { |
651
|
|
|
|
|
|
|
if ($last->{level} == $level) { |
652
|
|
|
|
|
|
|
$self->{pdf}->set_text_pos($last->{x}, $y); |
653
|
|
|
|
|
|
|
$x = $last->{x}; |
654
|
|
|
|
|
|
|
last; |
655
|
|
|
|
|
|
|
} |
656
|
|
|
|
|
|
|
} |
657
|
|
|
|
|
|
|
} |
658
|
|
|
|
|
|
|
|
659
|
|
|
|
|
|
|
if ($level == 1) { |
660
|
|
|
|
|
|
|
my $indent = 80 * ($self->{extents}[0]{w} / $self->{extents}[-1]{w}); |
661
|
|
|
|
|
|
|
$self->{pdf}->set_text_pos($self->{extents}[0]{x} + $indent, $y); |
662
|
|
|
|
|
|
|
} |
663
|
|
|
|
|
|
|
|
664
|
|
|
|
|
|
|
$char = $self->{bullets}->[$level]; |
665
|
|
|
|
|
|
|
$size = 20-(2*$level); |
666
|
|
|
|
|
|
|
|
667
|
|
|
|
|
|
|
if ($level == 1) { |
668
|
|
|
|
|
|
|
my ($x, $y) = $pdf->get_text_pos; |
669
|
|
|
|
|
|
|
$y += 9; |
670
|
|
|
|
|
|
|
$pdf->set_text_pos($x, $y); |
671
|
|
|
|
|
|
|
$pdf->print_line(""); |
672
|
|
|
|
|
|
|
} |
673
|
|
|
|
|
|
|
|
674
|
|
|
|
|
|
|
($x, $y) = $pdf->get_text_pos; |
675
|
|
|
|
|
|
|
|
676
|
|
|
|
|
|
|
if (!@{$self->{xindent}} || $level > $self->{xindent}[0]{level}) { |
677
|
|
|
|
|
|
|
unshift @{$self->{xindent}}, {level => $level, x => $x}; |
678
|
|
|
|
|
|
|
} |
679
|
|
|
|
|
|
|
|
680
|
|
|
|
|
|
|
my $bw; |
681
|
|
|
|
|
|
|
if (!$el->{Attributes}{"{}level"}{Value} && @{$self->{list_index}} && $self->{list_index}->[-1] > 0) { |
682
|
|
|
|
|
|
|
my $index = $self->{list_index}->[-1]; |
683
|
|
|
|
|
|
|
$self->{list_index}->[-1]++; |
684
|
|
|
|
|
|
|
$char = $self->{numbers}->[$level]; |
685
|
|
|
|
|
|
|
$char =~ s/(([^\$]|^)(\$\$)*)\$1/$1$index/g; |
686
|
|
|
|
|
|
|
my $alpha = ('','a'..'z')[$index]; |
687
|
|
|
|
|
|
|
$char =~ s/(([^\$]|^)(\$\$)*)\$a/$1$alpha/g; |
688
|
|
|
|
|
|
|
$alpha = uc($alpha); |
689
|
|
|
|
|
|
|
$char =~ s/(([^\$]|^)(\$\$)*)\$A/$1$alpha/g; |
690
|
|
|
|
|
|
|
$alpha = ''; |
691
|
|
|
|
|
|
|
$alpha .= 'x', $index -= 10 while ($index > 10); |
692
|
|
|
|
|
|
|
$alpha .= ('','i','ii','iii','iv','v','vi','vii','viii','ix','x')[$index]; |
693
|
|
|
|
|
|
|
$char =~ s/(([^\$]|^)(\$\$)*)\$i/$1$alpha/g; |
694
|
|
|
|
|
|
|
$alpha = uc($alpha); |
695
|
|
|
|
|
|
|
$char =~ s/(([^\$]|^)(\$\$)*)\$I/$1$alpha/g; |
696
|
|
|
|
|
|
|
$char =~ s/\$\$/\$/g; |
697
|
|
|
|
|
|
|
$pdf->set_font(face => $self->{normal_font}, size => $size); |
698
|
|
|
|
|
|
|
$bw = $pdf->string_width(text => $char." "); |
699
|
|
|
|
|
|
|
$pdf->print($char); |
700
|
|
|
|
|
|
|
} else { |
701
|
|
|
|
|
|
|
$pdf->set_font(face => "ZapfDingbats", size => $size - 4, encoding => "builtin"); |
702
|
|
|
|
|
|
|
$bw = $pdf->string_width(text => $char); |
703
|
|
|
|
|
|
|
$pdf->print($char); |
704
|
|
|
|
|
|
|
$pdf->set_font(face => $self->{normal_font}, size => $size); |
705
|
|
|
|
|
|
|
} |
706
|
|
|
|
|
|
|
if ($pdf->string_width(text => " ") < $bw) { |
707
|
|
|
|
|
|
|
$pdf->print(" "); |
708
|
|
|
|
|
|
|
} else { |
709
|
|
|
|
|
|
|
$pdf->set_text_pos($x, $y); |
710
|
|
|
|
|
|
|
$pdf->print(" "); |
711
|
|
|
|
|
|
|
} |
712
|
|
|
|
|
|
|
|
713
|
|
|
|
|
|
|
return ($pdf->get_text_pos, $size); |
714
|
|
|
|
|
|
|
} |
715
|
|
|
|
|
|
|
|
716
|
|
|
|
|
|
|
sub get_filetype { |
717
|
|
|
|
|
|
|
my $filename = shift; |
718
|
|
|
|
|
|
|
|
719
|
|
|
|
|
|
|
my ($suffix) = $filename =~ /([^\.]+?)$/; |
720
|
|
|
|
|
|
|
$suffix = lc($suffix); |
721
|
|
|
|
|
|
|
if ($suffix eq 'jpg') { |
722
|
|
|
|
|
|
|
return 'jpeg'; |
723
|
|
|
|
|
|
|
} |
724
|
|
|
|
|
|
|
return $suffix; |
725
|
|
|
|
|
|
|
} |
726
|
|
|
|
|
|
|
|
727
|
|
|
|
|
|
|
my %colours = ( |
728
|
|
|
|
|
|
|
black => "000000", |
729
|
|
|
|
|
|
|
green => "008000", |
730
|
|
|
|
|
|
|
silver => "C0C0C0", |
731
|
|
|
|
|
|
|
lime => "00FF00", |
732
|
|
|
|
|
|
|
gray => "808080", |
733
|
|
|
|
|
|
|
olive => "808000", |
734
|
|
|
|
|
|
|
white => "FFFFFF", |
735
|
|
|
|
|
|
|
yellow => "FFFF00", |
736
|
|
|
|
|
|
|
maroon => "800000", |
737
|
|
|
|
|
|
|
navy => "000080", |
738
|
|
|
|
|
|
|
red => "FF0000", |
739
|
|
|
|
|
|
|
blue => "0000FF", |
740
|
|
|
|
|
|
|
purple => "800080", |
741
|
|
|
|
|
|
|
teal => "008080", |
742
|
|
|
|
|
|
|
fuchsia => "FF00FF", |
743
|
|
|
|
|
|
|
aqua => "00FFFF", |
744
|
|
|
|
|
|
|
); |
745
|
|
|
|
|
|
|
|
746
|
|
|
|
|
|
|
sub get_colour { |
747
|
|
|
|
|
|
|
my $colour = shift; |
748
|
|
|
|
|
|
|
if ($colour !~ s/^#//) { |
749
|
|
|
|
|
|
|
$colour = $colours{$colour} || die "Unknown colour: $colour"; |
750
|
|
|
|
|
|
|
} |
751
|
|
|
|
|
|
|
if ($colour !~ /^[0-9a-fA-F]{6}$/) { |
752
|
|
|
|
|
|
|
die "Invalid colour format: #$colour"; |
753
|
|
|
|
|
|
|
} |
754
|
|
|
|
|
|
|
my ($r, $g, $b) = map { hex()/255 } ($colour =~ /(..)/g); |
755
|
|
|
|
|
|
|
return [$r, $g, $b]; |
756
|
|
|
|
|
|
|
} |
757
|
|
|
|
|
|
|
|
758
|
|
|
|
|
|
|
my $current_fill_colour = [0,0,0]; |
759
|
|
|
|
|
|
|
my $current_stroke_colour = [0,0,0]; |
760
|
|
|
|
|
|
|
my $current_rendering = 0; |
761
|
|
|
|
|
|
|
my $current_line_cap = 0; |
762
|
|
|
|
|
|
|
my $current_line_join = 0; |
763
|
|
|
|
|
|
|
my $current_line_width = 1; |
764
|
|
|
|
|
|
|
my $current_miter_limit = 10; |
765
|
|
|
|
|
|
|
my $current_fillrule = "winding"; |
766
|
|
|
|
|
|
|
|
767
|
|
|
|
|
|
|
sub push_font { |
768
|
|
|
|
|
|
|
my ($self) = @_; |
769
|
|
|
|
|
|
|
my $pdf = $self->{bb} || $self->{pdf}; |
770
|
|
|
|
|
|
|
my $elt = $self->{SlideCurrent} || $self->{Current}; |
771
|
|
|
|
|
|
|
push @{$self->{font_stack}}, [ |
772
|
|
|
|
|
|
|
$pdf->get_parameter("fontname"), |
773
|
|
|
|
|
|
|
$pdf->get_value("fontsize"), |
774
|
|
|
|
|
|
|
$current_fill_colour, |
775
|
|
|
|
|
|
|
$current_stroke_colour, |
776
|
|
|
|
|
|
|
$pdf->{underline}, |
777
|
|
|
|
|
|
|
$elt->{LocalName}, |
778
|
|
|
|
|
|
|
$self->{fill}, |
779
|
|
|
|
|
|
|
$self->{stroke}, |
780
|
|
|
|
|
|
|
$current_line_cap, |
781
|
|
|
|
|
|
|
$current_line_join, |
782
|
|
|
|
|
|
|
$current_line_width, |
783
|
|
|
|
|
|
|
$current_miter_limit, |
784
|
|
|
|
|
|
|
$current_fillrule, |
785
|
|
|
|
|
|
|
$self->{transitional}, |
786
|
|
|
|
|
|
|
]; |
787
|
|
|
|
|
|
|
} |
788
|
|
|
|
|
|
|
|
789
|
|
|
|
|
|
|
sub pop_font { |
790
|
|
|
|
|
|
|
my ($self) = @_; |
791
|
|
|
|
|
|
|
my ($font, $size, $fill_colour, $stroke_colour, $underline, $name, $fill, $stroke, $lc, $lj, $lw, $ml, $fr, $trans) = @{pop @{$self->{font_stack}}}; |
792
|
|
|
|
|
|
|
my $pdf = $self->{bb} || $self->{pdf}; |
793
|
|
|
|
|
|
|
my $elt = $self->{SlideCurrent} || $self->{Current}; |
794
|
|
|
|
|
|
|
$pdf->set_font(face => $font, size => $size); |
795
|
|
|
|
|
|
|
$current_fill_colour = $fill_colour; |
796
|
|
|
|
|
|
|
$pdf->set_colour(rgb => $current_fill_colour, type => "fill"); |
797
|
|
|
|
|
|
|
$current_stroke_colour = $stroke_colour; |
798
|
|
|
|
|
|
|
$pdf->set_colour(rgb => $current_stroke_colour, type => "stroke"); |
799
|
|
|
|
|
|
|
$pdf->set_decoration($underline?"underline":"none"); |
800
|
|
|
|
|
|
|
$current_line_cap = $lc; |
801
|
|
|
|
|
|
|
$pdf->set_line_cap($lc); |
802
|
|
|
|
|
|
|
$current_line_join = $lj; |
803
|
|
|
|
|
|
|
$pdf->set_line_join($lj); |
804
|
|
|
|
|
|
|
$current_line_width = $lw; |
805
|
|
|
|
|
|
|
$pdf->set_line_width($lw); |
806
|
|
|
|
|
|
|
$current_miter_limit = $ml; |
807
|
|
|
|
|
|
|
$pdf->set_miter_limit($ml); |
808
|
|
|
|
|
|
|
$pdf->set_parameter("fillrule",$fr); |
809
|
|
|
|
|
|
|
$self->{fill} = $fill; |
810
|
|
|
|
|
|
|
$self->{stroke} = $stroke; |
811
|
|
|
|
|
|
|
if ($self->{fill} && $self->{stroke}) { |
812
|
|
|
|
|
|
|
$pdf->set_value(textrendering => 2); |
813
|
|
|
|
|
|
|
} |
814
|
|
|
|
|
|
|
elsif ($self->{fill}) { |
815
|
|
|
|
|
|
|
$pdf->set_value(textrendering => 0); |
816
|
|
|
|
|
|
|
} |
817
|
|
|
|
|
|
|
elsif ($self->{stroke}) { |
818
|
|
|
|
|
|
|
$pdf->set_value(textrendering => 1); |
819
|
|
|
|
|
|
|
} |
820
|
|
|
|
|
|
|
else { |
821
|
|
|
|
|
|
|
$pdf->set_value(textrendering => 3); # invisible |
822
|
|
|
|
|
|
|
} |
823
|
|
|
|
|
|
|
} |
824
|
|
|
|
|
|
|
|
825
|
|
|
|
|
|
|
sub process_css_styles { |
826
|
|
|
|
|
|
|
my ($self, $style, $text_mode) = @_; |
827
|
|
|
|
|
|
|
|
828
|
|
|
|
|
|
|
if ($text_mode) { |
829
|
|
|
|
|
|
|
$self->{stroke} = 0; |
830
|
|
|
|
|
|
|
$self->{fill} = 1; |
831
|
|
|
|
|
|
|
} |
832
|
|
|
|
|
|
|
else { |
833
|
|
|
|
|
|
|
$self->{stroke} = 1; |
834
|
|
|
|
|
|
|
$self->{fill} = 0; |
835
|
|
|
|
|
|
|
} |
836
|
|
|
|
|
|
|
|
837
|
|
|
|
|
|
|
$self->push_font(); |
838
|
|
|
|
|
|
|
return unless $style; |
839
|
|
|
|
|
|
|
|
840
|
|
|
|
|
|
|
my $pdf = $self->{bb} || $self->{pdf}; |
841
|
|
|
|
|
|
|
|
842
|
|
|
|
|
|
|
my $new_font = $pdf->get_parameter("fontname"); |
843
|
|
|
|
|
|
|
my $bold = 0; |
844
|
|
|
|
|
|
|
my $italic = 0; |
845
|
|
|
|
|
|
|
my $underline = 0; |
846
|
|
|
|
|
|
|
my $size = $pdf->get_value('fontsize'); |
847
|
|
|
|
|
|
|
if ($new_font =~ s/-(.*)$//) { |
848
|
|
|
|
|
|
|
my $removed = $1; |
849
|
|
|
|
|
|
|
if ($removed =~ /Bold/i) { |
850
|
|
|
|
|
|
|
$bold = 1; |
851
|
|
|
|
|
|
|
} |
852
|
|
|
|
|
|
|
if ($removed =~ /(Oblique|Italic)/i) { |
853
|
|
|
|
|
|
|
$italic = 1; |
854
|
|
|
|
|
|
|
} |
855
|
|
|
|
|
|
|
} |
856
|
|
|
|
|
|
|
foreach my $part (split(/;\s*/s, $style)) { |
857
|
|
|
|
|
|
|
my ($key, $value) = split(/\s*:\s*/, $part, 2); |
858
|
|
|
|
|
|
|
# Keys we need to implement: |
859
|
|
|
|
|
|
|
# color, fill, font, font-style, font-weight, font-size, |
860
|
|
|
|
|
|
|
# font-family, stroke, stroke-linecap, stroke-linejoin, stroke-width, |
861
|
|
|
|
|
|
|
|
862
|
|
|
|
|
|
|
# warn("got $key = $value\n"); |
863
|
|
|
|
|
|
|
if ($key eq 'font') { |
864
|
|
|
|
|
|
|
# [ [ <'font-style'> || <'font-variant'> || <'font-weight'> ]? <'font-size'> [ / <'line-height'> ]? <'font-family'> ] |
865
|
|
|
|
|
|
|
if ($value =~ /^((\S+)\s+)?((\S+)\s+)(\S+)$/) { |
866
|
|
|
|
|
|
|
my ($attribs, $ptsize, $name) = ($2, $4, $5); |
867
|
|
|
|
|
|
|
$attribs ||= 'inherit'; |
868
|
|
|
|
|
|
|
if ($attribs eq 'normal') { |
869
|
|
|
|
|
|
|
$bold = 0; $italic = 0; |
870
|
|
|
|
|
|
|
} |
871
|
|
|
|
|
|
|
elsif ($attribs eq 'inherit') { |
872
|
|
|
|
|
|
|
# Do nothing |
873
|
|
|
|
|
|
|
} |
874
|
|
|
|
|
|
|
elsif ($attribs eq 'bold' || $attribs eq 'bolder') { |
875
|
|
|
|
|
|
|
$bold = 1; |
876
|
|
|
|
|
|
|
} |
877
|
|
|
|
|
|
|
elsif ($attribs eq 'italic' || $attribs eq 'oblique') { |
878
|
|
|
|
|
|
|
$italic = 1; |
879
|
|
|
|
|
|
|
} |
880
|
|
|
|
|
|
|
|
881
|
|
|
|
|
|
|
if ($ptsize !~ s/pt$//) { |
882
|
|
|
|
|
|
|
die "Cannot support fonts in anything but point sizes yet: $value"; |
883
|
|
|
|
|
|
|
} |
884
|
|
|
|
|
|
|
$size = $ptsize; |
885
|
|
|
|
|
|
|
|
886
|
|
|
|
|
|
|
$name =~ s/sans-serif/Helvetica/; |
887
|
|
|
|
|
|
|
$name =~ s/serif/Times/; |
888
|
|
|
|
|
|
|
$name =~ s/monospace/Courier/; |
889
|
|
|
|
|
|
|
$new_font = $name; |
890
|
|
|
|
|
|
|
} |
891
|
|
|
|
|
|
|
else { |
892
|
|
|
|
|
|
|
die "Failed to parse CSS font attribute: $value"; |
893
|
|
|
|
|
|
|
} |
894
|
|
|
|
|
|
|
} |
895
|
|
|
|
|
|
|
elsif ($key eq 'font-family') { |
896
|
|
|
|
|
|
|
$value =~ s/sans-serif/Helvetica/; |
897
|
|
|
|
|
|
|
$value =~ s/serif/Times/; |
898
|
|
|
|
|
|
|
$value =~ s/monospace/Courier/; |
899
|
|
|
|
|
|
|
$new_font = $value; |
900
|
|
|
|
|
|
|
} |
901
|
|
|
|
|
|
|
elsif ($key eq 'font-style') { |
902
|
|
|
|
|
|
|
if ($value eq 'normal') { |
903
|
|
|
|
|
|
|
$italic = 0; |
904
|
|
|
|
|
|
|
} |
905
|
|
|
|
|
|
|
elsif ($value eq 'italic') { |
906
|
|
|
|
|
|
|
$italic = 1; |
907
|
|
|
|
|
|
|
} |
908
|
|
|
|
|
|
|
} |
909
|
|
|
|
|
|
|
elsif ($key eq 'font-weight') { |
910
|
|
|
|
|
|
|
if ($value eq 'normal') { |
911
|
|
|
|
|
|
|
$bold = 0; |
912
|
|
|
|
|
|
|
} |
913
|
|
|
|
|
|
|
elsif ($value eq 'bold') { |
914
|
|
|
|
|
|
|
$bold = 1; |
915
|
|
|
|
|
|
|
} |
916
|
|
|
|
|
|
|
} |
917
|
|
|
|
|
|
|
elsif ($key eq 'text-decoration') { |
918
|
|
|
|
|
|
|
if ($value eq 'none') { |
919
|
|
|
|
|
|
|
$underline = 0; |
920
|
|
|
|
|
|
|
} |
921
|
|
|
|
|
|
|
elsif ($value eq 'underline') { |
922
|
|
|
|
|
|
|
$underline = 1; |
923
|
|
|
|
|
|
|
} |
924
|
|
|
|
|
|
|
} |
925
|
|
|
|
|
|
|
elsif ($key eq 'font-size') { |
926
|
|
|
|
|
|
|
if ($value !~ s/pt$// && $value =~ m/[a-z]/) { |
927
|
|
|
|
|
|
|
die "Can't do anything but font-size in pt yet"; |
928
|
|
|
|
|
|
|
} |
929
|
|
|
|
|
|
|
$size = $value; |
930
|
|
|
|
|
|
|
} |
931
|
|
|
|
|
|
|
elsif ($key eq 'color') { |
932
|
|
|
|
|
|
|
# set both the stroke and fill color |
933
|
|
|
|
|
|
|
$current_fill_colour = $current_stroke_colour = get_colour($value); |
934
|
|
|
|
|
|
|
$pdf->set_colour(rgb => $current_fill_colour, type => "both"); |
935
|
|
|
|
|
|
|
} |
936
|
|
|
|
|
|
|
elsif ($key eq 'fill') { |
937
|
|
|
|
|
|
|
if ($value eq 'none') { |
938
|
|
|
|
|
|
|
$self->{fill} = 0; |
939
|
|
|
|
|
|
|
} |
940
|
|
|
|
|
|
|
else { |
941
|
|
|
|
|
|
|
# it's a color |
942
|
|
|
|
|
|
|
$self->{fill} = 1; |
943
|
|
|
|
|
|
|
$current_fill_colour = get_colour($value); |
944
|
|
|
|
|
|
|
$pdf->set_colour(rgb => $current_fill_colour, type => "fill"); |
945
|
|
|
|
|
|
|
} |
946
|
|
|
|
|
|
|
} |
947
|
|
|
|
|
|
|
elsif ($key eq 'fill-rule') { |
948
|
|
|
|
|
|
|
$value = 'winding' if $value eq 'nonzero'; |
949
|
|
|
|
|
|
|
$pdf->set_parameter(fillrule => $value); |
950
|
|
|
|
|
|
|
$current_fillrule = $value; |
951
|
|
|
|
|
|
|
} |
952
|
|
|
|
|
|
|
elsif ($key eq 'stroke') { |
953
|
|
|
|
|
|
|
if ($value eq 'none') { |
954
|
|
|
|
|
|
|
$self->{stroke} = 0; |
955
|
|
|
|
|
|
|
} |
956
|
|
|
|
|
|
|
else { |
957
|
|
|
|
|
|
|
# it's a color |
958
|
|
|
|
|
|
|
$self->{stroke} = 1; |
959
|
|
|
|
|
|
|
$current_stroke_colour = get_colour($value); |
960
|
|
|
|
|
|
|
$pdf->set_colour(rgb => $current_stroke_colour, type => "stroke"); |
961
|
|
|
|
|
|
|
} |
962
|
|
|
|
|
|
|
} |
963
|
|
|
|
|
|
|
elsif ($key eq 'stroke-linecap') { |
964
|
|
|
|
|
|
|
$pdf->set_line_cap("${value}_end"); # PDFLib takes care of butt|round|square |
965
|
|
|
|
|
|
|
$current_line_cap = $value; |
966
|
|
|
|
|
|
|
} |
967
|
|
|
|
|
|
|
elsif ($key eq 'stroke-linejoin') { |
968
|
|
|
|
|
|
|
$pdf->set_line_join($value); # PDFLib takes care of miter|round|bevel |
969
|
|
|
|
|
|
|
$current_line_join = $value; |
970
|
|
|
|
|
|
|
} |
971
|
|
|
|
|
|
|
elsif ($key eq 'stroke-width') { |
972
|
|
|
|
|
|
|
$pdf->set_line_width($value); |
973
|
|
|
|
|
|
|
$current_line_width = $value; |
974
|
|
|
|
|
|
|
} |
975
|
|
|
|
|
|
|
elsif ($key eq 'stroke-miterlimit') { |
976
|
|
|
|
|
|
|
$pdf->set_miter_limit($value); |
977
|
|
|
|
|
|
|
$current_miter_limit = $value; |
978
|
|
|
|
|
|
|
} |
979
|
|
|
|
|
|
|
} |
980
|
|
|
|
|
|
|
|
981
|
|
|
|
|
|
|
return unless $text_mode; |
982
|
|
|
|
|
|
|
|
983
|
|
|
|
|
|
|
$pdf->set_decoration($underline?"underline":"none"); |
984
|
|
|
|
|
|
|
|
985
|
|
|
|
|
|
|
my $ok = 0; |
986
|
|
|
|
|
|
|
# warn(sprintf("set_font(%s => %s, %s => %s, %s => %s, %s => %s)\n", |
987
|
|
|
|
|
|
|
# face => $new_font, |
988
|
|
|
|
|
|
|
# italic => $italic, |
989
|
|
|
|
|
|
|
# bold => $bold, |
990
|
|
|
|
|
|
|
# size => $size, |
991
|
|
|
|
|
|
|
# ) |
992
|
|
|
|
|
|
|
# ); |
993
|
|
|
|
|
|
|
foreach my $face (split(/\s*/, $new_font)) { |
994
|
|
|
|
|
|
|
eval { |
995
|
|
|
|
|
|
|
$pdf->set_font( |
996
|
|
|
|
|
|
|
face => $new_font, |
997
|
|
|
|
|
|
|
italic => $italic, |
998
|
|
|
|
|
|
|
bold => $bold, |
999
|
|
|
|
|
|
|
size => $size, |
1000
|
|
|
|
|
|
|
); |
1001
|
|
|
|
|
|
|
}; |
1002
|
|
|
|
|
|
|
if (!$@) { |
1003
|
|
|
|
|
|
|
$ok = 1; |
1004
|
|
|
|
|
|
|
last; |
1005
|
|
|
|
|
|
|
} |
1006
|
|
|
|
|
|
|
} |
1007
|
|
|
|
|
|
|
if (!$ok) { |
1008
|
|
|
|
|
|
|
die "Unable to find font: $new_font : $@"; |
1009
|
|
|
|
|
|
|
} |
1010
|
|
|
|
|
|
|
|
1011
|
|
|
|
|
|
|
if ($self->{fill} && $self->{stroke}) { |
1012
|
|
|
|
|
|
|
$pdf->set_value(textrendering => 2); |
1013
|
|
|
|
|
|
|
} |
1014
|
|
|
|
|
|
|
elsif ($self->{fill}) { |
1015
|
|
|
|
|
|
|
$pdf->set_value(textrendering => 0); |
1016
|
|
|
|
|
|
|
} |
1017
|
|
|
|
|
|
|
elsif ($self->{stroke}) { |
1018
|
|
|
|
|
|
|
$pdf->set_value(textrendering => 1); |
1019
|
|
|
|
|
|
|
} |
1020
|
|
|
|
|
|
|
else { |
1021
|
|
|
|
|
|
|
$pdf->set_value(textrendering => 3); # invisible |
1022
|
|
|
|
|
|
|
} |
1023
|
|
|
|
|
|
|
} |
1024
|
|
|
|
|
|
|
|
1025
|
|
|
|
|
|
|
sub slide_start_element { |
1026
|
|
|
|
|
|
|
my ($self, $el) = @_; |
1027
|
|
|
|
|
|
|
|
1028
|
|
|
|
|
|
|
$self->{SlideCurrent} = $el; |
1029
|
|
|
|
|
|
|
|
1030
|
|
|
|
|
|
|
my $name = $el->{LocalName}; |
1031
|
|
|
|
|
|
|
|
1032
|
|
|
|
|
|
|
#warn("slide_start_ $name ".join(",",map { $_."=>".$el->{Attributes}{$_}->{Value} } keys %{$el->{Attributes}})."\n"); |
1033
|
|
|
|
|
|
|
|
1034
|
|
|
|
|
|
|
# transitions... |
1035
|
|
|
|
|
|
|
if ( (!$self->{PrintMode}) && |
1036
|
|
|
|
|
|
|
$name =~ /^(point|plain|image|source[_-]code|table|col|row|circle|ellipse|rect|text|line|path)$/) { |
1037
|
|
|
|
|
|
|
if (exists($el->{Attributes}{"{}transition"}) |
1038
|
|
|
|
|
|
|
|| @{$self->{default_transition}}) { |
1039
|
|
|
|
|
|
|
# has a transition |
1040
|
|
|
|
|
|
|
my $trans = $el->{Attributes}{"{}transition"}; |
1041
|
|
|
|
|
|
|
# default transition if unspecified (and not for table tags) |
1042
|
|
|
|
|
|
|
if ( (!$trans) && ($name ne 'table') && ($name ne 'row') && ($name ne 'col') && ($name ne 'box') ) { |
1043
|
|
|
|
|
|
|
$trans = { Value => $self->{default_transition}[0] }; |
1044
|
|
|
|
|
|
|
} |
1045
|
|
|
|
|
|
|
if ($trans && ($trans->{Value} ne 'none') ) { |
1046
|
|
|
|
|
|
|
my @cache = @{$self->{cache_trash}}; |
1047
|
|
|
|
|
|
|
local $self->{cache} = \@cache; |
1048
|
|
|
|
|
|
|
local $self->{cache_trash}; |
1049
|
|
|
|
|
|
|
# warn("playback on $el\n"); |
1050
|
|
|
|
|
|
|
$self->{transitional} = 1; |
1051
|
|
|
|
|
|
|
my $parent = $el->{Parent}; |
1052
|
|
|
|
|
|
|
while ($parent) { |
1053
|
|
|
|
|
|
|
last if $parent->{LocalName} eq 'slide'; |
1054
|
|
|
|
|
|
|
$parent = $parent->{Parent}; |
1055
|
|
|
|
|
|
|
} |
1056
|
|
|
|
|
|
|
die "No parent slide element" unless $parent; |
1057
|
|
|
|
|
|
|
local $parent->{Attributes}{"{}transition"}{Value} = $trans->{Value}; |
1058
|
|
|
|
|
|
|
$self->playback_cache; # should get us back here. |
1059
|
|
|
|
|
|
|
$self->run_todo; |
1060
|
|
|
|
|
|
|
# make sure we don't transition this node again |
1061
|
|
|
|
|
|
|
$el->{Attributes}{"{}transition"}{Value} = 'none'; |
1062
|
|
|
|
|
|
|
# warn("playback returns\n"); |
1063
|
|
|
|
|
|
|
$self->{transitional} = 0; |
1064
|
|
|
|
|
|
|
pop @{$self->{font_stack}} while (@{$self->{font_stack}} && $self->{font_stack}[-1][-1]); |
1065
|
|
|
|
|
|
|
} |
1066
|
|
|
|
|
|
|
} else { |
1067
|
|
|
|
|
|
|
$el->{Attributes}{"{}transition"}{Value} = 'none'; |
1068
|
|
|
|
|
|
|
} |
1069
|
|
|
|
|
|
|
} |
1070
|
|
|
|
|
|
|
|
1071
|
|
|
|
|
|
|
if ($name =~ m/^(table|list|image|source[-_]code)$/ && $el->{Attributes}{'{}title'}) { |
1072
|
|
|
|
|
|
|
$self->push_font(); |
1073
|
|
|
|
|
|
|
$self->{pdf}->set_font(face => $self->{normal_font}, italic => 1, size => 15); |
1074
|
|
|
|
|
|
|
my ($x, $y) = $self->{pdf}->get_text_pos; |
1075
|
|
|
|
|
|
|
my $indent = 80 * ($self->{extents}[0]{w} / $self->{extents}[-1]{w}); |
1076
|
|
|
|
|
|
|
$self->{pdf}->set_text_pos($self->{bb}?$self->{bb}->{x}:$self->{extents}[0]{x}+$indent, $y); |
1077
|
|
|
|
|
|
|
$self->{pdf}->print($el->{Attributes}{'{}title'}{Value}); |
1078
|
|
|
|
|
|
|
$self->{pdf}->print_line("") unless $name eq 'image'; |
1079
|
|
|
|
|
|
|
$self->pop_font(); |
1080
|
|
|
|
|
|
|
} |
1081
|
|
|
|
|
|
|
|
1082
|
|
|
|
|
|
|
if ($name eq 'slide') { |
1083
|
|
|
|
|
|
|
$self->new_page(undef,$el->{Attributes}{"{}type"}{Value}); |
1084
|
|
|
|
|
|
|
$self->{image_id} = 0; |
1085
|
|
|
|
|
|
|
# if we do bullet/image transitions, make sure new pages don't use a transition |
1086
|
|
|
|
|
|
|
$el->{Attributes}{"{}transition"}{Value} = "replace"; |
1087
|
|
|
|
|
|
|
$self->{extents} = [{ x => 0, w => 612 }]; |
1088
|
|
|
|
|
|
|
} |
1089
|
|
|
|
|
|
|
elsif ($name eq 'title') { |
1090
|
|
|
|
|
|
|
$self->gathered_text; # reset |
1091
|
|
|
|
|
|
|
$self->{chars_ok} = 1; |
1092
|
|
|
|
|
|
|
|
1093
|
|
|
|
|
|
|
if ($self->{pagetype} ne 'empty') { |
1094
|
|
|
|
|
|
|
my $bb = $self->{pdf}->new_bounding_box( |
1095
|
|
|
|
|
|
|
x => 5, y => 400, w => 602, h => 50, |
1096
|
|
|
|
|
|
|
align => "centre", |
1097
|
|
|
|
|
|
|
); |
1098
|
|
|
|
|
|
|
$self->{bb} = $bb; |
1099
|
|
|
|
|
|
|
$bb->set_font( |
1100
|
|
|
|
|
|
|
face => $self->{title_font}, |
1101
|
|
|
|
|
|
|
size => $self->{title_size}, |
1102
|
|
|
|
|
|
|
); |
1103
|
|
|
|
|
|
|
} |
1104
|
|
|
|
|
|
|
} |
1105
|
|
|
|
|
|
|
elsif ($name eq 'table') { |
1106
|
|
|
|
|
|
|
# push extents. |
1107
|
|
|
|
|
|
|
$self->{extents} = [{ %{$self->{extents}[0]} }, @{$self->{extents}}]; |
1108
|
|
|
|
|
|
|
$self->{col_widths} = []; |
1109
|
|
|
|
|
|
|
my ($x, $y) = $self->{pdf}->get_text_pos; |
1110
|
|
|
|
|
|
|
$self->{pdf}->set_text_pos($self->{extents}[1]{x}, $y); |
1111
|
|
|
|
|
|
|
$self->{max_height} = $y; |
1112
|
|
|
|
|
|
|
$self->{row_number} = 0; |
1113
|
|
|
|
|
|
|
} |
1114
|
|
|
|
|
|
|
elsif ($name eq 'box') { |
1115
|
|
|
|
|
|
|
if (!$self->{transitional}) { |
1116
|
|
|
|
|
|
|
if (exists($el->{Attributes}{"{}default-transition"})) { |
1117
|
|
|
|
|
|
|
unshift @{$self->{default_transition}}, $el->{Attributes}{"{}default-transition"}{Value}; |
1118
|
|
|
|
|
|
|
unshift @{$self->{boxtransition}}, 1; |
1119
|
|
|
|
|
|
|
delete $el->{Attributes}{"{}default-transition"}; |
1120
|
|
|
|
|
|
|
} else { |
1121
|
|
|
|
|
|
|
unshift @{$self->{boxtransition}}, 0; |
1122
|
|
|
|
|
|
|
} |
1123
|
|
|
|
|
|
|
} |
1124
|
|
|
|
|
|
|
# push extents. |
1125
|
|
|
|
|
|
|
$self->{extents} = [{ %{$self->{extents}[0]} }, @{$self->{extents}}]; |
1126
|
|
|
|
|
|
|
$self->{extents}[0]{x} = $el->{Attributes}{'{}x'}{Value}; |
1127
|
|
|
|
|
|
|
$self->{extents}[0]{w} = $el->{Attributes}{'{}width'}{Value}; |
1128
|
|
|
|
|
|
|
$self->{extents}[0]{y} = $el->{Attributes}{'{}y'}{Value}; |
1129
|
|
|
|
|
|
|
$self->{extents}[0]{h} = $el->{Attributes}{'{}height'}{Value}; |
1130
|
|
|
|
|
|
|
$self->{boxlast} = [ $self->{pdf}->get_text_pos() ]; |
1131
|
|
|
|
|
|
|
$self->{pdf}->set_text_pos($self->{extents}[0]{x}, $self->{extents}[0]{y}); |
1132
|
|
|
|
|
|
|
} |
1133
|
|
|
|
|
|
|
elsif ($name eq 'row') { |
1134
|
|
|
|
|
|
|
$self->{col_number} = 0; |
1135
|
|
|
|
|
|
|
$self->{row_start} = []; |
1136
|
|
|
|
|
|
|
@{$self->{row_start}} = $self->{pdf}->get_text_pos; |
1137
|
|
|
|
|
|
|
} |
1138
|
|
|
|
|
|
|
elsif ($name eq 'col') { |
1139
|
|
|
|
|
|
|
my $width; |
1140
|
|
|
|
|
|
|
my $prev_x = $self->{extents}[1]{x}; |
1141
|
|
|
|
|
|
|
if ($self->{row_number} > 0) { |
1142
|
|
|
|
|
|
|
$width = $self->{col_widths}[$self->{col_number}]; |
1143
|
|
|
|
|
|
|
} |
1144
|
|
|
|
|
|
|
else { |
1145
|
|
|
|
|
|
|
$width = $el->{Attributes}{"{}width"}{Value}; |
1146
|
|
|
|
|
|
|
$width =~ s/%$// || die "Column widths must be in percentages"; |
1147
|
|
|
|
|
|
|
# warn("calculating ${width}% of $self->{extents}[1]{w}\n"); |
1148
|
|
|
|
|
|
|
$width = $self->{extents}[1]{w} * ($width/100); |
1149
|
|
|
|
|
|
|
$self->{col_widths}[$self->{col_number}] = $width; |
1150
|
|
|
|
|
|
|
} |
1151
|
|
|
|
|
|
|
if ($self->{col_number} > 0) { |
1152
|
|
|
|
|
|
|
my $up_to = $self->{col_number} - 1; |
1153
|
|
|
|
|
|
|
foreach my $col (0 .. $up_to) { |
1154
|
|
|
|
|
|
|
$prev_x += $self->{col_widths}[$col]; |
1155
|
|
|
|
|
|
|
} |
1156
|
|
|
|
|
|
|
} |
1157
|
|
|
|
|
|
|
# warn("col setting extents to x => $prev_x, w => $width\n"); |
1158
|
|
|
|
|
|
|
$self->{extents}[0]{x} = $prev_x; |
1159
|
|
|
|
|
|
|
$self->{extents}[0]{w} = $width; |
1160
|
|
|
|
|
|
|
$self->{pdf}->set_text_pos(@{$self->{row_start}}); |
1161
|
|
|
|
|
|
|
} |
1162
|
|
|
|
|
|
|
elsif ($name eq 'value') { |
1163
|
|
|
|
|
|
|
my $type = $el->{Attributes}{'{}type'}{Value}; |
1164
|
|
|
|
|
|
|
my $pdf = $self->{bb} || $self->{pdf}; |
1165
|
|
|
|
|
|
|
if (exists $self->{values}->{$type}) { |
1166
|
|
|
|
|
|
|
$pdf->print($self->{values}->{$type}); |
1167
|
|
|
|
|
|
|
} elsif (exists $self->{metadata}->{$type}) { |
1168
|
|
|
|
|
|
|
$pdf->print($self->{metadata}->{$type}); |
1169
|
|
|
|
|
|
|
} elsif ($type eq 'today') { |
1170
|
|
|
|
|
|
|
$pdf->print(localtime->strftime($el->{Attributes}{'{}format'}{Value}||'%Y-%m-%d')); |
1171
|
|
|
|
|
|
|
} elsif ($type eq 'logo') { |
1172
|
|
|
|
|
|
|
if (my $logo = $self->{logo}) { |
1173
|
|
|
|
|
|
|
my @scale = split(/\*/,$logo->{scale}); |
1174
|
|
|
|
|
|
|
my $imgw = $self->get_scale($scale[0],0,$self->{pdf}->get_value("imagewidth", $logo->{image}->img),$self->{pdf}->get_value("resx", $logo->{image}->img)); |
1175
|
|
|
|
|
|
|
my $imgh = $self->get_scale($scale[1]||$scale[0],1,$self->{pdf}->get_value("imageheight", $logo->{image}->img),$self->{pdf}->get_value("resy", $logo->{image}->img)); |
1176
|
|
|
|
|
|
|
my ($x, $y) = $pdf->get_text_pos(); |
1177
|
|
|
|
|
|
|
if ($self->{bb}) { |
1178
|
|
|
|
|
|
|
$pdf->push_todo('add_image',img => $logo->{image}, x => $x+$pdf->{cur_width}, y => $y, w => $imgw, h => $imgh); |
1179
|
|
|
|
|
|
|
$pdf->push_todo('set_text_pos',$x+$pdf->{cur_width}+$imgw,$y); |
1180
|
|
|
|
|
|
|
} else { |
1181
|
|
|
|
|
|
|
$pdf->add_image(img => $logo->{image}, x => $x, y => $y, w => $imgw, h => $imgh); |
1182
|
|
|
|
|
|
|
} |
1183
|
|
|
|
|
|
|
} |
1184
|
|
|
|
|
|
|
} elsif ($type eq 'background') { |
1185
|
|
|
|
|
|
|
if (my $bg = $self->{bg}) { |
1186
|
|
|
|
|
|
|
my @scale = split(/\*/,$bg->{scale}); |
1187
|
|
|
|
|
|
|
my $imgw = $self->get_scale($scale[0],0,$self->{pdf}->get_value("imagewidth", $bg->{image}->img),$self->{pdf}->get_value("resx", $bg->{image}->img)); |
1188
|
|
|
|
|
|
|
my $imgh = $self->get_scale($scale[1]||$scale[0],1,$self->{pdf}->get_value("imageheight", $bg->{image}->img),$self->{pdf}->get_value("resy", $bg->{image}->img)); |
1189
|
|
|
|
|
|
|
my ($x, $y) = $pdf->get_text_pos(); |
1190
|
|
|
|
|
|
|
if ($self->{bb}) { |
1191
|
|
|
|
|
|
|
$pdf->push_todo('add_image',img => $bg->{image}, x => $x+$pdf->{cur_width}, y => $y, w => $imgw, h => $imgh); |
1192
|
|
|
|
|
|
|
$pdf->push_todo('set_text_pos',$x+$pdf->{cur_width}+$imgw,$y); |
1193
|
|
|
|
|
|
|
} else { |
1194
|
|
|
|
|
|
|
$pdf->add_image(img => $bg->{image}, x => $x, y => $y, w => $imgw, h => $imgh); |
1195
|
|
|
|
|
|
|
} |
1196
|
|
|
|
|
|
|
} |
1197
|
|
|
|
|
|
|
} elsif ($type eq 'current-slideset') { |
1198
|
|
|
|
|
|
|
$pdf->print(join(".",reverse @{$self->{slide_index}}).". "); |
1199
|
|
|
|
|
|
|
} |
1200
|
|
|
|
|
|
|
} |
1201
|
|
|
|
|
|
|
elsif ($name eq 'i') { |
1202
|
|
|
|
|
|
|
my $new = $self->{pdf}->get_parameter("fontname") || $self->{normal_font}; |
1203
|
|
|
|
|
|
|
my $bold = 0; |
1204
|
|
|
|
|
|
|
if ($new =~ s/-(.*)$//) { |
1205
|
|
|
|
|
|
|
my $removed = $1; |
1206
|
|
|
|
|
|
|
if ($removed =~ /Bold/i) { |
1207
|
|
|
|
|
|
|
$bold = 1; |
1208
|
|
|
|
|
|
|
} |
1209
|
|
|
|
|
|
|
} |
1210
|
|
|
|
|
|
|
$self->push_font(); |
1211
|
|
|
|
|
|
|
$self->{bb}->set_font(face => $new, italic => 1, bold => $bold); |
1212
|
|
|
|
|
|
|
} |
1213
|
|
|
|
|
|
|
elsif ($name eq 'b') { |
1214
|
|
|
|
|
|
|
my $new = $self->{pdf}->get_parameter("fontname") || $self->{normal_font}; |
1215
|
|
|
|
|
|
|
my $italic = 0; |
1216
|
|
|
|
|
|
|
if ($new =~ s/-(.*)$//) { |
1217
|
|
|
|
|
|
|
my $removed = $1; |
1218
|
|
|
|
|
|
|
if ($removed =~ /(Oblique|Italic)/i) { |
1219
|
|
|
|
|
|
|
$italic = 1; |
1220
|
|
|
|
|
|
|
} |
1221
|
|
|
|
|
|
|
} |
1222
|
|
|
|
|
|
|
$self->push_font(); |
1223
|
|
|
|
|
|
|
$self->{bb}->set_font(face => $new, italic => $italic, bold => 1); |
1224
|
|
|
|
|
|
|
} |
1225
|
|
|
|
|
|
|
elsif ($name eq 'u') { |
1226
|
|
|
|
|
|
|
$self->push_font(); |
1227
|
|
|
|
|
|
|
$self->{bb}->set_decoration("underline"); |
1228
|
|
|
|
|
|
|
} |
1229
|
|
|
|
|
|
|
elsif ($name eq 'plain') { |
1230
|
|
|
|
|
|
|
$self->{chars_ok} = 1; |
1231
|
|
|
|
|
|
|
my ($x, $y) = $self->{pdf}->get_text_pos; |
1232
|
|
|
|
|
|
|
|
1233
|
|
|
|
|
|
|
my $indent = 80 * ($self->{extents}[0]{w} / $self->{extents}[-1]{w}); |
1234
|
|
|
|
|
|
|
$y += 9; |
1235
|
|
|
|
|
|
|
$self->{pdf}->set_text_pos($self->{extents}[0]{x} + $indent, $y); |
1236
|
|
|
|
|
|
|
$self->{pdf}->set_font(face => $self->{normal_font}, size => 18); |
1237
|
|
|
|
|
|
|
$self->{pdf}->print_line(""); |
1238
|
|
|
|
|
|
|
|
1239
|
|
|
|
|
|
|
($x, $y) = $self->{pdf}->get_text_pos; |
1240
|
|
|
|
|
|
|
my $align = $el->{Attributes}{"{}align"}{Value} || 'left'; |
1241
|
|
|
|
|
|
|
my $bb = $self->{pdf}->new_bounding_box( |
1242
|
|
|
|
|
|
|
x => $x, y => $y, w => ($self->{extents}[0]{w} - ($x - $self->{extents}[0]{x})), h => $y, align => $align |
1243
|
|
|
|
|
|
|
); |
1244
|
|
|
|
|
|
|
$self->{bb} = $bb; |
1245
|
|
|
|
|
|
|
} |
1246
|
|
|
|
|
|
|
elsif ($name eq 'point') { |
1247
|
|
|
|
|
|
|
$self->{chars_ok} = 1; |
1248
|
|
|
|
|
|
|
|
1249
|
|
|
|
|
|
|
my ($x, $y, $size) = $self->bullet($el); |
1250
|
|
|
|
|
|
|
|
1251
|
|
|
|
|
|
|
# warn(sprintf("creating new bb: %s => %d, %s => %d, %s => %d, %s => %d", |
1252
|
|
|
|
|
|
|
# x => $x, y => $y, w => ($self->{extents}[0]{w} - ($x - $self->{extents}[0]{x})), h => (450 - $y) |
1253
|
|
|
|
|
|
|
# )); |
1254
|
|
|
|
|
|
|
my $bb = $self->{pdf}->new_bounding_box( |
1255
|
|
|
|
|
|
|
x => $x, y => $y, w => ($self->{extents}[0]{w} - ($x - $self->{extents}[0]{x})), h => $y |
1256
|
|
|
|
|
|
|
); |
1257
|
|
|
|
|
|
|
$self->{bb} = $bb; |
1258
|
|
|
|
|
|
|
} |
1259
|
|
|
|
|
|
|
elsif ($name eq 'image') { |
1260
|
|
|
|
|
|
|
my $image = $self->{images}[$self->{image_id}]; |
1261
|
|
|
|
|
|
|
my ($scale, $handle, $href) = |
1262
|
|
|
|
|
|
|
($image->{scale}, $image->{image_ref}, $image->{href}); |
1263
|
|
|
|
|
|
|
if (defined($image->{x}) && defined($image->{y})) { |
1264
|
|
|
|
|
|
|
my $pdf = $self->{pdf}; |
1265
|
|
|
|
|
|
|
my @scale = split(/\*/,$scale); |
1266
|
|
|
|
|
|
|
my $imgw = $self->get_scale($scale[0],0,$pdf->get_value("imagewidth", $handle->img),$pdf->get_value("resx", $handle->img)); |
1267
|
|
|
|
|
|
|
my $imgh = $self->get_scale($scale[1]||$scale[0],1,$pdf->get_value("imageheight", $handle->img),$pdf->get_value("resy", $handle->img)); |
1268
|
|
|
|
|
|
|
$pdf->add_image(img => $handle, |
1269
|
|
|
|
|
|
|
x => $image->{x}, |
1270
|
|
|
|
|
|
|
y => $image->{y}, |
1271
|
|
|
|
|
|
|
w => $imgw, |
1272
|
|
|
|
|
|
|
h => $imgh |
1273
|
|
|
|
|
|
|
); |
1274
|
|
|
|
|
|
|
} |
1275
|
|
|
|
|
|
|
else { |
1276
|
|
|
|
|
|
|
$self->image($scale, $handle, $href); |
1277
|
|
|
|
|
|
|
} |
1278
|
|
|
|
|
|
|
} |
1279
|
|
|
|
|
|
|
elsif ($name eq 'source_code' || $name eq 'source-code') { |
1280
|
|
|
|
|
|
|
my $size = $el->{Attributes}{"{}fontsize"}{Value} || 14; |
1281
|
|
|
|
|
|
|
$self->{chars_ok} = 1; |
1282
|
|
|
|
|
|
|
|
1283
|
|
|
|
|
|
|
my ($x, $y) = $self->{pdf}->get_text_pos; |
1284
|
|
|
|
|
|
|
my $indent = 80 * ($self->{extents}[0]{w} / $self->{extents}[-1]{w}); |
1285
|
|
|
|
|
|
|
$self->{pdf}->set_text_pos($self->{extents}[0]{x} + $indent, $y); |
1286
|
|
|
|
|
|
|
|
1287
|
|
|
|
|
|
|
$self->push_font(); |
1288
|
|
|
|
|
|
|
$self->{pdf}->set_font(face => "Courier", size => $size); |
1289
|
|
|
|
|
|
|
($x, $y) = $self->{pdf}->get_text_pos; |
1290
|
|
|
|
|
|
|
my $bb = $self->{pdf}->new_bounding_box( |
1291
|
|
|
|
|
|
|
x => $x, y => $y, w => ($self->{extents}[0]{w} - ($x - $self->{extents}[0]{x})), h => $y, |
1292
|
|
|
|
|
|
|
wrap => 0, |
1293
|
|
|
|
|
|
|
); |
1294
|
|
|
|
|
|
|
# warn("new_bounding_box( h => $y ) => $bb\n"); |
1295
|
|
|
|
|
|
|
$self->{bb} = $bb; |
1296
|
|
|
|
|
|
|
} |
1297
|
|
|
|
|
|
|
elsif ($name eq 'color' || $name eq 'colour') { |
1298
|
|
|
|
|
|
|
my $hex_colour; |
1299
|
|
|
|
|
|
|
if (exists($el->{Attributes}{"{}name"})) { |
1300
|
|
|
|
|
|
|
my $colour = lc($el->{Attributes}{"{}name"}{Value}); |
1301
|
|
|
|
|
|
|
$hex_colour = $colours{$colour} |
1302
|
|
|
|
|
|
|
|| die "No such colour: $colour"; |
1303
|
|
|
|
|
|
|
} |
1304
|
|
|
|
|
|
|
else { |
1305
|
|
|
|
|
|
|
$hex_colour = $el->{Attributes}{"{}rgb"}{Value}; |
1306
|
|
|
|
|
|
|
} |
1307
|
|
|
|
|
|
|
if (!$hex_colour) { |
1308
|
|
|
|
|
|
|
die "Missing colour attribute: name or rgb (found: " . join(', ', keys(%{$el->{Attributes}})) .")"; |
1309
|
|
|
|
|
|
|
} |
1310
|
|
|
|
|
|
|
$hex_colour =~ s/^#//; |
1311
|
|
|
|
|
|
|
if ($hex_colour !~ /^[0-9a-fA-F]{6}$/) { |
1312
|
|
|
|
|
|
|
die "Invalid hex format: $hex_colour"; |
1313
|
|
|
|
|
|
|
} |
1314
|
|
|
|
|
|
|
|
1315
|
|
|
|
|
|
|
my ($r, $g, $b) = map { hex()/255 } ($hex_colour =~ /(..)/g); |
1316
|
|
|
|
|
|
|
|
1317
|
|
|
|
|
|
|
$self->push_font(); |
1318
|
|
|
|
|
|
|
$self->{bb}->set_color(rgb => [$r,$g,$b]); |
1319
|
|
|
|
|
|
|
} |
1320
|
|
|
|
|
|
|
elsif ($name eq 'span') { |
1321
|
|
|
|
|
|
|
$self->process_css_styles($el->{Attributes}{"{}style"}{Value}, 1); |
1322
|
|
|
|
|
|
|
} |
1323
|
|
|
|
|
|
|
elsif ($name eq 'g') { |
1324
|
|
|
|
|
|
|
$self->process_css_styles($el->{Attributes}{"{}style"}{Value}, 1); |
1325
|
|
|
|
|
|
|
} |
1326
|
|
|
|
|
|
|
elsif ($name eq 'rect') { |
1327
|
|
|
|
|
|
|
my ($x, $y, $width, $height) = ( |
1328
|
|
|
|
|
|
|
$el->{Attributes}{"{}x"}{Value}, |
1329
|
|
|
|
|
|
|
$el->{Attributes}{"{}y"}{Value}, |
1330
|
|
|
|
|
|
|
$el->{Attributes}{"{}width"}{Value}, |
1331
|
|
|
|
|
|
|
$el->{Attributes}{"{}height"}{Value}, |
1332
|
|
|
|
|
|
|
); |
1333
|
|
|
|
|
|
|
$self->{pdf}->save_graphics_state(); |
1334
|
|
|
|
|
|
|
$self->process_css_styles($el->{Attributes}{"{}style"}{Value}); |
1335
|
|
|
|
|
|
|
if ($self->{coords} eq 'svg') { |
1336
|
|
|
|
|
|
|
$self->{pdf}->rect(x => $x, y => $self->{pdf}->get_value('pageheight')-$y-$height, w => $width, h => $height); |
1337
|
|
|
|
|
|
|
} |
1338
|
|
|
|
|
|
|
else { |
1339
|
|
|
|
|
|
|
$self->{pdf}->rect(x => $x, y => $y, w => $width, h => $height); |
1340
|
|
|
|
|
|
|
} |
1341
|
|
|
|
|
|
|
|
1342
|
|
|
|
|
|
|
if ($self->{fill} && $self->{stroke}) { |
1343
|
|
|
|
|
|
|
$self->{pdf}->fill_stroke; |
1344
|
|
|
|
|
|
|
} |
1345
|
|
|
|
|
|
|
elsif ($self->{fill}) { |
1346
|
|
|
|
|
|
|
$self->{pdf}->fill; |
1347
|
|
|
|
|
|
|
} |
1348
|
|
|
|
|
|
|
elsif ($self->{stroke}) { |
1349
|
|
|
|
|
|
|
$self->{pdf}->stroke; |
1350
|
|
|
|
|
|
|
} |
1351
|
|
|
|
|
|
|
} |
1352
|
|
|
|
|
|
|
elsif ($name eq 'circle') { |
1353
|
|
|
|
|
|
|
my ($cx, $cy, $r) = ( |
1354
|
|
|
|
|
|
|
$el->{Attributes}{"{}cx"}{Value}, |
1355
|
|
|
|
|
|
|
$el->{Attributes}{"{}cy"}{Value}, |
1356
|
|
|
|
|
|
|
$el->{Attributes}{"{}r"}{Value}, |
1357
|
|
|
|
|
|
|
); |
1358
|
|
|
|
|
|
|
$self->{pdf}->save_graphics_state(); |
1359
|
|
|
|
|
|
|
$self->process_css_styles($el->{Attributes}{"{}style"}{Value}); |
1360
|
|
|
|
|
|
|
if ($self->{coords} eq 'svg') { |
1361
|
|
|
|
|
|
|
$self->{pdf}->circle(x => $cx, y => $self->{pdf}->get_value('pageheight')-$cy, r => $r); |
1362
|
|
|
|
|
|
|
} |
1363
|
|
|
|
|
|
|
else { |
1364
|
|
|
|
|
|
|
$self->{pdf}->circle(x => $cx, y => $cy, r => $r); |
1365
|
|
|
|
|
|
|
} |
1366
|
|
|
|
|
|
|
if ($self->{fill} && $self->{stroke}) { |
1367
|
|
|
|
|
|
|
$self->{pdf}->fill_stroke; |
1368
|
|
|
|
|
|
|
} |
1369
|
|
|
|
|
|
|
elsif ($self->{fill}) { |
1370
|
|
|
|
|
|
|
$self->{pdf}->fill; |
1371
|
|
|
|
|
|
|
} |
1372
|
|
|
|
|
|
|
elsif ($self->{stroke}) { |
1373
|
|
|
|
|
|
|
$self->{pdf}->stroke; |
1374
|
|
|
|
|
|
|
} |
1375
|
|
|
|
|
|
|
} |
1376
|
|
|
|
|
|
|
elsif ($name eq 'ellipse') { |
1377
|
|
|
|
|
|
|
my ($cx, $cy, $rx, $ry) = ( |
1378
|
|
|
|
|
|
|
$el->{Attributes}{"{}cx"}{Value}, |
1379
|
|
|
|
|
|
|
$el->{Attributes}{"{}cy"}{Value}, |
1380
|
|
|
|
|
|
|
$el->{Attributes}{"{}rx"}{Value}, |
1381
|
|
|
|
|
|
|
$el->{Attributes}{"{}ry"}{Value}, |
1382
|
|
|
|
|
|
|
); |
1383
|
|
|
|
|
|
|
my $r = $rx; |
1384
|
|
|
|
|
|
|
my $scale = $ry / $r; |
1385
|
|
|
|
|
|
|
$cy /= $scale; |
1386
|
|
|
|
|
|
|
# warn("ellipse at $cx, $cy, scale: $scale, r: $r\n"); |
1387
|
|
|
|
|
|
|
$self->{pdf}->save_graphics_state(); |
1388
|
|
|
|
|
|
|
$self->process_css_styles($el->{Attributes}{"{}style"}{Value}); |
1389
|
|
|
|
|
|
|
$self->{pdf}->coord_scale(1, $scale); |
1390
|
|
|
|
|
|
|
if ($self->{coords} eq 'svg') { |
1391
|
|
|
|
|
|
|
$self->{pdf}->circle(x => $cx, y => $self->{pdf}->get_value('pageheight')-$cy, r => $r); |
1392
|
|
|
|
|
|
|
} |
1393
|
|
|
|
|
|
|
else { |
1394
|
|
|
|
|
|
|
$self->{pdf}->circle(x => $cx, y => $cy, r => $r); |
1395
|
|
|
|
|
|
|
} |
1396
|
|
|
|
|
|
|
if ($self->{fill} && $self->{stroke}) { |
1397
|
|
|
|
|
|
|
$self->{pdf}->fill_stroke; |
1398
|
|
|
|
|
|
|
} |
1399
|
|
|
|
|
|
|
elsif ($self->{fill}) { |
1400
|
|
|
|
|
|
|
$self->{pdf}->fill; |
1401
|
|
|
|
|
|
|
} |
1402
|
|
|
|
|
|
|
elsif ($self->{stroke}) { |
1403
|
|
|
|
|
|
|
$self->{pdf}->stroke; |
1404
|
|
|
|
|
|
|
} |
1405
|
|
|
|
|
|
|
} |
1406
|
|
|
|
|
|
|
elsif ($name eq 'line') { |
1407
|
|
|
|
|
|
|
my ($x1, $y1, $x2, $y2) = ( |
1408
|
|
|
|
|
|
|
$el->{Attributes}{"{}x1"}{Value}, |
1409
|
|
|
|
|
|
|
$el->{Attributes}{"{}y1"}{Value}, |
1410
|
|
|
|
|
|
|
$el->{Attributes}{"{}x2"}{Value}, |
1411
|
|
|
|
|
|
|
$el->{Attributes}{"{}y2"}{Value}, |
1412
|
|
|
|
|
|
|
); |
1413
|
|
|
|
|
|
|
$self->{pdf}->save_graphics_state(); |
1414
|
|
|
|
|
|
|
$self->process_css_styles($el->{Attributes}{"{}style"}{Value}); |
1415
|
|
|
|
|
|
|
if ($self->{coords} eq 'svg') { |
1416
|
|
|
|
|
|
|
$self->{pdf}->move_to($x1, $self->{pdf}->get_value('pageheight')-$y1); |
1417
|
|
|
|
|
|
|
$self->{pdf}->line_to($x2, $self->{pdf}->get_value('pageheight')-$y2); |
1418
|
|
|
|
|
|
|
} |
1419
|
|
|
|
|
|
|
else { |
1420
|
|
|
|
|
|
|
$self->{pdf}->move_to($x1, $y1); |
1421
|
|
|
|
|
|
|
$self->{pdf}->line_to($x2, $y2); |
1422
|
|
|
|
|
|
|
} |
1423
|
|
|
|
|
|
|
if ($self->{fill} && $self->{stroke}) { |
1424
|
|
|
|
|
|
|
$self->{pdf}->fill_stroke; |
1425
|
|
|
|
|
|
|
} |
1426
|
|
|
|
|
|
|
elsif ($self->{fill}) { |
1427
|
|
|
|
|
|
|
$self->{pdf}->fill; |
1428
|
|
|
|
|
|
|
} |
1429
|
|
|
|
|
|
|
elsif ($self->{stroke}) { |
1430
|
|
|
|
|
|
|
$self->{pdf}->stroke; |
1431
|
|
|
|
|
|
|
} |
1432
|
|
|
|
|
|
|
} |
1433
|
|
|
|
|
|
|
elsif ($name eq 'text') { |
1434
|
|
|
|
|
|
|
my ($x, $y) = ( |
1435
|
|
|
|
|
|
|
$el->{Attributes}{"{}x"}{Value}, |
1436
|
|
|
|
|
|
|
$el->{Attributes}{"{}y"}{Value}, |
1437
|
|
|
|
|
|
|
); |
1438
|
|
|
|
|
|
|
$self->{pdf}->save_graphics_state(); |
1439
|
|
|
|
|
|
|
$self->push_font(); |
1440
|
|
|
|
|
|
|
$self->{pdf}->set_font( face => $self->{normal_font}, size => 14.0 ) unless $el->{Parent}->{LocalName} eq 'g'; |
1441
|
|
|
|
|
|
|
$self->process_css_styles($el->{Attributes}{"{}style"}{Value}, 1); |
1442
|
|
|
|
|
|
|
if ($self->{coords} eq 'svg') { |
1443
|
|
|
|
|
|
|
$self->{pdf}->set_text_pos($x, $self->{pdf}->get_value('pageheight')-$y); |
1444
|
|
|
|
|
|
|
} |
1445
|
|
|
|
|
|
|
else { |
1446
|
|
|
|
|
|
|
$self->{pdf}->set_text_pos($x, $y); |
1447
|
|
|
|
|
|
|
} |
1448
|
|
|
|
|
|
|
$self->{chars_ok} = 1; |
1449
|
|
|
|
|
|
|
$self->gathered_text; # reset |
1450
|
|
|
|
|
|
|
} |
1451
|
|
|
|
|
|
|
elsif ($name eq 'list') { |
1452
|
|
|
|
|
|
|
if ($el->{Attributes}{"{}ordered"}) { |
1453
|
|
|
|
|
|
|
push @{$self->{list_index}}, 1; |
1454
|
|
|
|
|
|
|
} else { |
1455
|
|
|
|
|
|
|
push @{$self->{list_index}}, 0; |
1456
|
|
|
|
|
|
|
} |
1457
|
|
|
|
|
|
|
} |
1458
|
|
|
|
|
|
|
elsif ($name eq 'path') { |
1459
|
|
|
|
|
|
|
my ($data) = ( |
1460
|
|
|
|
|
|
|
$el->{Attributes}{"{}d"}{Value}, |
1461
|
|
|
|
|
|
|
); |
1462
|
|
|
|
|
|
|
$self->{pdf}->save_graphics_state(); |
1463
|
|
|
|
|
|
|
$self->process_css_styles($el->{Attributes}{"{}style"}{Value}); |
1464
|
|
|
|
|
|
|
$self->process_path($data); |
1465
|
|
|
|
|
|
|
} |
1466
|
|
|
|
|
|
|
} |
1467
|
|
|
|
|
|
|
|
1468
|
|
|
|
|
|
|
use constant PI => atan2(1, 1) * 4.0; |
1469
|
|
|
|
|
|
|
|
1470
|
|
|
|
|
|
|
sub convert_from_svg |
1471
|
|
|
|
|
|
|
{ |
1472
|
|
|
|
|
|
|
my ($x0, $y0, $rx, $ry, $phi, $large_arc, $sweep, $x, $y) = @_; |
1473
|
|
|
|
|
|
|
my ($cx, $cy, $theta, $delta); |
1474
|
|
|
|
|
|
|
|
1475
|
|
|
|
|
|
|
# a plethora of temporary variables |
1476
|
|
|
|
|
|
|
my ( |
1477
|
|
|
|
|
|
|
$dx2, $dy2, $phi_r, $x1, $y1, |
1478
|
|
|
|
|
|
|
$rx_sq, $ry_sq, |
1479
|
|
|
|
|
|
|
$x1_sq, $y1_sq, |
1480
|
|
|
|
|
|
|
$sign, $sq, $coef, |
1481
|
|
|
|
|
|
|
$cx1, $cy1, $sx2, $sy2, |
1482
|
|
|
|
|
|
|
$p, $n, |
1483
|
|
|
|
|
|
|
$ux, $uy, $vx, $vy |
1484
|
|
|
|
|
|
|
); |
1485
|
|
|
|
|
|
|
|
1486
|
|
|
|
|
|
|
# Compute 1/2 distance between current and final point |
1487
|
|
|
|
|
|
|
$dx2 = ($x0 - $x) / 2.0; |
1488
|
|
|
|
|
|
|
$dy2 = ($y0 - $y) / 2.0; |
1489
|
|
|
|
|
|
|
|
1490
|
|
|
|
|
|
|
# Convert from degrees to radians |
1491
|
|
|
|
|
|
|
$phi %= 360; |
1492
|
|
|
|
|
|
|
$phi_r = $phi * PI / 180.0; |
1493
|
|
|
|
|
|
|
|
1494
|
|
|
|
|
|
|
# Compute (x1, y1) |
1495
|
|
|
|
|
|
|
$x1 = cos($phi_r) * $dx2 + sin($phi_r) * $dy2; |
1496
|
|
|
|
|
|
|
$y1 = -sin($phi_r) * $dx2 + cos($phi_r) * $dy2; |
1497
|
|
|
|
|
|
|
|
1498
|
|
|
|
|
|
|
# Make sure radii are large enough |
1499
|
|
|
|
|
|
|
$rx = abs($rx); $ry = abs($ry); |
1500
|
|
|
|
|
|
|
$rx_sq = $rx * $rx; |
1501
|
|
|
|
|
|
|
$ry_sq = $ry * $ry; |
1502
|
|
|
|
|
|
|
$x1_sq = $x1 * $x1; |
1503
|
|
|
|
|
|
|
$y1_sq = $y1 * $y1; |
1504
|
|
|
|
|
|
|
|
1505
|
|
|
|
|
|
|
my $radius_check = ($x1_sq / $rx_sq) + ($y1_sq / $ry_sq); |
1506
|
|
|
|
|
|
|
if ($radius_check > 1) |
1507
|
|
|
|
|
|
|
{ |
1508
|
|
|
|
|
|
|
$rx *= sqrt($radius_check); |
1509
|
|
|
|
|
|
|
$ry *= sqrt($radius_check); |
1510
|
|
|
|
|
|
|
$rx_sq = $rx * $rx; |
1511
|
|
|
|
|
|
|
$ry_sq = $ry * $ry; |
1512
|
|
|
|
|
|
|
} |
1513
|
|
|
|
|
|
|
|
1514
|
|
|
|
|
|
|
# Step 2: Compute (cx1, cy1) |
1515
|
|
|
|
|
|
|
|
1516
|
|
|
|
|
|
|
$sign = ($large_arc == $sweep) ? -1 : 1; |
1517
|
|
|
|
|
|
|
$sq = (($rx_sq * $ry_sq) - ($rx_sq * $y1_sq) - ($ry_sq * $x1_sq)) / |
1518
|
|
|
|
|
|
|
(($rx_sq * $y1_sq) + ($ry_sq * $x1_sq)); |
1519
|
|
|
|
|
|
|
$sq = ($sq < 0) ? 0 : $sq; |
1520
|
|
|
|
|
|
|
$coef = ($sign * sqrt($sq)); |
1521
|
|
|
|
|
|
|
$cx1 = round($coef * (($rx * $y1) / $ry)); |
1522
|
|
|
|
|
|
|
$cy1 = round($coef * -(($ry * $x1) / $rx)); |
1523
|
|
|
|
|
|
|
|
1524
|
|
|
|
|
|
|
# Step 3: Compute (cx, cy) from (cx1, cy1) |
1525
|
|
|
|
|
|
|
|
1526
|
|
|
|
|
|
|
$sx2 = ($x0 + $x) / 2.0; |
1527
|
|
|
|
|
|
|
$sy2 = ($y0 + $y) / 2.0; |
1528
|
|
|
|
|
|
|
|
1529
|
|
|
|
|
|
|
# Step 4: Compute angle start and angle extent |
1530
|
|
|
|
|
|
|
|
1531
|
|
|
|
|
|
|
#$ux = ($x0-$cx); |
1532
|
|
|
|
|
|
|
#$uy = ($y0-$cy); |
1533
|
|
|
|
|
|
|
#$vx = ($x-$cx); |
1534
|
|
|
|
|
|
|
#$vy = ($y-$cy); |
1535
|
|
|
|
|
|
|
|
1536
|
|
|
|
|
|
|
#print STDERR " u: ($ux,$uy) | v: ($vx,$vy)\n"; |
1537
|
|
|
|
|
|
|
|
1538
|
|
|
|
|
|
|
$ux = ($x1 - $cx1) / $rx; |
1539
|
|
|
|
|
|
|
$uy = ($y1 - $cy1) / $ry; |
1540
|
|
|
|
|
|
|
$vx = (-$x1 - $cx1) / $rx; |
1541
|
|
|
|
|
|
|
$vy = (-$y1 - $cy1) / $ry; |
1542
|
|
|
|
|
|
|
|
1543
|
|
|
|
|
|
|
$n = sqrt( ($ux * $ux) + ($uy * $uy) ); |
1544
|
|
|
|
|
|
|
$p = $ux; # 1 * ux + 0 * uy |
1545
|
|
|
|
|
|
|
$sign = ($uy > 0) ? -1 : 1; |
1546
|
|
|
|
|
|
|
|
1547
|
|
|
|
|
|
|
$theta = $sign * acos( $p / $n ); |
1548
|
|
|
|
|
|
|
$theta = $theta * 180 / PI; |
1549
|
|
|
|
|
|
|
|
1550
|
|
|
|
|
|
|
$n = sqrt(($ux * $ux + $uy * $uy) * ($vx * $vx + $vy * $vy)); |
1551
|
|
|
|
|
|
|
$p = $ux * $vx + $uy * $vy; |
1552
|
|
|
|
|
|
|
$sign = (($ux * $vy - $uy * $vx) > 0) ? -1 : 1; |
1553
|
|
|
|
|
|
|
$delta = $sign * acos( $p / $n ); |
1554
|
|
|
|
|
|
|
$delta = round($delta * 180 / PI); |
1555
|
|
|
|
|
|
|
#print STDERR " delta: $delta\n"; |
1556
|
|
|
|
|
|
|
|
1557
|
|
|
|
|
|
|
if ($large_arc == 0 && $delta >= 180) { |
1558
|
|
|
|
|
|
|
$delta -= 360; |
1559
|
|
|
|
|
|
|
} elsif ($large_arc == 0 && $delta < -180) { |
1560
|
|
|
|
|
|
|
$delta += 360; |
1561
|
|
|
|
|
|
|
} elsif ($large_arc == 1 && $delta <= 180 && $delta > 0) { |
1562
|
|
|
|
|
|
|
$delta -= 360; |
1563
|
|
|
|
|
|
|
} elsif ($large_arc == 1 && $delta > -180 && $delta <= 0) { |
1564
|
|
|
|
|
|
|
$delta += 360; |
1565
|
|
|
|
|
|
|
} |
1566
|
|
|
|
|
|
|
|
1567
|
|
|
|
|
|
|
#print STDERR " actually doing arc ($large_arc,$sweep): $cx1, $cy1 $rx,$ry, $theta, $delta, $phi\n"; |
1568
|
|
|
|
|
|
|
|
1569
|
|
|
|
|
|
|
return bezier_arc_approximation($cx1, $cy1, $rx, $ry, $theta, $delta, $phi_r, $sx2, $sy2); |
1570
|
|
|
|
|
|
|
} |
1571
|
|
|
|
|
|
|
|
1572
|
|
|
|
|
|
|
sub round { |
1573
|
|
|
|
|
|
|
return int(($_[0])*100+.5)/100; |
1574
|
|
|
|
|
|
|
} |
1575
|
|
|
|
|
|
|
|
1576
|
|
|
|
|
|
|
# Taken from http://www.faqts.com/knowledge_base/view.phtml/aid/4313 |
1577
|
|
|
|
|
|
|
sub bezier_arc_approximation { |
1578
|
|
|
|
|
|
|
my ($cx, $cy, $rx, $ry, $start, $extent, $phi_r, $rcx, $rcy) = @_; |
1579
|
|
|
|
|
|
|
|
1580
|
|
|
|
|
|
|
# The resulting coordinates are of the form (x1,y1, x2,y2, x3,y3, x4,y4) such that |
1581
|
|
|
|
|
|
|
# the curve goes from (x1, y1) to (x4, y4) with (x2, y2) and (x3, y3) as their |
1582
|
|
|
|
|
|
|
# respective Bézier control points. |
1583
|
|
|
|
|
|
|
|
1584
|
|
|
|
|
|
|
my $nfrag = int(ceil(abs($extent)/90)); |
1585
|
|
|
|
|
|
|
my $fragAngle = $extent/$nfrag; |
1586
|
|
|
|
|
|
|
|
1587
|
|
|
|
|
|
|
my $halfAng = $fragAngle * PI / 360; |
1588
|
|
|
|
|
|
|
my $kappa = 4 / 3 * (1-cos($halfAng))/sin($halfAng); |
1589
|
|
|
|
|
|
|
|
1590
|
|
|
|
|
|
|
my @ret; |
1591
|
|
|
|
|
|
|
|
1592
|
|
|
|
|
|
|
for my $i (0..($nfrag-1)) { |
1593
|
|
|
|
|
|
|
my $theta0 = ($start + $i*$fragAngle) * PI / 180; |
1594
|
|
|
|
|
|
|
my $theta1 = ($start + ($i+1)*$fragAngle) * PI / 180; |
1595
|
|
|
|
|
|
|
push @ret, [ |
1596
|
|
|
|
|
|
|
rotate($rcx,$rcy,$phi_r, $cx + $rx * cos($theta0), $cy -$ry * sin($theta0)), |
1597
|
|
|
|
|
|
|
rotate($rcx,$rcy,$phi_r, $cx + $rx * (cos($theta0) - $kappa * sin($theta0)), $cy -$ry * (sin($theta0) + $kappa * cos($theta0))), |
1598
|
|
|
|
|
|
|
rotate($rcx,$rcy,$phi_r, $cx + $rx * (cos($theta1) + $kappa * sin($theta1)), $cy -$ry * (sin($theta1) - $kappa * cos($theta1))), |
1599
|
|
|
|
|
|
|
rotate($rcx,$rcy,$phi_r, $cx + $rx * cos($theta1), $cy -$ry * sin($theta1)), |
1600
|
|
|
|
|
|
|
]; |
1601
|
|
|
|
|
|
|
} |
1602
|
|
|
|
|
|
|
|
1603
|
|
|
|
|
|
|
return @ret; |
1604
|
|
|
|
|
|
|
} |
1605
|
|
|
|
|
|
|
|
1606
|
|
|
|
|
|
|
sub rotate { |
1607
|
|
|
|
|
|
|
my ($rcx, $rcy, $phi_r, $x, $y) = @_; |
1608
|
|
|
|
|
|
|
return (($rcx + (cos($phi_r) * $x - sin($phi_r) * $y)), ($rcy + (sin($phi_r) * $x + cos($phi_r) * $y))); |
1609
|
|
|
|
|
|
|
} |
1610
|
|
|
|
|
|
|
|
1611
|
|
|
|
|
|
|
sub process_path { |
1612
|
|
|
|
|
|
|
my $self = shift; |
1613
|
|
|
|
|
|
|
my ($data) = @_; |
1614
|
|
|
|
|
|
|
$data =~ s/^\s*//; |
1615
|
|
|
|
|
|
|
my @parts = split(/([A-Za-z])/, $data); |
1616
|
|
|
|
|
|
|
# warn("got: '", join("', '", @parts), "'\n"); |
1617
|
|
|
|
|
|
|
shift(@parts); # get rid of junk at start |
1618
|
|
|
|
|
|
|
my $ytotal = $self->{pdf}->get_value('pageheight'); |
1619
|
|
|
|
|
|
|
|
1620
|
|
|
|
|
|
|
my $relative = 0; |
1621
|
|
|
|
|
|
|
|
1622
|
|
|
|
|
|
|
my ($xoffset, $yoffset) = map { $self->{pdf}->get_value($_) } qw(currentx currenty); |
1623
|
|
|
|
|
|
|
$yoffset = $ytotal-$yoffset; |
1624
|
|
|
|
|
|
|
|
1625
|
|
|
|
|
|
|
my ($last_reflect_x, $last_reflect_y, $need_to_close); |
1626
|
|
|
|
|
|
|
|
1627
|
|
|
|
|
|
|
while (@parts) { |
1628
|
|
|
|
|
|
|
my $type = shift(@parts); |
1629
|
|
|
|
|
|
|
my $rest = shift(@parts); |
1630
|
|
|
|
|
|
|
|
1631
|
|
|
|
|
|
|
if ($type eq lc($type)) { |
1632
|
|
|
|
|
|
|
# warn("using relative coordinates\n"); |
1633
|
|
|
|
|
|
|
$relative++; |
1634
|
|
|
|
|
|
|
} |
1635
|
|
|
|
|
|
|
|
1636
|
|
|
|
|
|
|
my @coords = grep { /^[\d\.\-]+$/ } split(/[^\d\.\-]+/, $rest||''); |
1637
|
|
|
|
|
|
|
# warn("got coords: '", join("', '", @coords), "'\n"); |
1638
|
|
|
|
|
|
|
|
1639
|
|
|
|
|
|
|
my ($x, $y); |
1640
|
|
|
|
|
|
|
|
1641
|
|
|
|
|
|
|
if (lc($type) eq 'm') { # moveto |
1642
|
|
|
|
|
|
|
if (@coords % 2) { |
1643
|
|
|
|
|
|
|
warn("moveto coords must be in pairs, skipping.\n"); |
1644
|
|
|
|
|
|
|
next; |
1645
|
|
|
|
|
|
|
} |
1646
|
|
|
|
|
|
|
|
1647
|
|
|
|
|
|
|
$need_to_close = 1; |
1648
|
|
|
|
|
|
|
|
1649
|
|
|
|
|
|
|
($x, $y) = splice(@coords, 0, 2); |
1650
|
|
|
|
|
|
|
if ($relative) { |
1651
|
|
|
|
|
|
|
$x += $xoffset; |
1652
|
|
|
|
|
|
|
$y += $yoffset; |
1653
|
|
|
|
|
|
|
} |
1654
|
|
|
|
|
|
|
# warn("move_to($x, $y)\n"); |
1655
|
|
|
|
|
|
|
if ($self->{coords} eq 'svg') { |
1656
|
|
|
|
|
|
|
$self->{pdf}->move_to($x, $ytotal-$y); |
1657
|
|
|
|
|
|
|
} |
1658
|
|
|
|
|
|
|
else { |
1659
|
|
|
|
|
|
|
$self->{pdf}->move_to($x, $y); |
1660
|
|
|
|
|
|
|
} |
1661
|
|
|
|
|
|
|
|
1662
|
|
|
|
|
|
|
if (@coords) { |
1663
|
|
|
|
|
|
|
# more coords == lines |
1664
|
|
|
|
|
|
|
unshift @parts, ($relative ? 'l' : 'L'), join(',', @coords); |
1665
|
|
|
|
|
|
|
next; |
1666
|
|
|
|
|
|
|
} |
1667
|
|
|
|
|
|
|
$xoffset = $x; $yoffset = $y; |
1668
|
|
|
|
|
|
|
} |
1669
|
|
|
|
|
|
|
elsif (lc($type) eq 'z') { # closepath |
1670
|
|
|
|
|
|
|
if ($self->{fill} && $self->{stroke}) { |
1671
|
|
|
|
|
|
|
$self->{pdf}->close_path_fill_stroke; |
1672
|
|
|
|
|
|
|
} |
1673
|
|
|
|
|
|
|
elsif ($self->{fill}) { |
1674
|
|
|
|
|
|
|
$self->{pdf}->close_path_fill; |
1675
|
|
|
|
|
|
|
} |
1676
|
|
|
|
|
|
|
elsif ($self->{stroke}) { |
1677
|
|
|
|
|
|
|
$self->{pdf}->close_path_stroke; |
1678
|
|
|
|
|
|
|
} |
1679
|
|
|
|
|
|
|
} |
1680
|
|
|
|
|
|
|
elsif (lc($type) eq 'l') { # lineto |
1681
|
|
|
|
|
|
|
if (@coords % 2) { |
1682
|
|
|
|
|
|
|
warn("moveto coords must be in pairs, skipping.\n"); |
1683
|
|
|
|
|
|
|
next; |
1684
|
|
|
|
|
|
|
} |
1685
|
|
|
|
|
|
|
|
1686
|
|
|
|
|
|
|
$need_to_close = 1; |
1687
|
|
|
|
|
|
|
|
1688
|
|
|
|
|
|
|
while(@coords) { |
1689
|
|
|
|
|
|
|
($x, $y) = splice(@coords, 0, 2); |
1690
|
|
|
|
|
|
|
# warn("line: $x, $y\n"); |
1691
|
|
|
|
|
|
|
if ($relative) { |
1692
|
|
|
|
|
|
|
$x += $xoffset; |
1693
|
|
|
|
|
|
|
$y += $yoffset; |
1694
|
|
|
|
|
|
|
} |
1695
|
|
|
|
|
|
|
# warn("line_to($x, $y)\n"); |
1696
|
|
|
|
|
|
|
if ($self->{coords} eq 'svg') { |
1697
|
|
|
|
|
|
|
$self->{pdf}->line_to($x, $ytotal-$y); |
1698
|
|
|
|
|
|
|
} |
1699
|
|
|
|
|
|
|
else { |
1700
|
|
|
|
|
|
|
$self->{pdf}->line_to($x, $y); |
1701
|
|
|
|
|
|
|
} |
1702
|
|
|
|
|
|
|
} |
1703
|
|
|
|
|
|
|
$xoffset = $x; $yoffset = $y; |
1704
|
|
|
|
|
|
|
} |
1705
|
|
|
|
|
|
|
elsif (lc($type) eq 'h') { # horizontal lineto |
1706
|
|
|
|
|
|
|
$need_to_close = 1; |
1707
|
|
|
|
|
|
|
|
1708
|
|
|
|
|
|
|
while (@coords) { |
1709
|
|
|
|
|
|
|
$x = shift @coords; |
1710
|
|
|
|
|
|
|
if ($relative) { |
1711
|
|
|
|
|
|
|
$x += $xoffset; |
1712
|
|
|
|
|
|
|
} |
1713
|
|
|
|
|
|
|
if ($self->{coords} eq 'svg') { |
1714
|
|
|
|
|
|
|
$self->{pdf}->line_to($x, $ytotal-$yoffset); |
1715
|
|
|
|
|
|
|
} |
1716
|
|
|
|
|
|
|
else { |
1717
|
|
|
|
|
|
|
$self->{pdf}->line_to($x, $yoffset); |
1718
|
|
|
|
|
|
|
} |
1719
|
|
|
|
|
|
|
} |
1720
|
|
|
|
|
|
|
$xoffset = $x; |
1721
|
|
|
|
|
|
|
} |
1722
|
|
|
|
|
|
|
elsif (lc($type) eq 'v') { # vertical lineto |
1723
|
|
|
|
|
|
|
$need_to_close = 1; |
1724
|
|
|
|
|
|
|
|
1725
|
|
|
|
|
|
|
while (@coords) { |
1726
|
|
|
|
|
|
|
$y = shift @coords; |
1727
|
|
|
|
|
|
|
if ($relative) { |
1728
|
|
|
|
|
|
|
$y += $yoffset; |
1729
|
|
|
|
|
|
|
} |
1730
|
|
|
|
|
|
|
if ($self->{coords} eq 'svg') { |
1731
|
|
|
|
|
|
|
$self->{pdf}->line_to($xoffset, $ytotal-$y); |
1732
|
|
|
|
|
|
|
} |
1733
|
|
|
|
|
|
|
else { |
1734
|
|
|
|
|
|
|
$self->{pdf}->line_to($xoffset, $y); |
1735
|
|
|
|
|
|
|
} |
1736
|
|
|
|
|
|
|
} |
1737
|
|
|
|
|
|
|
$yoffset = $y; |
1738
|
|
|
|
|
|
|
} |
1739
|
|
|
|
|
|
|
elsif (lc($type) eq 'c') { # curveto |
1740
|
|
|
|
|
|
|
if (@coords % 6) { |
1741
|
|
|
|
|
|
|
warn("curveto coords must be in 6's, skipping.\n"); |
1742
|
|
|
|
|
|
|
next; |
1743
|
|
|
|
|
|
|
} |
1744
|
|
|
|
|
|
|
|
1745
|
|
|
|
|
|
|
$need_to_close = 1; |
1746
|
|
|
|
|
|
|
|
1747
|
|
|
|
|
|
|
while (@coords) { |
1748
|
|
|
|
|
|
|
my ($x1, $y1, $x2, $y2, $x3, $y3) = splice(@coords, 0, 6); |
1749
|
|
|
|
|
|
|
if ($relative) { |
1750
|
|
|
|
|
|
|
for ($x1, $x2, $x3) { |
1751
|
|
|
|
|
|
|
$_ += $xoffset; |
1752
|
|
|
|
|
|
|
} |
1753
|
|
|
|
|
|
|
for ($y1, $y2, $y3) { |
1754
|
|
|
|
|
|
|
$_ += $yoffset; |
1755
|
|
|
|
|
|
|
} |
1756
|
|
|
|
|
|
|
} |
1757
|
|
|
|
|
|
|
if ($self->{coords} eq 'svg') { |
1758
|
|
|
|
|
|
|
$self->{pdf}->bezier( |
1759
|
|
|
|
|
|
|
x1 => $x1, y1 => $ytotal-$y1, |
1760
|
|
|
|
|
|
|
x2 => $x2, y2 => $ytotal-$y2, |
1761
|
|
|
|
|
|
|
x3 => $x3, y3 => $ytotal-$y3, |
1762
|
|
|
|
|
|
|
); |
1763
|
|
|
|
|
|
|
} |
1764
|
|
|
|
|
|
|
else { |
1765
|
|
|
|
|
|
|
$self->{pdf}->bezier( |
1766
|
|
|
|
|
|
|
x1 => $x1, y1 => $y1, |
1767
|
|
|
|
|
|
|
x2 => $x2, y2 => $y2, |
1768
|
|
|
|
|
|
|
x3 => $x3, y3 => $y3, |
1769
|
|
|
|
|
|
|
); |
1770
|
|
|
|
|
|
|
} |
1771
|
|
|
|
|
|
|
($last_reflect_x, $last_reflect_y) = ($x2, $y2); |
1772
|
|
|
|
|
|
|
($x, $y) = ($x3, $y3); |
1773
|
|
|
|
|
|
|
} |
1774
|
|
|
|
|
|
|
$xoffset = $x; $yoffset = $y; |
1775
|
|
|
|
|
|
|
} |
1776
|
|
|
|
|
|
|
elsif (lc($type) eq 's') { # shorthand/smooth curveto |
1777
|
|
|
|
|
|
|
if (@coords % 4) { |
1778
|
|
|
|
|
|
|
warn("shorthand curveto coords must be in 4's, skipping.\n"); |
1779
|
|
|
|
|
|
|
next; |
1780
|
|
|
|
|
|
|
} |
1781
|
|
|
|
|
|
|
|
1782
|
|
|
|
|
|
|
$need_to_close = 1; |
1783
|
|
|
|
|
|
|
|
1784
|
|
|
|
|
|
|
while (@coords) { |
1785
|
|
|
|
|
|
|
my ($x2, $y2, $x3, $y3) = splice(@coords, 0, 4); |
1786
|
|
|
|
|
|
|
if ($relative) { |
1787
|
|
|
|
|
|
|
$x2 += $xoffset; |
1788
|
|
|
|
|
|
|
$x3 += $xoffset; |
1789
|
|
|
|
|
|
|
$y2 += $yoffset; |
1790
|
|
|
|
|
|
|
$y3 += $yoffset; |
1791
|
|
|
|
|
|
|
} |
1792
|
|
|
|
|
|
|
my ($x1, $y1); |
1793
|
|
|
|
|
|
|
if (defined($last_reflect_x)) { |
1794
|
|
|
|
|
|
|
$x1 = $xoffset - ($last_reflect_x - $xoffset); |
1795
|
|
|
|
|
|
|
$y1 = $yoffset - ($last_reflect_y - $yoffset); |
1796
|
|
|
|
|
|
|
} |
1797
|
|
|
|
|
|
|
else { |
1798
|
|
|
|
|
|
|
$x1 = $xoffset; |
1799
|
|
|
|
|
|
|
$y1 = $yoffset; |
1800
|
|
|
|
|
|
|
} |
1801
|
|
|
|
|
|
|
if ($self->{coords} eq 'svg') { |
1802
|
|
|
|
|
|
|
$self->{pdf}->bezier( |
1803
|
|
|
|
|
|
|
x1 => $x1, y1 => $ytotal-$y1, |
1804
|
|
|
|
|
|
|
x2 => $x2, y2 => $ytotal-$y2, |
1805
|
|
|
|
|
|
|
x3 => $x3, y3 => $ytotal-$y3, |
1806
|
|
|
|
|
|
|
); |
1807
|
|
|
|
|
|
|
} |
1808
|
|
|
|
|
|
|
else { |
1809
|
|
|
|
|
|
|
$self->{pdf}->bezier( |
1810
|
|
|
|
|
|
|
x1 => $x1, y1 => $y1, |
1811
|
|
|
|
|
|
|
x2 => $x2, y2 => $y2, |
1812
|
|
|
|
|
|
|
x3 => $x3, y3 => $y3, |
1813
|
|
|
|
|
|
|
); |
1814
|
|
|
|
|
|
|
} |
1815
|
|
|
|
|
|
|
($last_reflect_x, $last_reflect_y) = ($x2, $y2); |
1816
|
|
|
|
|
|
|
($x, $y) = ($x3, $y3); |
1817
|
|
|
|
|
|
|
} |
1818
|
|
|
|
|
|
|
$xoffset = $x; $yoffset = $y; |
1819
|
|
|
|
|
|
|
} |
1820
|
|
|
|
|
|
|
elsif (lc($type) eq 'q') { # quadratic bezier curveto |
1821
|
|
|
|
|
|
|
if (@coords % 4) { |
1822
|
|
|
|
|
|
|
warn("quadratic curveto coords must be in 4's, skipping.\n"); |
1823
|
|
|
|
|
|
|
next; |
1824
|
|
|
|
|
|
|
} |
1825
|
|
|
|
|
|
|
|
1826
|
|
|
|
|
|
|
$need_to_close = 1; |
1827
|
|
|
|
|
|
|
|
1828
|
|
|
|
|
|
|
while (@coords) { |
1829
|
|
|
|
|
|
|
my ($x1, $y1, $x3, $y3) = splice(@coords, 0, 4); |
1830
|
|
|
|
|
|
|
if ($relative) { |
1831
|
|
|
|
|
|
|
for ($x1, $x3) { |
1832
|
|
|
|
|
|
|
$_ += $xoffset; |
1833
|
|
|
|
|
|
|
} |
1834
|
|
|
|
|
|
|
for ($y1, $y3) { |
1835
|
|
|
|
|
|
|
$_ += $yoffset; |
1836
|
|
|
|
|
|
|
} |
1837
|
|
|
|
|
|
|
} |
1838
|
|
|
|
|
|
|
my ($x2, $y2) = ($x1, $y1); |
1839
|
|
|
|
|
|
|
if ($self->{coords} eq 'svg') { |
1840
|
|
|
|
|
|
|
$self->{pdf}->bezier( |
1841
|
|
|
|
|
|
|
x1 => $x1, y1 => $ytotal-$y1, |
1842
|
|
|
|
|
|
|
x2 => $x2, y2 => $ytotal-$y2, |
1843
|
|
|
|
|
|
|
x3 => $x3, y3 => $ytotal-$y3, |
1844
|
|
|
|
|
|
|
); |
1845
|
|
|
|
|
|
|
} |
1846
|
|
|
|
|
|
|
else { |
1847
|
|
|
|
|
|
|
$self->{pdf}->bezier( |
1848
|
|
|
|
|
|
|
x1 => $x1, y1 => $y1, |
1849
|
|
|
|
|
|
|
x2 => $x2, y2 => $y2, |
1850
|
|
|
|
|
|
|
x3 => $x3, y3 => $y3, |
1851
|
|
|
|
|
|
|
); |
1852
|
|
|
|
|
|
|
} |
1853
|
|
|
|
|
|
|
($last_reflect_x, $last_reflect_y) = ($x2, $y2); |
1854
|
|
|
|
|
|
|
($x, $y) = ($x3, $y3); |
1855
|
|
|
|
|
|
|
} |
1856
|
|
|
|
|
|
|
$xoffset = $x; $yoffset = $y; |
1857
|
|
|
|
|
|
|
} |
1858
|
|
|
|
|
|
|
elsif (lc($type) eq 't') { # shorthand/smooth quadratic bezier curveto |
1859
|
|
|
|
|
|
|
if (@coords % 2) { |
1860
|
|
|
|
|
|
|
warn("shorthand quadratic curveto coords must be in pairs, skipping.\n"); |
1861
|
|
|
|
|
|
|
next; |
1862
|
|
|
|
|
|
|
} |
1863
|
|
|
|
|
|
|
|
1864
|
|
|
|
|
|
|
$need_to_close = 1; |
1865
|
|
|
|
|
|
|
|
1866
|
|
|
|
|
|
|
while (@coords) { |
1867
|
|
|
|
|
|
|
my ($x3, $y3) = splice(@coords, 0, 2); |
1868
|
|
|
|
|
|
|
if ($relative) { |
1869
|
|
|
|
|
|
|
$x3 += $xoffset; |
1870
|
|
|
|
|
|
|
$y3 += $yoffset; |
1871
|
|
|
|
|
|
|
} |
1872
|
|
|
|
|
|
|
my ($x1, $y1, $x2, $y2); |
1873
|
|
|
|
|
|
|
if (defined($last_reflect_x)) { |
1874
|
|
|
|
|
|
|
$x1 = $xoffset - ($last_reflect_x - $xoffset); |
1875
|
|
|
|
|
|
|
$y1 = $yoffset - ($last_reflect_y - $yoffset); |
1876
|
|
|
|
|
|
|
} |
1877
|
|
|
|
|
|
|
else { |
1878
|
|
|
|
|
|
|
$x1 = $xoffset; |
1879
|
|
|
|
|
|
|
$y1 = $yoffset; |
1880
|
|
|
|
|
|
|
} |
1881
|
|
|
|
|
|
|
($x2, $y2) = ($x1, $y1); |
1882
|
|
|
|
|
|
|
if ($self->{coords} eq 'svg') { |
1883
|
|
|
|
|
|
|
$self->{pdf}->bezier( |
1884
|
|
|
|
|
|
|
x1 => $x1, y1 => $ytotal-$y1, |
1885
|
|
|
|
|
|
|
x2 => $x2, y2 => $ytotal-$y2, |
1886
|
|
|
|
|
|
|
x3 => $x3, y3 => $ytotal-$y3, |
1887
|
|
|
|
|
|
|
); |
1888
|
|
|
|
|
|
|
} |
1889
|
|
|
|
|
|
|
else { |
1890
|
|
|
|
|
|
|
$self->{pdf}->bezier( |
1891
|
|
|
|
|
|
|
x1 => $x1, y1 => $y1, |
1892
|
|
|
|
|
|
|
x2 => $x2, y2 => $y2, |
1893
|
|
|
|
|
|
|
x3 => $x3, y3 => $y3, |
1894
|
|
|
|
|
|
|
); |
1895
|
|
|
|
|
|
|
} |
1896
|
|
|
|
|
|
|
($last_reflect_x, $last_reflect_y) = ($x2, $y2); |
1897
|
|
|
|
|
|
|
($x, $y) = ($x3, $y3); |
1898
|
|
|
|
|
|
|
} |
1899
|
|
|
|
|
|
|
$xoffset = $x; $yoffset = $y; |
1900
|
|
|
|
|
|
|
} |
1901
|
|
|
|
|
|
|
elsif (lc($type) eq 'a') { # elliptical arc |
1902
|
|
|
|
|
|
|
if (@coords % 7) { |
1903
|
|
|
|
|
|
|
warn("elliptical arc coords must be in 7's, skipping.\n"); |
1904
|
|
|
|
|
|
|
next; |
1905
|
|
|
|
|
|
|
} |
1906
|
|
|
|
|
|
|
|
1907
|
|
|
|
|
|
|
while (@coords) { |
1908
|
|
|
|
|
|
|
my ($rx, $ry, $rot, $large_arc_flag, $sweep_flag, $x2, $y2) = |
1909
|
|
|
|
|
|
|
splice(@coords, 0, 7); |
1910
|
|
|
|
|
|
|
|
1911
|
|
|
|
|
|
|
if ($relative) { |
1912
|
|
|
|
|
|
|
$x2 += $xoffset; |
1913
|
|
|
|
|
|
|
$y2 += $yoffset; |
1914
|
|
|
|
|
|
|
} |
1915
|
|
|
|
|
|
|
|
1916
|
|
|
|
|
|
|
# warn("arc($xoffset,$yoffset $rest)\n"); |
1917
|
|
|
|
|
|
|
|
1918
|
|
|
|
|
|
|
#print STDERR "arc from $xoffset,$yoffset to $x2,$y2 ($large_arc_flag,$sweep_flag)\n"; |
1919
|
|
|
|
|
|
|
|
1920
|
|
|
|
|
|
|
my @curves = convert_from_svg( |
1921
|
|
|
|
|
|
|
$xoffset, $yoffset, |
1922
|
|
|
|
|
|
|
$rx, $ry, |
1923
|
|
|
|
|
|
|
$rot, int($large_arc_flag), int($sweep_flag), |
1924
|
|
|
|
|
|
|
$x2, $y2); |
1925
|
|
|
|
|
|
|
|
1926
|
|
|
|
|
|
|
foreach my $curve (@curves) { |
1927
|
|
|
|
|
|
|
#$self->{pdf}->move_to($$curve[0],$ytotal-$$curve[1]); |
1928
|
|
|
|
|
|
|
#print STDERR " bezier: ($$curve[0],$$curve[1]) -> ($$curve[6],$$curve[7])\n"; |
1929
|
|
|
|
|
|
|
if ($self->{coords} eq 'svg') { |
1930
|
|
|
|
|
|
|
$self->{pdf}->bezier( |
1931
|
|
|
|
|
|
|
x1 => $$curve[2], |
1932
|
|
|
|
|
|
|
y1 => $ytotal-$$curve[3], |
1933
|
|
|
|
|
|
|
x2 => $$curve[4], |
1934
|
|
|
|
|
|
|
y2 => $ytotal-$$curve[5], |
1935
|
|
|
|
|
|
|
x3 => $$curve[6], |
1936
|
|
|
|
|
|
|
y3 => $ytotal-$$curve[7], |
1937
|
|
|
|
|
|
|
); |
1938
|
|
|
|
|
|
|
} |
1939
|
|
|
|
|
|
|
else { |
1940
|
|
|
|
|
|
|
$self->{pdf}->bezier( |
1941
|
|
|
|
|
|
|
x1 => $$curve[2], |
1942
|
|
|
|
|
|
|
y1 => $ytotal-$$curve[3], |
1943
|
|
|
|
|
|
|
x2 => $$curve[4], |
1944
|
|
|
|
|
|
|
y2 => $ytotal-$$curve[5], |
1945
|
|
|
|
|
|
|
x3 => $$curve[6], |
1946
|
|
|
|
|
|
|
y3 => $ytotal-$$curve[7], |
1947
|
|
|
|
|
|
|
); |
1948
|
|
|
|
|
|
|
} |
1949
|
|
|
|
|
|
|
} |
1950
|
|
|
|
|
|
|
|
1951
|
|
|
|
|
|
|
($x, $y) = ($x2, $y2); |
1952
|
|
|
|
|
|
|
} |
1953
|
|
|
|
|
|
|
$xoffset = $x; $yoffset = $y; |
1954
|
|
|
|
|
|
|
} |
1955
|
|
|
|
|
|
|
else { |
1956
|
|
|
|
|
|
|
warn("Unknown SVG path command: $type in $data"); |
1957
|
|
|
|
|
|
|
} |
1958
|
|
|
|
|
|
|
} |
1959
|
|
|
|
|
|
|
|
1960
|
|
|
|
|
|
|
if ($need_to_close) { |
1961
|
|
|
|
|
|
|
if ($self->{fill} && $self->{stroke}) { |
1962
|
|
|
|
|
|
|
$self->{pdf}->fill_stroke; |
1963
|
|
|
|
|
|
|
} |
1964
|
|
|
|
|
|
|
elsif ($self->{fill}) { |
1965
|
|
|
|
|
|
|
$self->{pdf}->fill; |
1966
|
|
|
|
|
|
|
} |
1967
|
|
|
|
|
|
|
elsif ($self->{stroke}) { |
1968
|
|
|
|
|
|
|
$self->{pdf}->stroke; |
1969
|
|
|
|
|
|
|
} |
1970
|
|
|
|
|
|
|
} |
1971
|
|
|
|
|
|
|
} |
1972
|
|
|
|
|
|
|
|
1973
|
|
|
|
|
|
|
sub slide_end_element { |
1974
|
|
|
|
|
|
|
my ($self, $el) = @_; |
1975
|
|
|
|
|
|
|
|
1976
|
|
|
|
|
|
|
my $name = $el->{LocalName}; |
1977
|
|
|
|
|
|
|
|
1978
|
|
|
|
|
|
|
#warn("slide_end_ $name ".join(",",map { $_."=>".$el->{Attributes}{$_}->{Value} } keys %{$el->{Attributes}})."\n"); |
1979
|
|
|
|
|
|
|
|
1980
|
|
|
|
|
|
|
$el = $self->{SlideCurrent}; |
1981
|
|
|
|
|
|
|
|
1982
|
|
|
|
|
|
|
if ($name =~ /^(point|plain|source[_-]code)$/) { |
1983
|
|
|
|
|
|
|
# finish bounding box |
1984
|
|
|
|
|
|
|
my ($x, $y) = $self->{bb}->get_text_pos; |
1985
|
|
|
|
|
|
|
$self->{bb}->finish; |
1986
|
|
|
|
|
|
|
$self->{pdf}->set_text_pos($self->{bb}->{x}, $y - 4); |
1987
|
|
|
|
|
|
|
my $bb = delete $self->{bb}; |
1988
|
|
|
|
|
|
|
$self->{pdf}->print_line(""); |
1989
|
|
|
|
|
|
|
} |
1990
|
|
|
|
|
|
|
|
1991
|
|
|
|
|
|
|
if ($name eq 'title') { |
1992
|
|
|
|
|
|
|
if ($self->{pagetype} ne 'empty') { |
1993
|
|
|
|
|
|
|
my ($x, $y) = $self->{bb}->get_text_pos; |
1994
|
|
|
|
|
|
|
$self->{bb}->finish; |
1995
|
|
|
|
|
|
|
$self->{pdf}->set_text_pos($self->{bb}->{x}, $y - 4); |
1996
|
|
|
|
|
|
|
my $bb = delete $self->{bb}; |
1997
|
|
|
|
|
|
|
$self->{pdf}->print_line(""); |
1998
|
|
|
|
|
|
|
} |
1999
|
|
|
|
|
|
|
# create bookmarks |
2000
|
|
|
|
|
|
|
if (!$self->{transitional}) { |
2001
|
|
|
|
|
|
|
my $text = $self->gathered_text; |
2002
|
|
|
|
|
|
|
$self->{values}->{'slide-title'} = $text; |
2003
|
|
|
|
|
|
|
$self->push_bookmark( |
2004
|
|
|
|
|
|
|
$self->{pdf}->add_bookmark( |
2005
|
|
|
|
|
|
|
text => $self->{text_encoder}->convert($text), |
2006
|
|
|
|
|
|
|
level => 3, |
2007
|
|
|
|
|
|
|
parent_of => $self->top_bookmark, |
2008
|
|
|
|
|
|
|
) |
2009
|
|
|
|
|
|
|
); |
2010
|
|
|
|
|
|
|
} |
2011
|
|
|
|
|
|
|
if ($self->{pagetype} ne 'empty') { |
2012
|
|
|
|
|
|
|
my ($x, $y) = $self->{pdf}->get_text_pos(); |
2013
|
|
|
|
|
|
|
$self->{pdf}->add_link( |
2014
|
|
|
|
|
|
|
link => $el->{Attributes}{"{}href"}{Value}, |
2015
|
|
|
|
|
|
|
x => 20, y => $y + $self->{pdf}->get_value('leading'), |
2016
|
|
|
|
|
|
|
w => 570, h => 24) if exists($el->{Attributes}{"{}href"}); |
2017
|
|
|
|
|
|
|
$self->{pdf}->set_text_pos(60, $y); |
2018
|
|
|
|
|
|
|
} |
2019
|
|
|
|
|
|
|
$self->{chars_ok} = 0; |
2020
|
|
|
|
|
|
|
} |
2021
|
|
|
|
|
|
|
elsif ($name eq 'slide') { |
2022
|
|
|
|
|
|
|
$self->pop_bookmark unless $self->{transitional}; |
2023
|
|
|
|
|
|
|
} |
2024
|
|
|
|
|
|
|
elsif ($name eq 'i' || $name eq 'b' || $name eq 'span' || $name eq 'g' || $name eq 'u') { |
2025
|
|
|
|
|
|
|
$self->pop_font(); |
2026
|
|
|
|
|
|
|
} |
2027
|
|
|
|
|
|
|
elsif ($name eq 'point') { |
2028
|
|
|
|
|
|
|
$self->{chars_ok} = 0; |
2029
|
|
|
|
|
|
|
my ($x, $y) = $self->{pdf}->get_text_pos(); |
2030
|
|
|
|
|
|
|
$self->{pdf}->add_link( |
2031
|
|
|
|
|
|
|
link => $el->{Attributes}{"{}href"}{Value}, |
2032
|
|
|
|
|
|
|
x => 20, y => $y + $self->{pdf}->get_value('leading'), |
2033
|
|
|
|
|
|
|
w => 570, h => 24) if exists($el->{Attributes}{"{}href"}); |
2034
|
|
|
|
|
|
|
} |
2035
|
|
|
|
|
|
|
elsif ($name eq 'plain') { |
2036
|
|
|
|
|
|
|
$self->{chars_ok} = 0; |
2037
|
|
|
|
|
|
|
} |
2038
|
|
|
|
|
|
|
elsif ($name eq 'source_code' || $name eq 'source-code') { |
2039
|
|
|
|
|
|
|
$self->{chars_ok} = 0; |
2040
|
|
|
|
|
|
|
$self->pop_font(); |
2041
|
|
|
|
|
|
|
} |
2042
|
|
|
|
|
|
|
elsif ($name eq 'image') { |
2043
|
|
|
|
|
|
|
$self->{image_id}++; |
2044
|
|
|
|
|
|
|
} |
2045
|
|
|
|
|
|
|
elsif ($name eq 'colour' || $name eq 'color') { |
2046
|
|
|
|
|
|
|
$self->pop_font(); |
2047
|
|
|
|
|
|
|
} |
2048
|
|
|
|
|
|
|
elsif ($name eq 'table') { |
2049
|
|
|
|
|
|
|
shift @{$self->{extents}}; |
2050
|
|
|
|
|
|
|
} |
2051
|
|
|
|
|
|
|
elsif ($name eq 'box') { |
2052
|
|
|
|
|
|
|
shift @{$self->{extents}}; |
2053
|
|
|
|
|
|
|
$self->{pdf}->set_text_pos(@{$self->{boxlast}}); |
2054
|
|
|
|
|
|
|
if (!$self->{transitional}) { |
2055
|
|
|
|
|
|
|
if ($self->{boxtransition}[0]) { |
2056
|
|
|
|
|
|
|
shift @{$self->{default_transition}}; |
2057
|
|
|
|
|
|
|
} |
2058
|
|
|
|
|
|
|
shift @{$self->{boxtransition}}; |
2059
|
|
|
|
|
|
|
} |
2060
|
|
|
|
|
|
|
} |
2061
|
|
|
|
|
|
|
elsif ($name eq 'row') { |
2062
|
|
|
|
|
|
|
$self->{row_number}++; |
2063
|
|
|
|
|
|
|
$self->{pdf}->set_text_pos($self->{row_start}[0], $self->{max_height}); |
2064
|
|
|
|
|
|
|
} |
2065
|
|
|
|
|
|
|
elsif ($name eq 'col') { |
2066
|
|
|
|
|
|
|
$self->{col_number}++; |
2067
|
|
|
|
|
|
|
$self->{pdf}->print_line(""); |
2068
|
|
|
|
|
|
|
my ($x, $y) = $self->{pdf}->get_text_pos; |
2069
|
|
|
|
|
|
|
# warn("end-col: $y < $self->{max_height} ???"); |
2070
|
|
|
|
|
|
|
$self->{max_height} = $y if $y < $self->{max_height}; |
2071
|
|
|
|
|
|
|
} |
2072
|
|
|
|
|
|
|
elsif ($name eq 'text') { |
2073
|
|
|
|
|
|
|
my $text = $self->gathered_text; |
2074
|
|
|
|
|
|
|
$self->{chars_ok} = 0; |
2075
|
|
|
|
|
|
|
$self->{pdf}->print($text); |
2076
|
|
|
|
|
|
|
$self->{pdf}->restore_graphics_state(); |
2077
|
|
|
|
|
|
|
$self->pop_font(); |
2078
|
|
|
|
|
|
|
$self->pop_font(); |
2079
|
|
|
|
|
|
|
} |
2080
|
|
|
|
|
|
|
elsif ($name eq 'list') { |
2081
|
|
|
|
|
|
|
pop @{$self->{list_index}}; |
2082
|
|
|
|
|
|
|
} |
2083
|
|
|
|
|
|
|
elsif ($name =~ /^(circle|ellipse|line|rect|path)$/) { |
2084
|
|
|
|
|
|
|
$self->{pdf}->restore_graphics_state(); |
2085
|
|
|
|
|
|
|
$self->pop_font(); |
2086
|
|
|
|
|
|
|
} |
2087
|
|
|
|
|
|
|
|
2088
|
|
|
|
|
|
|
if ($name =~ m/^(table|list|image|source[-_]code)$/ && $el->{Attributes}{'{}caption'}) { |
2089
|
|
|
|
|
|
|
$self->push_font(); |
2090
|
|
|
|
|
|
|
$self->{pdf}->set_font(face => $self->{normal_font}, italic => 1, size => 14); |
2091
|
|
|
|
|
|
|
my ($x, $y) = $self->{pdf}->get_text_pos; |
2092
|
|
|
|
|
|
|
my $indent = 80 * ($self->{extents}[0]{w} / $self->{extents}[-1]{w}); |
2093
|
|
|
|
|
|
|
$self->{pdf}->set_text_pos($self->{bb}?$self->{bb}->{x}:$self->{extents}[0]{x}+$indent, $y); |
2094
|
|
|
|
|
|
|
$self->{pdf}->print_line(""); |
2095
|
|
|
|
|
|
|
$self->{pdf}->print($el->{Attributes}{'{}caption'}{Value}); |
2096
|
|
|
|
|
|
|
$self->pop_font(); |
2097
|
|
|
|
|
|
|
} |
2098
|
|
|
|
|
|
|
|
2099
|
|
|
|
|
|
|
|
2100
|
|
|
|
|
|
|
$self->{SlideCurrent} = $el->{Parent}; |
2101
|
|
|
|
|
|
|
} |
2102
|
|
|
|
|
|
|
|
2103
|
|
|
|
|
|
|
sub slide_characters { |
2104
|
|
|
|
|
|
|
my ($self, $chars) = @_; |
2105
|
|
|
|
|
|
|
|
2106
|
|
|
|
|
|
|
return unless $self->{chars_ok}; |
2107
|
|
|
|
|
|
|
|
2108
|
|
|
|
|
|
|
$self->{gathered_text} .= $chars->{Data}; |
2109
|
|
|
|
|
|
|
|
2110
|
|
|
|
|
|
|
my $name = $self->{SlideCurrent}->{LocalName}; |
2111
|
|
|
|
|
|
|
my $text = $chars->{Data}; |
2112
|
|
|
|
|
|
|
return unless $text && $self->{bb}; |
2113
|
|
|
|
|
|
|
my $leftover = $self->{bb}->print($self->{text_encoder}->convert($text)); |
2114
|
|
|
|
|
|
|
if (defined $leftover && $leftover =~ m/\S/) { |
2115
|
|
|
|
|
|
|
die "Could not print: $leftover\nof: $text\n"; |
2116
|
|
|
|
|
|
|
} |
2117
|
|
|
|
|
|
|
} |
2118
|
|
|
|
|
|
|
|
2119
|
|
|
|
|
|
|
1; |
2120
|
|
|
|
|
|
|
__END__ |