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