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   982 use base 'PDF::Builder::Resource::Font';
  8         15  
  8         3291  
4              
5 8     8   55 use strict;
  8         15  
  8         149  
6 8     8   36 use warnings;
  8         16  
  8         341  
7              
8             our $VERSION = '3.024'; # VERSION
9             our $LAST_UPDATE = '3.024'; # manually update whenever code is changed
10              
11 8     8   45 use File::Basename;
  8         15  
  8         528  
12              
13 8     8   43 use PDF::Builder::Util;
  8         16  
  8         934  
14 8     8   53 use PDF::Builder::Basic::PDF::Utils;
  8         24  
  8         10083  
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   89 my $fname = shift;
133              
134             ## return %{$fonts->{$fname}} if defined $fonts->{$fname};
135 52         3962 eval "require PDF::Builder::Resource::Font::CoreFont::$fname; "; ## no critic
136 52 50       271 unless($@) {
137 52         166 my $class = "PDF::Builder::Resource::Font::CoreFont::$fname";
138 52         365 $fonts->{$fname} = deep_copy($class->data());
139 52   100     7127 $fonts->{$fname}->{'uni'} ||= [];
140 52         198 foreach my $n (0..255) {
141 13312 100       27608 $fonts->{$fname}->{'uni'}->[$n] = uniByName($fonts->{$fname}->{'char'}->[$n]) unless defined $fonts->{$fname}->{'uni'}->[$n];
142             }
143 52         108 return %{$fonts->{$fname}};
  52         734  
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 159826 my $this = shift;
155              
156 148040 100       179059 if (not ref $this) {
    100          
    50          
    0          
157 147600         272103 return $this;
158             } elsif (ref $this eq "ARRAY") {
159 289         569 return [map &deep_copy($_), @$this]; ## no critic
160             } elsif (ref $this eq "HASH") {
161 151         16412 return +{map { $_ => &deep_copy($this->{$_}) } keys %$this};
  133108         172857  
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 133 my ($class, $pdf, $name, @opts) = @_;
172              
173 52         91 my ($self,$data);
174 52         89 my %opts = ();
175 52         126 my $is_standard = is_standard($name);
176              
177 52 50       1136 if (-f $name) {
178 0         0 eval "require '$name'; "; ## no critic
179 0         0 $name = basename($name,'.pm');
180             }
181 52         188 my $lookname = lc($name);
182 52         176 $lookname =~ s/[^a-z0-9]+//gi;
183 52 50       227 %opts = @opts if (scalar @opts)%2 == 0;
184             # copy dashed name options to preferred undashed names
185 52 50 33     171 if (defined $opts{'-encode'} && !defined $opts{'encode'}) { $opts{'encode'} = delete($opts{'-encode'}); }
  0         0  
186 52 50 33     147 if (defined $opts{'-metrics'} && !defined $opts{'metrics'}) { $opts{'metrics'} = delete($opts{'-metrics'}); }
  0         0  
187 52 50 33     145 if (defined $opts{'-dokern'} && !defined $opts{'dokern'}) { $opts{'dokern'} = delete($opts{'-dokern'}); }
  0         0  
188 52 50 33     128 if (defined $opts{'-pdfname'} && !defined $opts{'pdfname'}) { $opts{'pdfname'} = delete($opts{'-pdfname'}); }
  0         0  
189              
190 52   100     265 $opts{'encode'} //= 'latin1';
191 52 50       159 $lookname = $alias->{$lookname} if $alias->{$lookname};
192              
193 52 50       132 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       110 unless (defined $opts{'metrics'}) {
201 52         132 $data = {_look_for_font($lookname)};
202             } else {
203 0         0 $data = {%{$opts{'metrics'}}};
  0         0  
204             }
205             }
206              
207 52 50       256 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       132 $class = ref $class if ref $class;
223             # $self = $class->SUPER::new($pdf, $data->{'apiname'}.pdfkey().'~'.time());
224 52         218 $self = $class->SUPER::new($pdf, $data->{'apiname'}.pdfkey());
225 52 50       128 $pdf->new_obj($self) unless $self->is_obj($pdf);
226 52         120 $self->{' data'} = $data;
227 52 50       135 $self->{'-dokern'} = 1 if $opts{'dokern'};
228              
229 52         164 $self->{'Subtype'} = PDFName($self->data()->{'type'});
230 52         214 $self->{'BaseFont'} = PDFName($self->fontname());
231 52 50       148 if ($opts{'pdfname'}) {
232 0         0 $self->name($opts{'pdfname'});
233             }
234              
235 52 100       158 unless ($self->data()->{'iscore'}) {
236 15         37 $self->{'FontDescriptor'} = $self->descrByData();
237             }
238              
239 52 50       274 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         252 $self->encodeByData($opts{'encode'});
244              
245             # The standard non-symbolic fonts use unmodified WinAnsiEncoding.
246 52 50 100     187 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         243 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 52     52 1 82 my $name = pop();
267              
268 52 50       139 return 1 if $name eq 'Courier';
269 52 50       110 return 1 if $name eq 'Courier-Bold';
270 52 50       121 return 1 if $name eq 'Courier-BoldOblique';
271 52 50       108 return 1 if $name eq 'Courier-Oblique';
272 52 100       108 return 1 if $name eq 'Helvetica';
273 32 50       63 return 1 if $name eq 'Helvetica-Bold';
274 32 50       55 return 1 if $name eq 'Helvetica-BoldOblique';
275 32 50       55 return 1 if $name eq 'Helvetica-Oblique';
276 32 50       50 return 1 if $name eq 'Symbol';
277 32 100       58 return 1 if $name eq 'Times-Bold';
278 31 50       54 return 1 if $name eq 'Times-BoldItalic';
279 31 50       59 return 1 if $name eq 'Times-Italic';
280 31 100       65 return 1 if $name eq 'Times-Roman';
281 30 100       49 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 29         47 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   104 $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         90 $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         232 $fonts = { };
422              
423             }
424              
425             1;
426              
427             __END__