File Coverage

blib/lib/PDF/API2/Resource/Font/CoreFont.pm
Criterion Covered Total %
statement 72 83 86.7
branch 22 34 64.7
condition 8 8 100.0
subroutine 14 14 100.0
pod 3 3 100.0
total 119 142 83.8


line stmt bran cond sub pod time code
1             package PDF::API2::Resource::Font::CoreFont;
2              
3 9     9   1493 use base 'PDF::API2::Resource::Font';
  9         25  
  9         5146  
4              
5 9     9   91 use strict;
  9         38  
  9         264  
6 9     9   40 use warnings;
  9         18  
  9         666  
7              
8             our $VERSION = '2.048'; # VERSION
9              
10 9     9   78 use File::Basename;
  9         19  
  9         892  
11 9     9   60 use List::Util qw(any);
  9         18  
  9         558  
12 9     9   44 use PDF::API2::Util;
  9         15  
  9         1193  
13 9     9   71 use PDF::API2::Basic::PDF::Utils;
  9         17  
  9         3434  
14              
15             my @standard_fonts = qw(
16             Courier Courier-Bold Courier-BoldOblique Courier-Oblique
17             Helvetica Helvetica-Bold Helvetica-BoldOblique Helvetica-Oblique
18             Symbol
19             Times-Bold Times-BoldItalic Times-Italic Times-Roman
20             ZapfDingbats
21             );
22              
23             # Windows fonts with Type1 equivalents
24             my $alias = {
25             'arial' => 'helvetica',
26             'arialitalic' => 'helveticaoblique',
27             'arialbold' => 'helveticabold',
28             'arialbolditalic' => 'helveticaboldoblique',
29              
30             'times' => 'timesroman',
31             'timesnewromanbolditalic' => 'timesbolditalic',
32             'timesnewromanbold' => 'timesbold',
33             'timesnewromanitalic' => 'timesitalic',
34             'timesnewroman' => 'timesroman',
35              
36             'couriernewbolditalic' => 'courierboldoblique',
37             'couriernewbold' => 'courierbold',
38             'couriernewitalic' => 'courieroblique',
39             'couriernew' => 'courier',
40             };
41              
42             =head1 NAME
43              
44             PDF::API2::Resource::Font::CoreFont - Module for using the 14 standard PDF fonts.
45              
46             =head1 SYNOPSIS
47              
48             my $pdf = PDF::API2->new();
49             my $font = $pdf->font('Times-Roman');
50              
51             my $page = $pdf->page();
52             my $text = $page->text();
53             $text->font($font, 20);
54             $text->translate(200, 700);
55             $text->text('Hello world!');
56              
57             $pdf->save('/path/to/new.pdf');
58              
59             =head1 STANDARD FONTS
60              
61             The following fourteen fonts are available in all PDF readers that conform to
62             the PDF specification:
63              
64             =over
65              
66             =item * Courier
67              
68             =item * Courier-Bold
69              
70             =item * Courier-BoldOblique
71              
72             =item * Courier-Oblique
73              
74             =item * Helvetica
75              
76             =item * Helvetica-Bold
77              
78             =item * Helvetica-BoldOblique
79              
80             =item * Helvetica-Oblique
81              
82             =item * Symbol
83              
84             =item * Times-Bold
85              
86             =item * Times-BoldItalic
87              
88             =item * Times-Italic
89              
90             =item * Times-Roman
91              
92             =item * ZapfDingbats
93              
94             =back
95              
96             These fonts (except Symbol and ZapfDingbats) include glyphs for ASCII and
97             certain Latin characters only. If other characters are needed, you will need to
98             embed a font file.
99              
100             =cut
101              
102             sub _look_for_font {
103 53     53   107 my $name = shift();
104 53         5071 eval "require PDF::API2::Resource::Font::CoreFont::$name";
105 53 50       3459 if ($@) {
106 0         0 die "requested font '$name' not installed";
107             }
108              
109 53         152 my $class = "PDF::API2::Resource::Font::CoreFont::$name";
110 53         529 my $font = _deep_copy($class->data());
111 53   100     2555 $font->{'uni'} ||= [];
112 53         225 foreach my $n (0..255) {
113 13568 100       22590 unless (defined $font->{'uni'}->[$n]) {
114 13312         21526 $font->{'uni'}->[$n] = uniByName($font->{'char'}->[$n]);
115             }
116             }
117 53         974 return %$font;
118             }
119              
120             # Deep copy something, thanks to Randal L. Schwartz
121             # Changed to deal with code refs, in which case it doesn't try to deep copy
122             sub _deep_copy {
123 31743     31743   39517 my $this = shift();
124 9     9   62 no warnings 'recursion';
  9         20  
  9         6939  
125 31743 0       52782 unless (ref($this)) {
    50          
    100          
    100          
126 31345         64894 return $this;
127             }
128 0         0 elsif (ref($this) eq 'ARRAY') {
129 291         541 return [ map { _deep_copy($_) } @$this];
  15140         20468  
130             }
131 0         0 elsif (ref($this) eq 'HASH') {
132 107         3008 return +{ map { $_ => _deep_copy($this->{$_}) } keys %$this };
  16550         25978  
133             }
134 0         0 elsif (ref $this eq "CODE") {
135             # Can't deep copy code refs
136 0         0 return $this;
137             }
138             else {
139 0         0 die 'Unable to copy a ' . ref($this);
140             }
141             }
142              
143             sub new {
144 53     53 1 155 my ($class, $pdf, $name, %options) = @_;
145 53         172 my $is_standard = is_standard($name);
146              
147 53 50       2293 if (-f $name) {
148 0         0 eval "require '$name'";
149 0         0 $name = basename($name, '.pm');
150             }
151              
152 53         237 my $lookname = lc($name);
153 53         269 $lookname =~ s/[^a-z0-9]+//gi;
154 53 50       202 $lookname = $alias->{$lookname} if $alias->{$lookname};
155              
156 53         88 my $data;
157 53 50       173 unless (defined $options{'-metrics'}) {
158 53         184 $data = { _look_for_font($lookname) };
159             }
160             else {
161 0         0 $data = { %{$options{'-metrics'}} };
  0         0  
162             }
163              
164 53 50       303 die "Undefined font '$name($lookname)'" unless $data->{'fontname'};
165              
166 53 50       208 $class = ref($class) if ref($class);
167 53         320 my $self = $class->SUPER::new($pdf, $data->{'apiname'} . pdfkey() . '~' . time());
168 53 50       189 $pdf->new_obj($self) unless $self->is_obj($pdf);
169 53         148 $self->{' data'} = $data;
170 53 50       163 $self->{'-dokern'} = 1 if $options{'-dokern'};
171              
172 53         301 $self->{'Subtype'} = PDFName($self->data->{'type'});
173 53         237 $self->{'BaseFont'} = PDFName($self->fontname());
174 53 50       179 if ($options{'-pdfname'}) {
175 0         0 $self->name($options{'-pdfname'});
176             }
177              
178 53 100       186 unless ($self->data->{'iscore'}) {
179 15         44 $self->{'FontDescriptor'} = $self->descrByData();
180             }
181              
182 53         394 $self->encodeByData($options{'-encode'});
183              
184             # The standard non-symbolic fonts use unmodified WinAnsiEncoding.
185 53 100 100     452 if ($is_standard and not $self->issymbol() and not $options{'-encode'}) {
      100        
186 21         98 $self->{'Encoding'} = PDFName('WinAnsiEncoding');
187 21         84 delete $self->{'FirstChar'};
188 21         72 delete $self->{'LastChar'};
189 21         1158 delete $self->{'Widths'};
190             }
191              
192 53         435 return $self;
193             }
194              
195             =head1 METHODS
196              
197             =head2 is_standard
198              
199             my $boolean = PDF::API2::Resource::Font::CoreFont->is_standard($name);
200              
201             Returns true if C<$name> is an exact, case-sensitive match for one of the
202             standard font names shown above.
203              
204             =cut
205              
206             sub is_standard {
207 70     70 1 3142 my $name = pop();
208 70     677   638 return any { $_ eq $name } @standard_fonts;
  677         991  
209             }
210              
211             =head2 names
212              
213             my @font_names = PDF::API2::Resource::Font::CoreFont->list();
214             my $array_ref = PDF::API2::Resource::Font::CoreFont->list();
215              
216             Returns an array or a reference to an array containing the names of the built-in
217             core (standard) fonts.
218              
219             =cut
220              
221             sub names {
222 3 100   3 1 611 return wantarray() ? @standard_fonts : [@standard_fonts];
223             }
224              
225             1;