File Coverage

blib/lib/PDF/Builder/Resource/CIDFont.pm
Criterion Covered Total %
statement 38 164 23.1
branch 2 66 3.0
condition 1 74 1.3
subroutine 8 30 26.6
pod 9 23 39.1
total 58 357 16.2


line stmt bran cond sub pod time code
1             package PDF::Builder::Resource::CIDFont;
2              
3 2     2   1109 use base 'PDF::Builder::Resource::BaseFont';
  2         6  
  2         693  
4              
5 2     2   14 use strict;
  2         4  
  2         48  
6 2     2   10 use warnings;
  2         4  
  2         120  
7              
8             our $VERSION = '3.025'; # VERSION
9             our $LAST_UPDATE = '3.024'; # manually update whenever code is changed
10              
11 2     2   12 use Encode qw(:all);
  2         3  
  2         594  
12              
13 2     2   26 use PDF::Builder::Basic::PDF::Utils;
  2         4  
  2         171  
14 2     2   13 use PDF::Builder::Util;
  2         4  
  2         5571  
15              
16             =head1 NAME
17              
18             PDF::Builder::Resource::CIDFont - Base class for CID fonts
19              
20             =head1 METHODS
21              
22             =over
23              
24             =item $font = PDF::Builder::Resource::CIDFont->new($pdf, $name)
25              
26             Returns a cid-font object, base class for all CID-based fonts.
27              
28             =cut
29              
30             sub new {
31 1     1 1 6 my ($class, $pdf, $name, %opts) = @_;
32              
33 1 50       4 $class = ref($class) if ref($class);
34 1         13 my $self = $class->SUPER::new($pdf, $name);
35 1 50 33     7 $pdf->new_obj($self) if defined($pdf) && !$self->is_obj($pdf);
36              
37 1         6 $self->{'Type'} = PDFName('Font');
38 1         6 $self->{'Subtype'} = PDFName('Type0');
39 1         4 $self->{'Encoding'} = PDFName('Identity-H');
40              
41 1         6 my $de = PDFDict();
42 1         4 $pdf->new_obj($de);
43 1         5 $self->{'DescendantFonts'} = PDFArray($de);
44              
45 1         3 $de->{'Type'} = PDFName('Font');
46 1         3 $de->{'CIDSystemInfo'} = PDFDict();
47 1         7 $de->{'CIDSystemInfo'}->{'Registry'} = PDFString('Adobe', 'x');
48 1         6 $de->{'CIDSystemInfo'}->{'Ordering'} = PDFString('Identity', 'x');
49 1         7 $de->{'CIDSystemInfo'}->{'Supplement'} = PDFNum(0);
50 1         7 $de->{'CIDToGIDMap'} = PDFName('Identity');
51              
52 1         5 $self->{' de'} = $de;
53              
54 1         4 return $self;
55             }
56              
57             sub glyphByCId {
58 0     0 0 0 my ($self, $gid) = @_;
59 0         0 return $self->data()->{'g2n'}->[$gid];
60             }
61              
62             sub uniByCId {
63 0     0 0 0 my ($self, $gid) = @_;
64 0         0 my $uni = $self->data()->{'g2u'}->[$gid];
65             # fallback to U+0000 if no match
66 0 0       0 $uni = 0 unless defined $uni;
67 0         0 return $uni;
68             }
69              
70             # TBD note that cidByUni has been seen returning 'undef' in some cases.
71             # be sure to handle this!
72             sub cidByUni {
73 53     53 0 89 my ($self, $gid) = @_;
74 53         94 return $self->data()->{'u2g'}->{$gid};
75             }
76              
77             sub cidByEnc {
78 0     0 0   my ($self, $gid) = @_;
79 0           return $self->data()->{'e2g'}->[$gid];
80             }
81              
82             sub wxByCId {
83 0     0 0   my ($self, $g) = @_;
84              
85 0           my $w;
86 0           my $widths = $self->data()->{'wx'};
87              
88 0 0 0       if (ref($widths) eq 'ARRAY' && defined $widths->[$g]) {
    0 0        
89 0           $w = int($widths->[$g]);
90             } elsif (ref($widths) eq 'HASH' && defined $widths->{$g}) {
91 0           $w = int($widths->{$g});
92             } else {
93 0           $w = $self->missingwidth();
94             }
95              
96 0           return $w;
97             }
98              
99             sub wxByUni {
100 0     0 1   my ($self, $gid) = @_;
101 0           return $self->wxByCId($self->data()->{'u2g'}->{$gid});
102             }
103              
104             sub wxByEnc {
105 0     0 1   my ($self, $gid) = @_;
106 0           return $self->wxByCId($self->data()->{'e2g'}->[$gid]);
107             }
108              
109             sub width {
110 0     0 1   my ($self, $text) = @_;
111 0           return $self->width_cid($self->cidsByStr($text));
112             }
113              
114             sub width_cid {
115 0     0 0   my ($self, $text) = @_;
116              
117 0           my $width = 0;
118 0           my $lastglyph = 0;
119 0           foreach my $n (unpack('n*', $text)) {
120 0           $width += $self->wxByCId($n);
121 0 0 0       if ($self->{'-dokern'} && $self->haveKernPairs()) {
122 0 0         if ($self->kernPairCid($lastglyph, $n)) {
123 0           $width -= $self->kernPairCid($lastglyph, $n);
124             }
125             }
126 0           $lastglyph = $n;
127             }
128 0           $width /= 1000;
129 0           return $width;
130             }
131              
132             =item $cidstring = $font->cidsByStr($string)
133              
134             Returns the cid-string from string based on the font's encoding map.
135              
136             =cut
137              
138             sub _cidsByStr {
139 0     0     my ($self, $s) = @_;
140              
141 0           $s = pack('n*', map { $self->cidByEnc($_) } unpack('C*', $s));
  0            
142 0           return $s;
143             }
144              
145             sub cidsByStr {
146 0     0 1   my ($self, $text) = @_;
147              
148 0 0 0       if (utf8::is_utf8($text) &&
    0 0        
    0 0        
    0 0        
      0        
      0        
      0        
      0        
      0        
      0        
      0        
149             defined $self->data()->{'decode'} &&
150             $self->data()->{'decode'} ne 'ident') {
151 0           $text = encode($self->data()->{'decode'}, $text);
152             } elsif (utf8::is_utf8($text) &&
153             defined $self->data()->{'decode'} &&
154             $self->data()->{'decode'} eq 'ident') {
155 0           $text = $self->cidsByUtf($text);
156             } elsif (!utf8::is_utf8($text) &&
157             defined $self->data()->{'encode'} &&
158             defined $self->data()->{'decode'} &&
159             $self->data()->{'decode'} eq 'ident') {
160 0           $text = $self->cidsByUtf(decode($self->data()->{'encode'}, $text));
161             } elsif (!utf8::is_utf8($text) &&
162             $self->can('issymbol') &&
163             $self->issymbol() &&
164             defined $self->data()->{'decode'} &&
165             $self->data()->{'decode'} eq 'ident') {
166 0           $text = pack('U*', (map { $_+0xf000 } unpack('C*', $text)));
  0            
167 0           $text = $self->cidsByUtf($text);
168             } else {
169 0           $text = $self->_cidsByStr($text);
170             }
171 0           return $text;
172             }
173              
174             =item $cidstring = $font->cidsByUtf($utf8string)
175              
176             Returns the CID-encoded string from utf8-string.
177              
178             =cut
179              
180             sub cidsByUtf {
181 0     0 1   my ($self, $s) = @_;
182              
183             $s = pack('n*',
184 0 0         map { $self->cidByUni($_)||0 }
185             (map {
186 0 0 0       ($_ and $_>0x7f and $_<0xA0)? uniByName(nameByUni($_)): $_
  0            
187             }
188             unpack('U*', $s)));
189              
190 0           utf8::downgrade($s);
191 0           return $s;
192             }
193              
194             sub textByStr {
195 0     0 1   my ($self, $text) = @_;
196 0           return $self->text_cid($self->cidsByStr($text));
197             }
198              
199             sub textByStrKern {
200 0     0 1   my ($self, $text, $size, $indent) = @_;
201 0           return $self->text_cid_kern($self->cidsByStr($text), $size, $indent);
202             }
203              
204             sub text {
205 0     0 0   my ($self, $text, $size, $indent) = @_;
206              
207 0           my $newtext = $self->textByStr($text);
208 0 0 0       if (defined $size && $self->{'-dokern'}) {
    0          
209 0           $newtext = $self->textByStrKern($text, $size, $indent);
210 0           return $newtext;
211             } elsif (defined $size) {
212 0 0 0       if (defined($indent) && $indent!=0) {
213 0           return("[ $indent $newtext ] TJ");
214             } else {
215 0           return "$newtext Tj";
216             }
217             } else {
218 0           return $newtext;
219             }
220             }
221              
222             sub text_cid {
223 0     0 0   my ($self, $text, $size) = @_;
224              
225 0 0         if ($self->can('fontfile')) {
226 0           foreach my $g (unpack('n*', $text)) {
227 0           $self->fontfile()->subsetByCId($g);
228             }
229             }
230 0           my $newtext = unpack('H*', $text);
231 0 0         if (defined $size) {
232 0           return "<$newtext> Tj";
233             } else {
234 0           return "<$newtext>";
235             }
236             }
237              
238             sub text_cid_kern {
239 0     0 0   my ($self, $text, $size, $indent) = @_;
240              
241 0 0         if ($self->can('fontfile')) {
242 0           foreach my $g (unpack('n*', $text)) {
243 0           $self->fontfile()->subsetByCId($g);
244             }
245             }
246 0 0 0       if (defined $size && $self->{'-dokern'} && $self->haveKernPairs()) {
    0 0        
247 0           my $newtext = ' ';
248 0           my $lastglyph = 0;
249 0           my $tBefore = 0;
250 0           foreach my $n (unpack('n*', $text)) {
251 0 0         if ($self->kernPairCid($lastglyph, $n)) {
252 0 0         $newtext .= '> ' if $tBefore;
253 0           $newtext .= sprintf('%i ', $self->kernPairCid($lastglyph, $n));
254 0           $tBefore = 0;
255             }
256 0           $lastglyph = $n;
257 0           my $t = sprintf('%04X', $n);
258 0 0         $newtext .= '<' unless $tBefore;
259 0           $newtext .= $t;
260 0           $tBefore = 1;
261             }
262 0 0         $newtext .= '> ' if $tBefore;
263 0 0 0       if (defined($indent) && $indent != 0) {
264 0           return "[ $indent $newtext ] TJ";
265             } else {
266 0           return "[ $newtext ] TJ";
267             }
268             } elsif (defined $size) {
269 0           my $newtext = unpack('H*', $text);
270 0 0 0       if (defined($indent) && $indent != 0) {
271 0           return "[ $indent <$newtext> ] TJ";
272             } else {
273 0           return "<$newtext> Tj";
274             }
275             } else {
276 0           my $newtext = unpack('H*', $text);
277 0           return "<$newtext>";
278             }
279             }
280              
281             sub kernPairCid {
282 0     0 0   return 0;
283             }
284              
285             sub haveKernPairs {
286 0     0 0   return 0; # PDF::API2 changed to just 'return;'
287             }
288              
289             sub encodeByName {
290 0     0 0   my ($self, $enc) = @_;
291              
292 0 0         return if $self->issymbol();
293              
294 0 0         if (defined $enc) {
295             $self->data()->{'e2u'} = [
296 0 0 0       map { ($_ and $_>0x7f and $_<0xA0)? uniByName(nameByUni($_)): $_ }
  0            
297             unpack('U*', decode($enc, pack('C*', 0..255)))
298             ];
299             }
300             $self->data()->{'e2n'} = [
301 0 0 0       map { $self->data()->{'g2n'}->[$self->data()->{'u2g'}->{$_} || 0] || '.notdef' }
302 0           @{$self->data()->{'e2u'}}
  0            
303             ];
304             $self->data()->{'e2g'} = [
305 0 0         map { $self->data()->{'u2g'}->{$_} || 0 }
306 0           @{$self->data()->{'e2u'}}
  0            
307             ];
308              
309 0           $self->data()->{'u2e'} = {};
310 0           foreach my $n (reverse 0..255) {
311 0   0       $self->data()->{'u2e'}->{$self->data()->{'e2u'}->[$n]} //= $n;
312             }
313              
314 0           return $self;
315             }
316              
317             sub subsetByCId {
318 0     0 0   return 1;
319             }
320              
321             sub subvec {
322 0     0 0   return 1;
323             }
324              
325             sub glyphNum {
326 0     0 1   my $self = shift;
327              
328 0 0         if (defined $self->data()->{'glyphs'}) {
329 0           return $self->data()->{'glyphs'};
330             }
331 0           return scalar @{$self->data()->{'wx'}};
  0            
332             }
333              
334             #sub outobjdeep {
335             # my ($self, $fh, $pdf, %opts) = @_;
336             #
337             # return $self->SUPER::outobjdeep($fh, $pdf, %opts);
338             #}
339              
340             =back
341              
342             =cut
343              
344             1;