File Coverage

blib/lib/PDF/Builder/Resource/Font.pm
Criterion Covered Total %
statement 88 147 59.8
branch 37 54 68.5
condition 12 19 63.1
subroutine 7 9 77.7
pod 1 3 33.3
total 145 232 62.5


line stmt bran cond sub pod time code
1             package PDF::Builder::Resource::Font;
2              
3 8     8   1137 use base 'PDF::Builder::Resource::BaseFont';
  8         17  
  8         4004  
4              
5 8     8   91 use strict;
  8         29  
  8         190  
6 8     8   45 use warnings;
  8         17  
  8         448  
7             #no warnings qw[ deprecated recursion uninitialized ];
8              
9             our $VERSION = '3.023'; # VERSION
10             our $LAST_UPDATE = '3.021'; # manually update whenever code is changed
11              
12 8     8   47 use Encode qw(:all);
  8         28  
  8         2017  
13              
14 8     8   67 use PDF::Builder::Util;
  8         17  
  8         1156  
15 8     8   65 use PDF::Builder::Basic::PDF::Utils;
  8         20  
  8         13559  
16              
17             =head1 NAME
18              
19             PDF::Builder::Resource::Font - some common support routines for font files. Inherits from L
20              
21             =cut
22              
23             sub encodeByData {
24 52     52 0 218 my ($self, $encoding) = @_;
25              
26 52         189 my $data = $self->data();
27              
28 52 100 50     277 if ($self->issymbol() || ($encoding||'') eq 'asis') {
      100        
29 50         143 $encoding = undef;
30             }
31              
32 52 100 100     401 if (defined $encoding && $encoding =~ m|^uni(\d+)$|o) {
    100          
    50          
33 1         6 my $blk = $1;
34 1         5 $data->{'e2u'} = [ map { $blk*256+$_ } (0..255) ];
  256         370  
35 1 50       7 $data->{'e2n'} = [ map { nameByUni($_) || '.notdef' } @{$data->{'e2u'}} ];
  256         413  
  1         4  
36 1         11 $data->{'firstchar'} = 0;
37             } elsif (defined $encoding) {
38 1         14 $data->{'e2u'} = [ unpack('U*', decode($encoding, pack('C*', (0..255)))) ];
39 1 50       84 $data->{'e2n'} = [ map { nameByUni($_) || '.notdef' } @{$data->{'e2u'}} ];
  256         417  
  1         4  
40             } elsif (defined $data->{'uni'}) {
41 50         95 $data->{'e2u'} = [ @{$data->{'uni'}} ];
  50         1899  
42 50 50       143 $data->{'e2n'} = [ map { $_ || '.notdef' } @{$data->{'char'}} ];
  12800         23413  
  50         231  
43             } else {
44 0         0 $data->{'e2u'} = [ map { uniByName($_) } @{$data->{'char'}} ];
  0         0  
  0         0  
45 0 0       0 $data->{'e2n'} = [ map { $_ || '.notdef' } @{$data->{'char'}} ];
  0         0  
  0         0  
46             }
47              
48 52         529 $data->{'u2c'} = {};
49 52         153 $data->{'u2e'} = {};
50 52         215 $data->{'u2n'} = {};
51 52         207 $data->{'n2c'} = {};
52 52         164 $data->{'n2e'} = {};
53 52         143 $data->{'n2u'} = {};
54              
55 52         216 foreach my $n (0..255) {
56 13312         17843 my $xchar = undef;
57 13312         16757 my $xuni = undef;
58 13312 50       22406 if (defined $data->{'char'}->[$n]) {
59 13312         19018 $xchar = $data->{'char'}->[$n];
60             } else {
61 0         0 $xchar = '.notdef';
62             }
63 13312 100       33422 $data->{'n2c'}->{$xchar} = $n unless defined $data->{'n2c'}->{$xchar};
64              
65 13312 50       22933 if (defined $data->{'e2n'}->[$n]) {
66 13312         18747 $xchar = $data->{'e2n'}->[$n];
67             } else {
68 0         0 $xchar = '.notdef';
69             }
70 13312 100       28272 $data->{'n2e'}->{$xchar} = $n unless defined $data->{'n2e'}->{$xchar};
71              
72             $data->{'n2u'}->{$xchar} = $data->{'e2u'}->[$n]
73 13312 100       31687 unless defined $data->{'n2u'}->{$xchar};
74              
75 13312 50       21490 if (defined $data->{'char'}->[$n]) {
76 13312         18643 $xchar = $data->{'char'}->[$n];
77             } else {
78 0         0 $xchar = '.notdef';
79             }
80 13312 100       21378 if (defined $data->{'uni'}->[$n]) {
81 11579         17112 $xuni = $data->{'uni'}->[$n];
82             } else {
83 1733         2276 $xuni = 0;
84             }
85 13312 100       25023 $data->{'n2u'}->{$xchar} = $xuni unless defined $data->{'n2u'}->{$xchar};
86              
87 13312 100 66     53411 $data->{'u2c'}->{$xuni} ||= $n unless defined $data->{'u2c'}->{$xuni};
88              
89 13312 100       21624 if (defined $data->{'e2u'}->[$n]) {
90 11643         16790 $xuni = $data->{'e2u'}->[$n];
91             } else {
92 1669         2166 $xuni = 0;
93             }
94 13312 100 66     47676 $data->{'u2e'}->{$xuni} ||= $n unless defined $data->{'u2e'}->{$xuni};
95              
96 13312 50       22892 if (defined $data->{'e2n'}->[$n]) {
97 13312         18725 $xchar = $data->{'e2n'}->[$n];
98             } else {
99 0         0 $xchar = '.notdef';
100             }
101 13312 100       30949 $data->{'u2n'}->{$xuni} = $xchar unless defined $data->{'u2n'}->{$xuni};
102              
103 13312 50       22271 if (defined $data->{'char'}->[$n]) {
104 13312         19535 $xchar = $data->{'char'}->[$n];
105             } else {
106 0         0 $xchar = '.notdef';
107             }
108 13312 100       21825 if (defined $data->{'uni'}->[$n]) {
109 11579         16885 $xuni = $data->{'uni'}->[$n];
110             } else {
111 1733         2274 $xuni = 0;
112             }
113 13312 100       26965 $data->{'u2n'}->{$xuni} = $xchar unless defined $data->{'u2n'}->{$xuni};
114             }
115              
116 52         540 my $en = PDFDict();
117 52         221 $self->{'Encoding'} = $en;
118              
119 52         220 $en->{'Type'} = PDFName('Encoding');
120 52         237 $en->{'BaseEncoding'} = PDFName('WinAnsiEncoding');
121              
122 52         245 $en->{'Differences'} = PDFArray(PDFNum(0));
123 52         262 foreach my $n (0..255) {
124 13312   50     26656 $en->{'Differences'}->add_elements(PDFName($self->glyphByEnc($n) || '.notdef'));
125             }
126              
127 52         300 $self->{'FirstChar'} = PDFNum($data->{'firstchar'});
128 52         211 $self->{'LastChar'} = PDFNum($data->{'lastchar'});
129              
130 52         193 $self->{'Widths'} = PDFArray();
131 52         556 foreach my $n ($data->{'firstchar'} .. $data->{'lastchar'}) {
132 11680         24258 $self->{'Widths'}->add_elements(PDFNum($self->wxByEnc($n)));
133             }
134              
135 52         248 return $self;
136             }
137              
138             =head1 METHODS
139              
140             =over
141              
142             =item $font->automap()
143              
144             This applies to core fonts (C<< $pdf->corefont() >>) and PostScript fonts
145             (C<< $pdf->psfont() >>). These cannot use UTF-8 (or other multibyte character)
146             encoded text; only single byte characters. This limits a font to a maximum of
147             256 glyphs (the "standard" single-byte encoding being used). Any other glyphs
148             supplied with the font are inaccessible.
149              
150             C splits a font containing more than 256 glyphs into "planes" of single
151             byte fonts of up to 256 glyphs, so that all glyphs may be accessed in separate
152             "fonts". An array of new fonts will be returned, with [0] being the standard
153             code page (of the selected encoding). If there are any glyphs beyond xFF on the
154             standard encoding page, they will be returned in one or more additional fonts
155             of 223 glyphs each. I The first 32 are reserved as control characters
156             (although they have no glyphs), and number x20 is a space. This, plus 223,
157             gives 256 in total (the last plane may have fewer than 223 glyphs). These
158             "fonts" are temporary (dynamic), though as usable as any other font.
159              
160             Note that a plane may be B (only I at x20 and possibly an unusable
161             character at x21) if the previous plane was full. You might want to check if
162             any character in the plane has a Unicode value (if not, it's empty).
163              
164             The I of these 223 glyphs in each following plane does I appear
165             to follow any particular official scheme, so be sure to reference something like
166             C to see what is available, and what code point a glyph
167             is at (e.g., an 'A' in the text stream will print something different if you're
168             not on plane 0). For a given font B, they should be I. For
169             instance, in Times-Roman core font, an \x21 or ! in plane[1] should always give
170             an A+macron. Further note that new editions of font files released in the future
171             may have changes to the glyph list and the ordering (affecting which plane a
172             glyph appears on), so use automap() with caution. It appears that glyphs are
173             sorted by Unicode number, but if a new glyph is inserted, it would bump other
174             glyphs to new positions, and even to the next plane.
175              
176             An example:
177              
178             $fnt = $pdf->corefont('Times-Roman', -encode => 'latin1');
179             @planes = ($fnt, $fnt->automap()); # two planes
180             $text->font($planes[0], 15); # or just $fnt will work
181             $text->text('!'); # prints !
182             $text->font($planes[1], 15);
183             $text->text('!'); # prints A+macron
184              
185             If you had used 'latin2' encoding, an \x21 on plane 1 will give an inverted !
186             (¡ HTML entity).
187              
188             Note that C<< $planes[$n]->fontname() >> should always be the desired base
189             font (e.g., I), while C<< $planes[$n]->name() >> will be the font
190             ID (e.g., I) for plane 0, while for other planes there will be a
191             unique suffix added (e.g., I).
192              
193             If you have just an occasional non-plane 0 character (or run of characters),
194             it may be tolerable to switch back and forth between planes like this, just as
195             typing an HTML entity once in a while when you need a Greek letter on a web page
196             is acceptable to most people. However, if you're typing a lot of Greek text, a
197             dedicated keyboard may be better for you. Like that, switching to a TTF font in
198             order to be able to use UTF-8 may be easier.
199              
200             =back
201              
202             =cut
203              
204             sub automap {
205 0     0 1   my ($self) = @_;
206 0           my $data = $self->data();
207              
208 0           my %gl = map { $_=>defineName($_) } keys %{$data->{'wx'}};
  0            
  0            
209              
210 0           foreach my $n (0..255) {
211 0           delete $gl{$data->{'e2n'}->[$n]};
212             }
213              
214 0 0 0       if (defined $data->{'comps'} && !$self->{'-nocomps'}) {
215 0           foreach my $n (keys %{$data->{'comps'}}) {
  0            
216 0           delete $gl{$n};
217             }
218             }
219              
220 0           my @nm = sort { $gl{$a} <=> $gl{$b} } keys %gl;
  0            
221              
222 0           my @fnts = ();
223 0           my $count = 0;
224 0           while (my @glyphs = splice(@nm, 0, 223)) {
225 0           my $obj = $self->SUPER::new($self->{' apipdf'}, $self->name().'am'.$count);
226 0           $obj->{' data'} = { %{$data} };
  0            
227 0           $obj->data()->{'firstchar'} = 32;
228 0           $obj->data()->{'lastchar'} = 32+scalar(@glyphs);
229 0           push(@fnts, $obj);
230 0           foreach my $key (qw( Subtype BaseFont FontDescriptor )) {
231 0 0         $obj->{$key} = $self->{$key} if defined $self->{$key};
232             }
233 0           $obj->data()->{'char'} = [];
234 0           $obj->data()->{'uni'} = [];
235 0           foreach my $n (0..31) {
236 0           $obj->data()->{'char'}->[$n] = '.notdef';
237 0           $obj->data()->{'uni'}->[$n] = 0;
238             }
239 0           $obj->data()->{'char'}->[32] = 'space';
240 0           $obj->data()->{'uni'}->[32] = 32;
241 0           foreach my $n (33 .. $obj->data()->{'lastchar'}) {
242 0           $obj->data()->{'char'}->[$n] = $glyphs[$n-33];
243 0           $obj->data()->{'uni'}->[$n] = $gl{$glyphs[$n-33]};
244             }
245 0           foreach my $n (($obj->data()->{'lastchar'}+1) .. 255) {
246 0           $obj->data()->{'char'}->[$n] = '.notdef';
247 0           $obj->data()->{'uni'}->[$n] = 0;
248             }
249 0           $obj->encodeByData(undef);
250              
251 0           $count++;
252             }
253              
254 0           return @fnts;
255             }
256              
257             sub remap {
258 0     0 0   my ($self, $enc) = @_;
259              
260 0           my $obj = $self->SUPER::new($self->{' apipdf'}, $self->name().'rm'.pdfkey());
261 0           $obj->{' data'}={ %{$self->data()} };
  0            
262 0           foreach my $key (qw( Subtype BaseFont FontDescriptor )) {
263 0 0         $obj->{$key} = $self->{$key} if defined $self->{$key};
264             }
265              
266 0           $obj->encodeByData($enc);
267              
268 0           return $obj;
269             }
270              
271             1;