File Coverage

blib/lib/PDF/Builder/Resource/Font/CoreFont.pm
Criterion Covered Total %
statement 85 110 77.2
branch 44 76 57.8
condition 13 22 59.0
subroutine 11 12 91.6
pod 3 4 75.0
total 156 224 69.6


line stmt bran cond sub pod time code
1             package PDF::Builder::Resource::Font::CoreFont;
2              
3 8     8   1140 use base 'PDF::Builder::Resource::Font';
  8         34  
  8         3981  
4              
5 8     8   64 use strict;
  8         34  
  8         175  
6 8     8   44 use warnings;
  8         18  
  8         418  
7              
8             our $VERSION = '3.025'; # VERSION
9             our $LAST_UPDATE = '3.024'; # manually update whenever code is changed
10              
11 8     8   66 use File::Basename;
  8         18  
  8         604  
12              
13 8     8   52 use PDF::Builder::Util;
  8         19  
  8         1128  
14 8     8   65 use PDF::Builder::Basic::PDF::Utils;
  8         25  
  8         12779  
15              
16             our $fonts;
17             our $alias;
18             our $subs;
19              
20             =head1 NAME
21              
22             PDF::Builder::Resource::Font::CoreFont - Module for using the 14 standard PDF built-in Fonts (plus 15 Windows Fonts).
23              
24             =head1 SYNOPSIS
25              
26             #
27             use PDF::Builder;
28             #
29             my $pdf = PDF::Builder->new();
30             my $cft = $pdf->font('Times-Roman');
31             #my $cft = $pdf->corefont('Times-Roman');
32             #
33             my $page = $pdf->page();
34             my $text = $page->text();
35             $text->font($cft, 20);
36             $text->translate(200, 700);
37             $text->text("Hello, World!");
38              
39             =head1 METHODS
40              
41             =over
42              
43             =item $font = PDF::Builder::Resource::Font::CoreFont->new($pdf, $fontname, %options)
44              
45             Returns a corefont object.
46              
47             Valid %options are:
48              
49             =over
50              
51             I
52             ... changes the encoding of the font from its default.
53             See I for the supported values. B only single byte
54             encodings are permitted. Multibyte encodings such as 'utf8' are forbidden.
55              
56             I ... changes the reference-name of the font from its default.
57             The reference-name is normally generated automatically and can be
58             retrieved via C<$pdfname=$font->name()>.
59              
60             =back
61              
62             =back
63              
64             =head2 Supported typefaces
65              
66             B
67              
68             =over
69              
70             =over
71              
72             =item * helvetica helveticaoblique helveticabold helvetiaboldoblique
73              
74             May have Arial substituted on some systems (e.g., Windows)
75              
76             =item * courier courieroblique courierbold courierboldoblique
77              
78             Fixed pitch, may have Courier New substituted on some systems (e.g., Windows)
79              
80             =item * timesroman timesitalic timesbold timesbolditalic
81              
82             May have Times New Roman substituted on some systems (e.g., Windows)
83              
84             =item * symbol zapfdingbats
85              
86             =back
87              
88             =back
89              
90             B
91              
92             =over
93              
94             =over
95              
96             =item * georgia georgiaitalic georgiabold georgiabolditalic
97              
98             =item * verdana verdanaitalic verdanabold verdanabolditalic
99              
100             =item * trebuchet trebuchetitalic trebuchetbold trebuchetbolditalic
101              
102             =item * bankgothic bankgothicitalic bankgothicbold bankgothicitalic
103              
104             Free versions of Bank Gothic are often only medium weight.
105              
106             =item * webdings wingdings
107              
108             =back
109              
110             =back
111              
112             Keep in mind that only font metrics (widths) are provided with PDF::Builder;
113             the fonts themselves are provided by the reader's machine (often packaged
114             with the operating system, or obtained separately by the user). To use a
115             specific font may require you to obtain one or more files from some source.
116              
117             If a font (typeface and variant) is not available on a given reader's
118             machine, a substitution I be automatically made. For example, Helvetica is
119             usually not shipped with Windows machines, and Arial might be substituted.
120             For most characters, the glyph widths will be the same, but this can not be
121             guaranteed!
122              
123             PDF::Builder currently uses the [typeface].pm files to map glyph names to
124             code points (single byte encodings only) and to look up the glyph widths for
125             character positioning. There is no guarantee that a given font file includes
126             all the desired glyphs, nor that the widths will be absolutely the same, even
127             in different releases of the same font.
128              
129             =cut
130              
131             sub _look_for_font {
132 52     52   143 my $fname = shift;
133              
134             ## return %{$fonts->{$fname}} if defined $fonts->{$fname};
135 52         5670 eval "require PDF::Builder::Resource::Font::CoreFont::$fname; "; ## no critic
136 52 50       311 unless($@) {
137 52         223 my $class = "PDF::Builder::Resource::Font::CoreFont::$fname";
138 52         447 $fonts->{$fname} = deep_copy($class->data());
139 52   100     8547 $fonts->{$fname}->{'uni'} ||= [];
140 52         261 foreach my $n (0..255) {
141 13312 100       34667 $fonts->{$fname}->{'uni'}->[$n] = uniByName($fonts->{$fname}->{'char'}->[$n]) unless defined $fonts->{$fname}->{'uni'}->[$n];
142             }
143 52         184 return %{$fonts->{$fname}};
  52         872  
144             } else {
145 0         0 die "requested core font '$fname' not installed ";
146             }
147             }
148              
149             #
150             # Deep copy something, thanks to Randal L. Schwartz
151             # Changed to deal w/ CODE refs, in which case it doesn't try to deep copy
152             #
153             sub deep_copy {
154 148040     148040 0 197462 my $this = shift;
155              
156 148040 100       223219 if (not ref $this) {
    100          
    50          
    0          
157 147600         341152 return $this;
158             } elsif (ref $this eq "ARRAY") {
159 289         698 return [map &deep_copy($_), @$this]; ## no critic
160             } elsif (ref $this eq "HASH") {
161 151         19131 return +{map { $_ => &deep_copy($this->{$_}) } keys %$this};
  133108         212218  
162             } elsif (ref $this eq "CODE") {
163             # Can't deep copy code refs
164 0         0 return $this;
165             } else {
166 0         0 die "what type is $_?";
167             }
168             }
169              
170             sub new {
171 52     52 1 182 my ($class, $pdf, $name, @opts) = @_;
172              
173 52         102 my ($self,$data);
174 52         107 my %opts = ();
175 52         134 my $is_standard = is_standard($name);
176              
177 52 50       1745 if (-f $name) {
178 0         0 eval "require '$name'; "; ## no critic
179 0         0 $name = basename($name,'.pm');
180             }
181 52         226 my $lookname = lc($name);
182 52         206 $lookname =~ s/[^a-z0-9]+//gi;
183 52 50       253 %opts = @opts if (scalar @opts)%2 == 0;
184             # copy dashed name options to preferred undashed names
185 52 50 33     225 if (defined $opts{'-encode'} && !defined $opts{'encode'}) { $opts{'encode'} = delete($opts{'-encode'}); }
  0         0  
186 52 50 33     189 if (defined $opts{'-metrics'} && !defined $opts{'metrics'}) { $opts{'metrics'} = delete($opts{'-metrics'}); }
  0         0  
187 52 50 33     188 if (defined $opts{'-dokern'} && !defined $opts{'dokern'}) { $opts{'dokern'} = delete($opts{'-dokern'}); }
  0         0  
188 52 50 33     171 if (defined $opts{'-pdfname'} && !defined $opts{'pdfname'}) { $opts{'pdfname'} = delete($opts{'-pdfname'}); }
  0         0  
189              
190 52   100     309 $opts{'encode'} //= 'latin1';
191 52 50       222 $lookname = $alias->{$lookname} if $alias->{$lookname};
192              
193 52 50       187 if (defined $subs->{$lookname}) {
194 0         0 $data = {_look_for_font($subs->{$lookname}->{'-alias'})};
195 0         0 foreach my $k (keys %{$subs->{$lookname}}) {
  0         0  
196 0 0       0 next if $k =~ /^\-/;
197 0         0 $data->{$k} = $subs->{$lookname}->{$k};
198             }
199             } else {
200 52 50       143 unless (defined $opts{'metrics'}) {
201 52         206 $data = {_look_for_font($lookname)};
202             } else {
203 0         0 $data = {%{$opts{'metrics'}}};
  0         0  
204             }
205             }
206              
207 52 50       309 die "Undefined Core Font '$name($lookname)'" unless $data->{'fontname'};
208              
209             # we have data now here so we need to check if
210             # there is a -ttfile or -afmfile/-pfmfile/-pfbfile
211             # and proxy the call to the relevant modules
212             #
213             #if (defined $data->{'-ttfile'} && $data->{'-ttfile'} = _look_for_fontfile($data->{'-ttfile'})) {
214             # return PDF::Builder::Resource::CIDFont::TrueType->new($pdf, $data->{'-ttfile'}, @opts);
215             #} elsif (defined $data->{'-pfbfile'} && $data->{'-pfbfile'} = _look_for_fontfile($data->{'-pfbfile'})) {
216             # $data->{'-afmfile'} = _look_for_fontfile($data->{'-afmfile'});
217             # return PDF::Builder::Resource::Font::Postscript->new($pdf, $data->{'-pfbfile'}, $data->{'-afmfile'}, @opts));
218             #} elsif (defined $data->{'-gfx'}) { # to be written and tested in 'Maki' first!
219             # return PDF::Builder::Resource::Font::gFont->new($pdf, $data, @opts);
220             #}
221              
222 52 50       194 $class = ref $class if ref $class;
223             # $self = $class->SUPER::new($pdf, $data->{'apiname'}.pdfkey().'~'.time());
224 52         296 $self = $class->SUPER::new($pdf, $data->{'apiname'}.pdfkey());
225 52 50       212 $pdf->new_obj($self) unless $self->is_obj($pdf);
226 52         178 $self->{' data'} = $data;
227 52 50       186 $self->{'-dokern'} = 1 if $opts{'dokern'};
228              
229 52         239 $self->{'Subtype'} = PDFName($self->data()->{'type'});
230 52         275 $self->{'BaseFont'} = PDFName($self->fontname());
231 52 50       207 if ($opts{'pdfname'}) {
232 0         0 $self->name($opts{'pdfname'});
233             }
234              
235 52 100       182 unless ($self->data()->{'iscore'}) {
236 15         57 $self->{'FontDescriptor'} = $self->descrByData();
237             }
238              
239 52 50       374 if ($opts{'encode'} =~ m/^utf/i) {
240 0         0 die "Invalid multibyte encoding for corefont: $opts{'encode'}\n";
241             # probably more encodings to check
242             }
243 52         318 $self->encodeByData($opts{'encode'});
244              
245             # The standard non-symbolic fonts use unmodified WinAnsiEncoding.
246 52 50 100     274 if ($is_standard and not $self->issymbol() and not $opts{'encode'}) {
      66        
247 0         0 $self->{'Encoding'} = PDFName('WinAnsiEncoding');
248 0         0 delete $self->{'FirstChar'};
249 0         0 delete $self->{'LastChar'};
250 0         0 delete $self->{'Widths'};
251             }
252              
253 52         317 return $self;
254             }
255              
256             =over
257              
258             =item $bool = $class->is_standard($name)
259              
260             Returns true if C<$name> is an exact, case-sensitive match for one of the
261             standard font names shown above.
262              
263             =cut
264              
265             sub is_standard {
266 104     104 1 207 my $name = pop();
267              
268 104 50       293 return 1 if $name eq 'Courier';
269 104 50       236 return 1 if $name eq 'Courier-Bold';
270 104 50       232 return 1 if $name eq 'Courier-BoldOblique';
271 104 50       239 return 1 if $name eq 'Courier-Oblique';
272 104 100       308 return 1 if $name eq 'Helvetica';
273 64 50       164 return 1 if $name eq 'Helvetica-Bold';
274 64 50       137 return 1 if $name eq 'Helvetica-BoldOblique';
275 64 50       144 return 1 if $name eq 'Helvetica-Oblique';
276 64 50       143 return 1 if $name eq 'Symbol';
277 64 100       148 return 1 if $name eq 'Times-Bold';
278 62 50       138 return 1 if $name eq 'Times-BoldItalic';
279 62 50       136 return 1 if $name eq 'Times-Italic';
280 62 100       128 return 1 if $name eq 'Times-Roman';
281 60 100       135 return 1 if $name eq 'ZapfDingbats';
282             # TBD what about the 15 Windows fonts?
283             # BankGothic
284             # Georgia (plus italic, bold, bold-italic)
285             # Trebuchet (plus italic, bold, bold-italic)
286             # Verdana (plus italic, bold, bold-italic)
287             # Webdings, Wingdings
288 58         160 return;
289             }
290              
291             =item PDF::Builder::Resource::Font::CoreFont->loadallfonts()
292              
293             "Requires in" all fonts available as corefonts.
294              
295             =cut
296              
297             sub loadallfonts {
298 0     0 1   foreach my $f (qw[
299             bankgothic
300             courier courierbold courierboldoblique courieroblique
301             georgia georgiabold georgiabolditalic georgiaitalic
302             helveticaboldoblique helveticaoblique helveticabold helvetica
303             symbol
304             timesbolditalic timesitalic timesroman timesbold
305             verdana verdanabold verdanabolditalic verdanaitalic
306             trebuchet trebuchetbold trebuchetbolditalic trebuchetitalic
307             webdings
308             wingdings
309             zapfdingbats
310             ]) {
311 0           _look_for_font($f);
312             }
313 0           return;
314             }
315              
316             # not yet supported
317             # andalemono
318             # arialrounded
319             # impact
320             # ozhandicraft
321              
322             BEGIN
323             {
324              
325 8     8   164 $alias = {
326             ## Windows Fonts with Type1 equivalence
327             'arial' => 'helvetica',
328             'arialitalic' => 'helveticaoblique',
329             'arialbold' => 'helveticabold',
330             'arialbolditalic' => 'helveticaboldoblique',
331              
332             'times' => 'timesroman',
333             'timesnewromanbolditalic' => 'timesbolditalic',
334             'timesnewromanbold' => 'timesbold',
335             'timesnewromanitalic' => 'timesitalic',
336             'timesnewroman' => 'timesroman',
337              
338             'couriernewbolditalic' => 'courierboldoblique',
339             'couriernewbold' => 'courierbold',
340             'couriernewitalic' => 'courieroblique',
341             'couriernew' => 'courier',
342             };
343              
344 8         73 $subs = {
345             'bankgothicbold' => {
346             'apiname' => 'Bg2',
347             '-alias' => 'bankgothic',
348             'fontname' => 'BankGothicMediumBT,Bold',
349             'flags' => 32+262144,
350             },
351             'bankgothicbolditalic' => {
352             'apiname' => 'Bg3',
353             '-alias' => 'bankgothic',
354             'fontname' => 'BankGothicMediumBT,BoldItalic',
355             'italicangle' => -15,
356             'flags' => 96+262144,
357             },
358             'bankgothicitalic' => {
359             'apiname' => 'Bg4',
360             '-alias' => 'bankgothic',
361             'fontname' => 'BankGothicMediumBT,Italic',
362             'italicangle' => -15,
363             'flags' => 96,
364             },
365             # 'impactitalic' => {
366             # 'apiname' => 'Imp2',
367             # '-alias' => 'impact',
368             # 'fontname' => 'Impact,Italic',
369             # 'italicangle' => -12,
370             # },
371             # 'ozhandicraftbold' => {
372             # 'apiname' => 'Oz2',
373             # '-alias' => 'ozhandicraft',
374             # 'fontname' => 'OzHandicraftBT,Bold',
375             # 'italicangle' => 0,
376             # 'flags' => 32+262144,
377             # },
378             # 'ozhandicraftitalic' => {
379             # 'apiname' => 'Oz3',
380             # '-alias' => 'ozhandicraft',
381             # 'fontname' => 'OzHandicraftBT,Italic',
382             # 'italicangle' => -15,
383             # 'flags' => 96,
384             # },
385             # 'ozhandicraftbolditalic' => {
386             # 'apiname' => 'Oz4',
387             # '-alias' => 'ozhandicraft',
388             # 'fontname' => 'OzHandicraftBT,BoldItalic',
389             # 'italicangle' => -15,
390             # 'flags' => 96+262144,
391             # },
392             # 'arialroundeditalic' => {
393             # 'apiname' => 'ArRo2',
394             # '-alias' => 'arialrounded',
395             # 'fontname' => 'ArialRoundedMTBold,Italic',
396             # 'italicangle' => -15,
397             # 'flags' => 96+262144,
398             # },
399             # 'arialitalic' => {
400             # 'apiname' => 'Ar2',
401             # '-alias' => 'arial',
402             # 'fontname' => 'Arial,Italic',
403             # 'italicangle' => -15,
404             # 'flags' => 96,
405             # },
406             # 'arialbolditalic' => {
407             # 'apiname' => 'Ar3',
408             # '-alias' => 'arial',
409             # 'fontname' => 'Arial,BoldItalic',
410             # 'italicangle' => -15,
411             # 'flags' => 96+262144,
412             # },
413             # 'arialbold' => {
414             # 'apiname' => 'Ar4',
415             # '-alias' => 'arial',
416             # 'fontname' => 'Arial,Bold',
417             # 'flags' => 32+262144,
418             # },
419             };
420              
421 8         276 $fonts = { };
422              
423             }
424              
425             1;
426              
427             __END__