File Coverage

blib/lib/PDF/Builder/Resource/CIDFont/TrueType.pm
Criterion Covered Total %
statement 18 87 20.6
branch 0 32 0.0
condition 0 20 0.0
subroutine 6 16 37.5
pod 10 10 100.0
total 34 165 20.6


line stmt bran cond sub pod time code
1             package PDF::Builder::Resource::CIDFont::TrueType;
2              
3 1     1   1005 use base 'PDF::Builder::Resource::CIDFont';
  1         2  
  1         96  
4              
5 1     1   4 use strict;
  1         2  
  1         16  
6 1     1   3 use warnings;
  1         1  
  1         53  
7              
8             our $VERSION = '3.028'; # VERSION
9             our $LAST_UPDATE = '3.028'; # manually update whenever code is changed
10              
11 1     1   4 use PDF::Builder::Basic::PDF::Utils;
  1         2  
  1         106  
12 1     1   623 use PDF::Builder::Resource::CIDFont::TrueType::FontFile;
  1         4  
  1         43  
13 1     1   7 use PDF::Builder::Util;
  1         2  
  1         974  
14              
15             =head1 NAME
16              
17             PDF::Builder::Resource::CIDFont::TrueType - TrueType (ttfont) font support
18              
19             Inherits from L<PDF::Builder::Resource::CIDFont>
20              
21             Generally also usable for OTF (Open Type) fonts
22              
23             =head1 METHODS
24              
25             =head2 new
26              
27             $font = PDF::Builder::Resource::CIDFont::TrueType->new($pdf, $file, %opts)
28              
29             =over
30              
31             Returns a font object for TrueType and OpenType fonts (from C<ttfont()> call).
32              
33             =back
34              
35             Valid Options (%opts) are:
36              
37             =over
38              
39             =item encode
40              
41             Changes the encoding of the font from its default (WinAnsiEncoding).
42              
43             Note that for a single byte encoding (e.g., 'latin1'), you are limited to 256
44             characters defined for that encoding. 'automap' does not work with TrueType.
45             If you want more characters than that, use 'utf8' encoding with a UTF-8
46             encoded text string.
47              
48             =item isocmap
49              
50             Use the ISO Unicode Map instead of the default MS Unicode Map.
51              
52             =item unicodemap
53              
54             If 1 (default), output ToUnicode CMap to permit text searches and screen
55             readers. Set to 0 to save space by I<not> including the ToUnicode CMap, but
56             text searching and screen reading will not be possible.
57              
58             =item dokern
59              
60             Enables kerning if data is available.
61              
62             C<kerning> is still accepted as an (older) B<alternative> to C<dokern>.
63              
64             =item embed
65              
66             If set (non-zero), which is the default, the font (entire or subsetted) will
67             be embedded in the PDF file. See the comments in C<noembed> about the possible
68             hazards of I<not> embedding the font, and limitations on embedding.
69              
70             C<true> (non-zero) and C<false> (zero) are the values of C<embed>. It is
71             possible that in the future, some non-zero values may get special meaning (such
72             as permission flags), so it is best to use only 0 and 1 for a value.
73              
74             =item noembed
75              
76             B<noembed> is I<ignored> if B<embed> I<is> given. C<noembed> is deprecated,
77             while C<embed> (default true) is preferred.
78              
79             Disables embedding of the font file. B<Note that this is potentially hazardous,
80             as the glyphs provided on the PDF reader machine may not match what was used on
81             the PDF writer machine (the one running PDF::Builder)!> If you know I<for sure>
82             that all PDF readers will be using the same TTF or OTF file you're using with
83             PDF::Builder; not embedding the font may be acceptable, in return for a smaller
84             PDF file size. Note that the Reader needs to know where to find the font file
85             -- it can't be in any random place, but typically needs to be listed in a path
86             that the Reader follows. Otherwise, it will be unable to render the text!
87              
88             Some additional comments on embedding font file(s) into the PDF: besides
89             substantially increasing the size of the PDF (even if the font is subsetted,
90             by default), PDF::Builder does not check the font file for any flags indicating
91             font licensing issues and limitations on use. A font foundry may not permit
92             embedding at all, may permit a subset of the font to be embedded, may permit a
93             full font to be embedded, and may specify what can be done with an embedded
94             font (e.g., may or may not be extracted for further use beyond displaying this
95             one PDF). When you choose to use (and embed) a font, you should be aware of any
96             such licensing issues.
97              
98             =item nosubset
99              
100             Disables subsetting of a TTF/OTF font, when embedded. By default, only the
101             glyphs used by a document are included in the file, and I<not> the entire font.
102             This can result in a tremendous savings in PDF file size. If you intend to
103             allow the PDF to be edited by users, not having the entire font glyph set
104             available may cause problems, so be aware of that (and consider using
105             C<< nosubset => 1 >>. Setting this flag to any value results in the entire
106             font glyph set being embedded in the file. It might be a good idea to use only
107             the value B<1>, in case other values are assigned roles in the future.
108              
109             =item debug
110              
111             If set to 1 (default is 0), diagnostic information is output about the CMap
112             processing.
113              
114             =item usecmf
115              
116             If set to 1 (default is 0), the first priority is to make use of one of the
117             four C<.cmap> files for CJK fonts. This is the I<old> way of processing TTF
118             files. If, after all is said and done, a working I<internal> CMap hasn't been
119             found (for usecmf=>0), C<ttfont()> will fall back to using a C<.cmap> file
120             if possible.
121              
122             =item cmaps
123              
124             This flag may be set to a string listing the Platform/Encoding pairs to look
125             for of any internal CMaps in the font file, in the desired order (highest
126             priority first). If one list (comma and/or space-separated pairs) is given, it
127             is used for both Windows and non-Windows platforms (on which PDF::Builder is
128             running, I<not> the PDF reader's). Two lists, separated by a semicolon ; may be
129             given, with the first being used for a Windows platform and the second for
130             non-Windows. The default list is C<0/6 3/10 0/4 3/1 0/3; 0/6 0/4 3/10 0/3 3/1>.
131             Finally, instead of a P/E list, a string C<find_ms> may be given to tell it to
132             simply call the Font::TTF C<find_ms()> method to find a (preferably Windows)
133             internal CMap. C<cmaps> set to 'find_ms' would emulate the I<old> way of
134             looking for CMaps. Symbol fonts (3/0) always use find_ms(), and the new default
135             lookup is (if C<.cmap> isn't used, see C<usecmf>) to try to get a match with
136             the default list for the appropriate OS. If none can be found, find_ms() is
137             tried, and as last resort use the C<.cmap> (if available), even if C<usecmf>
138             is not 1.
139              
140             =back
141              
142             =cut
143              
144             sub new {
145 0     0 1   my ($class, $pdf, $file, %opts) = @_;
146              
147             # copy dashed option names to preferred undashed names
148 0 0 0       if (defined $opts{'-encode'} && !defined $opts{'encode'}) { $opts{'encode'} = delete($opts{'-encode'}); }
  0            
149 0 0 0       if (defined $opts{'-nosubset'} && !defined $opts{'nosubset'}) { $opts{'nosubset'} = delete($opts{'-nosubset'}); }
  0            
150 0 0 0       if (defined $opts{'-dokern'} && !defined $opts{'dokern'}) { $opts{'dokern'} = delete($opts{'-dokern'}); }
  0            
151              
152             # embed should already be set by ttfont(), so ignore noembed too
153             #if (defined $opts{'-noembed'} && !defined $opts{'noembed'}) { $opts{'noembed'} = delete($opts{'-noembed'}); }
154             #if (defined $opts{'-embed'} && !defined $opts{'embed'}) { $opts{'embed'} = delete($opts{'-embed'}); }
155              
156 0   0       $opts{'encode'} //= 'latin1';
157 0           my ($ff, $data) = PDF::Builder::Resource::CIDFont::TrueType::FontFile->new($pdf, $file, %opts);
158              
159 0 0         $class = ref $class if ref $class;
160             # my $self = $class->SUPER::new($pdf, $data->{'apiname'}.pdfkey().'~'.time());
161 0           my $self = $class->SUPER::new($pdf, $data->{'apiname'} . pdfkey());
162 0 0 0       $pdf->new_obj($self) if defined($pdf) && !$self->is_obj($pdf);
163              
164 0           $self->{' data'} = $data;
165              
166 0           $self->{'BaseFont'} = PDFName($self->fontname());
167              
168 0           my $des = $self->descrByData();
169 0           my $de = $self->{' de'};
170              
171 0           $de->{'FontDescriptor'} = $des;
172 0 0         $de->{'Subtype'} = PDFName($self->iscff()? 'CIDFontType0': 'CIDFontType2');
173             ## $de->{'BaseFont'} = PDFName(pdfkey().'+'.($self->fontname()).'~'.time());
174 0           $de->{'BaseFont'} = PDFName($self->fontname());
175 0           $de->{'DW'} = PDFNum($self->missingwidth());
176 0 0         if ($opts{'embed'}) {
177             # TBD: check, API2 omits ->data() term
178 0 0         $des->{$self->data()->{'iscff'}? 'FontFile3': 'FontFile2'} = $ff;
179             }
180 0 0         unless ($self->issymbol()) {
181 0           $self->encodeByName($opts{'encode'});
182 0           $self->data->{'encode'} = $opts{'encode'};
183 0           $self->data->{'decode'} = 'ident';
184             }
185              
186 0 0         if ($opts{'nosubset'}) {
187 0           $self->data()->{'nosubset'} = 1;
188             }
189              
190 0           $self->{' ff'} = $ff;
191 0           $pdf->new_obj($ff);
192              
193 0 0         $self->{'-dokern'} = 1 if $opts{'dokern'};
194              
195 0           return $self;
196             }
197              
198             =head2 fontfile
199              
200             $font->fontfile()
201              
202             =over
203              
204             Returns font file object (' ff' element), so its methods may be invoked.
205              
206             =back
207              
208             =cut
209              
210             sub fontfile {
211 0     0 1   return $_[0]->{' ff'};
212             }
213              
214             =head2 fontobj
215              
216             $font->fontobj()
217              
218             =over
219              
220             Returns font object, so its methods and properties may be used.
221              
222             =back
223              
224             =cut
225              
226             sub fontobj {
227 0     0 1   return $_[0]->data()->{'obj'};
228             }
229              
230             =head2 wxByCId
231              
232             $font->wxByCId($gID)
233              
234             =over
235              
236             Returns unscaled glyph width, given its glyph ID (CID).
237              
238             =back
239              
240             =cut
241              
242             sub wxByCId {
243 0     0 1   my ($self, $g) = @_;
244              
245 0           my $t = $self->fontobj()->{'hmtx'}->read()->{'advance'}[$g];
246 0           my $w;
247              
248 0 0         if (defined $t) {
249 0           $w = int($t *1000/$self->data()->{'upem'});
250             } else {
251 0           $w = $self->missingwidth();
252             }
253              
254 0           return $w;
255             }
256              
257             =head2 haveKernPairs
258              
259             $flag = $font->haveKernPairs()
260              
261             =over
262              
263             Does the font include kerning data? Invokes fontfile's haveKernPairs().
264             Not clear what additional optional arguments are.
265              
266             =back
267              
268             =cut
269              
270             sub haveKernPairs {
271 0     0 1   my $self = shift;
272              
273 0           return $self->fontfile()->haveKernPairs(@_);
274             }
275              
276             =head2 kernPairCid
277              
278             $flag = $font->kernPairCid($gID, $n)
279              
280             =over
281              
282             Returns kerning information for? Not clear what additional arguments are.
283             Invokes fontfile's kernPairCid() method.
284              
285             =back
286              
287             =cut
288              
289             sub kernPairCid {
290 0     0 1   my $self = shift;
291              
292 0           return $self->fontfile()->kernPairCid(@_);
293             }
294              
295             =head2 subsetByCId
296              
297             $font->subsetByCId($gID)
298              
299             =over
300              
301             Invokes subsetByCId() method from fontfile() to put the glyph into the embedded
302             font cache in the PDF.
303              
304             =back
305              
306             =cut
307              
308             sub subsetByCId {
309 0     0 1   my $self = shift;
310              
311 0 0         return if $self->iscff();
312 0           my $g = shift;
313 0           return $self->fontfile()->subsetByCId($g);
314             }
315              
316             =head2 subvec
317              
318             $font->subvec($gID)
319              
320             =over
321              
322             (No Information) invokes fontfile's subvec() method.
323              
324             =back
325              
326             =cut
327              
328             sub subvec {
329 0     0 1   my $self = shift;
330              
331 0 0         return 1 if $self->iscff();
332 0           my $g = shift;
333 0           return $self->fontfile()->subvec($g);
334             }
335              
336             =head2 glyphNum
337              
338             $count = $font->glyphNum()
339              
340             =over
341              
342             Number of glyphs in the font.
343              
344             =back
345              
346             =cut
347              
348             sub glyphNum {
349 0     0 1   return $_[0]->fontfile()->glyphNum();
350             }
351              
352             =head2 outobjdeep
353              
354             $font->outobjdeep()
355              
356             =over
357              
358             (No Information) output to PDF
359              
360             =back
361              
362             =cut
363              
364             sub outobjdeep {
365 0     0 1   my ($self, $fh, $pdf) = @_;
366              
367 0           my $notdefbefore = 1;
368              
369 0           my $wx = PDFArray();
370 0           $self->{' de'}->{'W'} = $wx;
371 0           my $ml;
372              
373 0           foreach my $w (0 .. (scalar @{$self->data()->{'g2u'}} - 1 )) {
  0            
374 0 0 0       if ($self->subvec($w) && $notdefbefore == 1) {
    0 0        
375 0           $notdefbefore = 0;
376 0           $ml = PDFArray();
377 0           $wx->add_elements(PDFNum($w), $ml);
378             # $ml->add_elements(PDFNum($self->data()->{'wx'}->[$w]));
379 0           $ml->add_elements(PDFNum($self->wxByCId($w)));
380             } elsif ($self->subvec($w) && $notdefbefore == 0) {
381             # $ml->add_elements(PDFNum($self->data()->{'wx'}->[$w]));
382 0           $ml->add_elements(PDFNum($self->wxByCId($w)));
383             } else {
384 0           $notdefbefore = 1;
385             }
386             # optimization for CJK
387             #if ($self->subvec($w) && $notdefbefore == 1 && $self->data()->{'wx'}->[$w] != $self->missingwidth()) {
388             # $notdefbefore = 0;
389             # $ml = PDFArray();
390             # $wx->add_elements(PDFNum($w), $ml);
391             # $ml->add_elements(PDFNum($self->data()->{'wx'}->[$w]));
392             #} elsif ($self->subvec($w) && $notdefbefore == 0 && $self->data()->{'wx'}->[$w] != $self->missingwidth()) {
393             # $notdefbefore = 0;
394             # $ml->add_elements(PDFNum($self->data()->{'wx'}->[$w]));
395             #} else {
396             # $notdefbefore = 1;
397             #}
398             }
399              
400 0           return $self->SUPER::outobjdeep($fh, $pdf);
401             }
402              
403             1;