File Coverage

blib/lib/PDF/Font.pm
Criterion Covered Total %
statement 60 68 88.2
branch 3 10 30.0
condition n/a
subroutine 14 16 87.5
pod 3 4 75.0
total 80 98 81.6


line stmt bran cond sub pod time code
1             package PDF::Font;
2              
3             our $VERSION = '1.42';
4              
5             =head1 NAME
6              
7             PDF::Font - Base font class for PDF::Create.
8              
9             =head1 VERSION
10              
11             Version 1.42
12              
13             =cut
14              
15 18     18   351 use 5.006;
  18         51  
16 18     18   72 use strict; use warnings;
  18     18   19  
  18         617  
  18         58  
  18         18  
  18         463  
17              
18 18     18   8869 use utf8;
  18         146  
  18         59  
19 18     18   480 use Carp qw(croak);
  18         19  
  18         683  
20 18     18   66 use Data::Dumper;
  18         14  
  18         682  
21 18     18   9296 use JSON;
  18         153170  
  18         60  
22 18     18   8742 use File::Share ':all';
  18         89952  
  18         26686  
23              
24             =encoding utf8
25              
26             =head1 DESCRIPTION
27              
28             Base font class to support font families approved by L. This is used
29             in the method C inside the package L.
30              
31             =head1 SYNOPSIS
32              
33             use strict; use warnings;
34             use PDF::Font;
35              
36             my $font = PDF::Font->new('Helvetica');
37             my $char_widths = $font->char_width;
38             print "Character width: ", $font->get_char_width(ord('A')), "\n";
39             print "Character name: ", $font->get_char_name(ord('A')) , "\n";
40              
41             =head1 CONSTRUCTOR
42              
43             Expects C as the only parameter. It can be one of the following names:
44              
45             =over 4
46              
47             =item * Courier
48              
49             =item * Courier-Bold
50              
51             =item * Courier-BoldOblique
52              
53             =item * Courier-Oblique
54              
55             =item * Helvetica
56              
57             =item * Helvetica-Bold
58              
59             =item * Helvetica-BoldOblique
60              
61             =item * Helvetica-Oblique
62              
63             =item * Times-Bold
64              
65             =item * Times-BoldItalic
66              
67             =item * Times-Italic
68              
69             =item * Times-Roman
70              
71             =item * Symbol
72              
73             =back
74              
75             =cut
76              
77             our $DEBUG = 0;
78             our $SUPPORTED_FONTS = {
79             'Courier' => 1,
80             'Courier-Bold' => 1,
81             'Courier-BoldOblique' => 1,
82             'Courier-Oblique' => 1,
83             'Helvetica' => 1,
84             'Helvetica-Bold' => 1,
85             'Helvetica-BoldOblique' => 1,
86             'Helvetica-Oblique' => 1,
87             'Times-Bold' => 1,
88             'Times-BoldItalic' => 1,
89             'Times-Italic' => 1,
90             'Times-Roman' => 1,
91             'Symbol' => 1,
92             };
93              
94             sub new {
95 234     234 0 363 my ($class, $font_name) = @_;
96              
97 234 50       445 croak "Missing font name."
98             unless defined $font_name;
99             croak "Invalid font name [$font_name]."
100 234 50       402 unless (exists $SUPPORTED_FONTS->{$font_name});
101              
102 234         525 my $self = { debug => $DEBUG, font_name => $font_name };
103 234         302 bless $self, $class;
104              
105 234         363 $self->{char_width} = $self->_generate_char_width;
106 234         478 $self->{charset} = $self->_generate_charset;
107              
108 234         561 return $self;
109             }
110              
111             =head1 METHODS
112              
113             =head2 char_width()
114              
115             Returns arrayref of all characters width (0..255).
116              
117             =cut
118              
119             sub char_width {
120 234     234 1 265 my ($self) = @_;
121              
122 234         18498 return $self->{char_width};
123             }
124              
125             =head2 get_char_width($codepoint)
126              
127             Returns the character width for the given C<$codepoint>.
128              
129             =cut
130              
131             sub get_char_width {
132 0     0 1 0 my ($self, $codepoint) = @_;
133              
134             croak "Invalid codepoint [$codepoint] received."
135 0 0       0 unless (exists $self->{charset}->{$codepoint});
136              
137 0         0 return $self->{charset}->{$codepoint}->{char_width};
138             }
139              
140             =head2 get_char_name($codepoint)
141              
142             Returns the character name for the given C<$codepoint>.
143              
144             =cut
145              
146             sub get_char_name {
147 0     0 1 0 my ($self, $codepoint) = @_;
148              
149             croak "Invalid codepoint [$codepoint] received."
150 0 0       0 unless (exists $self->{charset}->{$codepoint});
151              
152 0         0 return $self->{charset}->{$codepoint}->{name};
153             }
154              
155             #
156             #
157             # PRIVATE METHODS
158              
159             sub _generate_char_width {
160 234     234   185 my ($self) = @_;
161              
162 234         912 my $name = sprintf("%s.json", lc($self->{font_name}));
163 234         513 my $file = dist_file('PDF-Create', $name);
164 234         33591 my $data = _load_data($file);
165              
166 234         1202 my $sorted_data = [ sort { $a->{codepoint} <=> $b->{codepoint} } @$data ];
  59670         40738  
167 234         260 my $char_width = [];
168 234         330 foreach my $char (@$sorted_data) {
169 59904         44614 push @$char_width, $char->{width};
170             }
171              
172 234         8904 return $char_width;
173             }
174              
175             sub _generate_charset {
176 234     234   257 my ($self) = @_;
177              
178 234         254 my $charset = {};
179 234         221 my $char_width = $self->{char_width};
180              
181 234         311 my $supported_characters = _supported_characters();
182 234         611 foreach my $index (0..$#$char_width) {
183 59904 50       65212 if ($self->{debug}) {
184 0         0 print "Code Point [$index]: ", $supported_characters->[$index]->{code_point};
185 0         0 print "Width: ", $char_width->[$index], "\n";
186             }
187 59904         44056 $supported_characters->[$index]->{char_width} = $char_width->[$index];
188 59904         71274 $charset->{$supported_characters->[$index]->{code_point}} = $supported_characters->[$index];
189             }
190              
191 234         1463 return $charset;
192             }
193              
194             sub _load_data {
195 234     234   281 my ($file) = @_;
196              
197 234         6913 open(my $fh, $file);
198 234         776 local $/;
199 234         5054 my $json = <$fh>;
200 234         643 my $data = from_json($json);
201 234         34988 close($fh);
202              
203 234         1019 return $data;
204             }
205              
206             sub _supported_characters {
207              
208             return [
209             # Control Codes: C0
210 234     234   25134 { code_point => 0, name => 'Null character NUL' },
211             { code_point => 1, name => 'Start of Heading SOH' },
212             { code_point => 2, name => 'Start of Text STX' },
213             { code_point => 3, name => 'End-of-text character ETX' },
214             { code_point => 4, name => 'End-of-transmission character EOT' },
215             { code_point => 5, name => 'Enquiry character ENQ' },
216             { code_point => 6, name => 'Acknowledge character ACK' },
217             { code_point => 7, name => 'Bell character BEL' },
218             { code_point => 8, name => 'Backspace BS' },
219             { code_point => 9, name => 'Horizontal tab HT' },
220             { code_point => 10, name => 'Line feed LF' },
221             { code_point => 11, name => 'Vertical tab VT' },
222             { code_point => 12, name => 'Form feed FF' },
223             { code_point => 13, name => 'Carriage return CR' },
224             { code_point => 14, name => 'Shift Out SO' },
225             { code_point => 15, name => 'Shift In SI' },
226             { code_point => 16, name => 'Data Link Escape DLE' },
227             { code_point => 17, name => 'Device Control 1 DC1' },
228             { code_point => 18, name => 'Device Control 2 DC2' },
229             { code_point => 19, name => 'Device Control 3 DC3' },
230             { code_point => 20, name => 'Device Control 4 DC4' },
231             { code_point => 21, name => 'Negative-acknowledge character NAK' },
232             { code_point => 22, name => 'Synchronous Idle SYN' },
233             { code_point => 23, name => 'End of Transmission Block ETB' },
234             { code_point => 24, name => 'Cancel character CAN' },
235             { code_point => 25, name => 'End of Medium EM' },
236             { code_point => 26, name => 'Substitute character SUB' },
237             { code_point => 27, name => 'Escape character ESC' },
238             { code_point => 28, name => 'File Separator FS' },
239             { code_point => 29, name => 'Group Separator GS' },
240             { code_point => 30, name => 'Record Separator RS' },
241             { code_point => 31, name => 'Unit Separator US' },
242              
243             # ASCII Punctuation & Symbols
244             { code_point => 32, name => 'Space' },
245             { code_point => 33, name => 'Exclamation' },
246             { code_point => 34, name => 'Quotation mark' },
247             { code_point => 35, name => 'Number sign, Hashtag, Octothorpe, Sharp' },
248             { code_point => 36, name => 'Dollar sign' },
249             { code_point => 37, name => 'Percent sign' },
250             { code_point => 38, name => 'Ampersand' },
251             { code_point => 39, name => 'Apostrophe' },
252             { code_point => 40, name => 'Left parenthesis' },
253             { code_point => 41, name => 'Right parenthesis' },
254             { code_point => 42, name => 'Asterisk' },
255             { code_point => 43, name => 'Plus sign' },
256             { code_point => 44, name => 'Comma' },
257             { code_point => 45, name => 'Hyphen-minus' },
258             { code_point => 46, name => 'Full stop' },
259             { code_point => 47, name => 'Slash (Solidus)' },
260             # ASCII Digits
261             { code_point => 48, name => 'Digit Zero' },
262             { code_point => 49, name => 'Digit One' },
263             { code_point => 50, name => 'Digit Two' },
264             { code_point => 51, name => 'Digit Three' },
265             { code_point => 52, name => 'Digit Four' },
266             { code_point => 53, name => 'Digit Five' },
267             { code_point => 54, name => 'Digit Six' },
268             { code_point => 55, name => 'Digit Seven' },
269             { code_point => 56, name => 'Digit Eight' },
270             { code_point => 57, name => 'Digit Nine' },
271             # ASCII Punctuation & Symbols
272             { code_point => 58, name => 'Colon' },
273             { code_point => 59, name => 'Semicolon' },
274             { code_point => 60, name => 'Less-than sign' },
275             { code_point => 61, name => 'Equal sign' },
276             { code_point => 62, name => 'Greater-than sign' },
277             { code_point => 63, name => 'Question mark' },
278             { code_point => 64, name => 'At sign' },
279             # Latin Alphabet: Uppercase
280             { code_point => 65, name => 'Latin Capital letter A' },
281             { code_point => 66, name => 'Latin Capital letter B' },
282             { code_point => 67, name => 'Latin Capital letter C' },
283             { code_point => 68, name => 'Latin Capital letter D' },
284             { code_point => 69, name => 'Latin Capital letter E' },
285             { code_point => 70, name => 'Latin Capital letter F' },
286             { code_point => 71, name => 'Latin Capital letter G' },
287             { code_point => 72, name => 'Latin Capital letter H' },
288             { code_point => 73, name => 'Latin Capital letter I' },
289             { code_point => 74, name => 'Latin Capital letter J' },
290             { code_point => 75, name => 'Latin Capital letter K' },
291             { code_point => 76, name => 'Latin Capital letter L' },
292             { code_point => 77, name => 'Latin Capital letter M' },
293             { code_point => 78, name => 'Latin Capital letter N' },
294             { code_point => 79, name => 'Latin Capital letter O' },
295             { code_point => 80, name => 'Latin Capital letter P' },
296             { code_point => 81, name => 'Latin Capital letter Q' },
297             { code_point => 82, name => 'Latin Capital letter R' },
298             { code_point => 83, name => 'Latin Capital letter S' },
299             { code_point => 84, name => 'Latin Capital letter T' },
300             { code_point => 85, name => 'Latin Capital letter U' },
301             { code_point => 86, name => 'Latin Capital letter V' },
302             { code_point => 87, name => 'Latin Capital letter W' },
303             { code_point => 88, name => 'Latin Capital letter X' },
304             { code_point => 89, name => 'Latin Capital letter Y' },
305             { code_point => 90, name => 'Latin Capital letter Z' },
306             # ASCII Punctuation & Symbols
307             { code_point => 91, name => 'Left Square Bracket' },
308             { code_point => 92, name => 'Backlash' },
309             { code_point => 93, name => 'Right Square Bracket' },
310             { code_point => 94, name => 'Circumflex' },
311             { code_point => 95, name => 'Low line' },
312             { code_point => 96, name => 'Grave' },
313             # Latin Alphabet: Smallcase
314             { code_point => 97, name => 'Latin Small letter a' },
315             { code_point => 98, name => 'Latin Small letter b' },
316             { code_point => 99, name => 'Latin Small letter c' },
317             { code_point => 100, name => 'Latin Small letter d' },
318             { code_point => 101, name => 'Latin Small letter e' },
319             { code_point => 102, name => 'Latin Small letter f' },
320             { code_point => 103, name => 'Latin Small letter g' },
321             { code_point => 104, name => 'Latin Small letter h' },
322             { code_point => 105, name => 'Latin Small letter i' },
323             { code_point => 106, name => 'Latin Small letter j' },
324             { code_point => 107, name => 'Latin Small letter k' },
325             { code_point => 108, name => 'Latin Small letter l' },
326             { code_point => 109, name => 'Latin Small letter m' },
327             { code_point => 110, name => 'Latin Small letter n' },
328             { code_point => 111, name => 'Latin Small letter o' },
329             { code_point => 112, name => 'Latin Small letter p' },
330             { code_point => 113, name => 'Latin Small letter q' },
331             { code_point => 114, name => 'Latin Small letter r' },
332             { code_point => 115, name => 'Latin Small letter s' },
333             { code_point => 116, name => 'Latin Small letter t' },
334             { code_point => 117, name => 'Latin Small letter u' },
335             { code_point => 118, name => 'Latin Small letter v' },
336             { code_point => 119, name => 'Latin Small letter w' },
337             { code_point => 120, name => 'Latin Small letter x' },
338             { code_point => 121, name => 'Latin Small letter y' },
339             { code_point => 122, name => 'Latin Small letter z' },
340             # ASCII Punctuation & Symbols
341             { code_point => 123, name => 'Left Curly Bracket' },
342             { code_point => 124, name => 'Vertical bar' },
343             { code_point => 125, name => 'Right Curly Bracket' },
344             { code_point => 126, name => 'Tilde' },
345             # Control Codes: C1
346             { code_point => 127, name => 'Delete DEL' },
347             { code_point => 128, name => 'Padding Character PAD' },
348             { code_point => 129, name => 'High Octet Preset HOP' },
349             { code_point => 130, name => 'Break Permitted Here BPH' },
350             { code_point => 131, name => 'No Break Here NBH' },
351             { code_point => 132, name => 'Index IND' },
352             { code_point => 133, name => 'Next Line NEL' },
353             { code_point => 134, name => 'Start of Selected Area SSA' },
354             { code_point => 135, name => 'End of Selected Area ESA' },
355             { code_point => 136, name => 'Character Tabulation Set HTS' },
356             { code_point => 137, name => 'Character Tabulation with Justification HTJ' },
357             { code_point => 138, name => 'Line Tabulation Set VTS' },
358             { code_point => 139, name => 'Partial Line Forward PLD' },
359             { code_point => 140, name => 'Partial Line Backward PLU' },
360             { code_point => 141, name => 'Reverse Line Feed RI' },
361             { code_point => 142, name => 'Single-Shift Two SS2' },
362             { code_point => 143, name => 'Single-Shift Three SS3' },
363             { code_point => 144, name => 'Device Control String DCS' },
364             { code_point => 145, name => 'Private Use 1 PU1' },
365             { code_point => 146, name => 'Private Use 2 PU2' },
366             { code_point => 147, name => 'Set Transmit State STS' },
367             { code_point => 148, name => 'Cancel character CCH' },
368             { code_point => 149, name => 'Message Waiting MW' },
369             { code_point => 150, name => 'Start of Protected Area SPA' },
370             { code_point => 151, name => 'End of Protected Area EPA' },
371             { code_point => 152, name => 'Start of String SOS' },
372             { code_point => 153, name => 'Single Graphic Character Introducer SGCI' },
373             { code_point => 154, name => 'Single Character Intro Introducer SCI' },
374             { code_point => 155, name => 'Control Sequence Introducer CSI' },
375             { code_point => 156, name => 'String Terminator ST' },
376             { code_point => 157, name => 'Operating System Command OSC' },
377             { code_point => 158, name => 'Private Message PM' },
378             { code_point => 159, name => 'Application Program Command APC' },
379              
380             # Latin-1 Punctuation & Symbols
381             { code_point => 160, name => 'Non-breaking space' },
382             { code_point => 161, name => 'Inverted Exclamation Mark' },
383             { code_point => 162, name => 'Cent sign' },
384             { code_point => 163, name => 'Pound sign' },
385             { code_point => 164, name => 'Currency sign' },
386             { code_point => 165, name => 'Yen sign' },
387             { code_point => 166, name => 'Broken bar' },
388             { code_point => 167, name => 'Section sign' },
389             { code_point => 168, name => 'Diaeresis (Umlaut)' },
390             { code_point => 169, name => 'Copyright sign' },
391             { code_point => 170, name => 'Feminine Ordinal Indicator' },
392             { code_point => 171, name => 'Left-pointing double angle quotation mark' },
393             { code_point => 172, name => 'Not sign' },
394             { code_point => 173, name => 'Soft hyphen' },
395             { code_point => 174, name => 'Registered sign' },
396             { code_point => 175, name => 'Macron' },
397             { code_point => 176, name => 'Degree symbol' },
398             { code_point => 177, name => 'Plus-minus sign' },
399             { code_point => 178, name => 'Superscript two' },
400             { code_point => 179, name => 'Superscript three' },
401             { code_point => 180, name => 'Acute accent' },
402             { code_point => 181, name => 'Micro sign' },
403             { code_point => 182, name => 'Pilcrow sign' },
404             { code_point => 183, name => 'Middle dot' },
405             { code_point => 184, name => 'Cedilla' },
406             { code_point => 185, name => 'Superscript one' },
407             { code_point => 186, name => 'Masculine ordinal indicator' },
408             { code_point => 187, name => 'Right-pointing double angle quotation mark' },
409             { code_point => 188, name => 'Vulgar fraction one quarter' },
410             { code_point => 189, name => 'Vulgar fraction one half' },
411             { code_point => 190, name => 'Vulgar fraction three quarters' },
412             { code_point => 191, name => 'Inverted Question Mark' },
413             # Latin-1 Letter: Uppercase
414             { code_point => 192, name => 'Latin Capital Letter A with grave' },
415             { code_point => 193, name => 'Latin Capital letter A with acute' },
416             { code_point => 194, name => 'Latin Capital letter A with circumflex' },
417             { code_point => 195, name => 'Latin Capital letter A with tilde' },
418             { code_point => 196, name => 'Latin Capital letter A with diaeresis' },
419             { code_point => 197, name => 'Latin Capital letter A with ring above' },
420             { code_point => 198, name => 'Latin Capital letter Æ' },
421             { code_point => 199, name => 'Latin Capital letter C with cedilla' },
422             { code_point => 200, name => 'Latin Capital letter E with grave' },
423             { code_point => 201, name => 'Latin Capital letter E with acute' },
424             { code_point => 202, name => 'Latin Capital letter E with circumflex' },
425             { code_point => 203, name => 'Latin Capital letter E with diaeresis' },
426             { code_point => 204, name => 'Latin Capital letter I with grave' },
427             { code_point => 205, name => 'Latin Capital letter I with acute' },
428             { code_point => 206, name => 'Latin Capital letter I with circumflex' },
429             { code_point => 207, name => 'Latin Capital letter I with diaeresis' },
430             { code_point => 208, name => 'Latin Capital letter Eth' },
431             { code_point => 209, name => 'Latin Capital letter N with tilde' },
432             { code_point => 210, name => 'Latin Capital letter O with grave' },
433             { code_point => 211, name => 'Latin Capital letter O with acute' },
434             { code_point => 212, name => 'Latin Capital letter O with circumflex' },
435             { code_point => 213, name => 'Latin Capital letter O with tilde' },
436             { code_point => 214, name => 'Latin Capital letter O with diaeresis' },
437             # Latin-1: Math
438             { code_point => 215, name => 'Multiplication sign' },
439             # Latin-1 Letter: Uppercase
440             { code_point => 216, name => 'Latin Capital letter O with stroke' },
441             { code_point => 217, name => 'Latin Capital letter U with grave' },
442             { code_point => 218, name => 'Latin Capital letter U with acute' },
443             { code_point => 219, name => 'Latin Capital Letter U with circumflex' },
444             { code_point => 220, name => 'Latin Capital Letter U with diaeresis' },
445             { code_point => 221, name => 'Latin Capital Letter Y with acute' },
446             { code_point => 222, name => 'Latin Capital Letter Thorn' },
447             # Latin-1 Letter: Lowercase
448             { code_point => 223, name => 'Latin Small Letter sharp' },
449             { code_point => 224, name => 'Latin Small Letter A with grave' },
450             { code_point => 225, name => 'Latin Small Letter A with acute' },
451             { code_point => 226, name => 'Latin Small Letter A with circumflex' },
452             { code_point => 227, name => 'Latin Small Letter A with tilde' },
453             { code_point => 228, name => 'Latin Small Letter A with diaeresis' },
454             { code_point => 229, name => 'Latin Small Letter A with ring above' },
455             { code_point => 230, name => 'Latin Small Letter Æ' },
456             { code_point => 231, name => 'Latin Small Letter C with cedilla' },
457             { code_point => 232, name => 'Latin Small Letter E with grave' },
458             { code_point => 233, name => 'Latin Small Letter E with acute' },
459             { code_point => 234, name => 'Latin Small Letter E with circumflex' },
460             { code_point => 235, name => 'Latin Small Letter E with diaeresis' },
461             { code_point => 236, name => 'Latin Small Letter I with grave' },
462             { code_point => 237, name => 'Latin Small Letter I with acute' },
463             { code_point => 238, name => 'Latin Small Letter I with circumflex' },
464             { code_point => 239, name => 'Latin Small Letter I with diaeresis' },
465             { code_point => 240, name => 'Latin Small Letter Eth' },
466             { code_point => 241, name => 'Latin Small Letter N with tilde' },
467             { code_point => 242, name => 'Latin Small Letter O with grave' },
468             { code_point => 243, name => 'Latin Small Letter O with acute' },
469             { code_point => 244, name => 'Latin Small Letter O with circumflex' },
470             { code_point => 245, name => 'Latin Small Letter O with tilde' },
471             { code_point => 246, name => 'Latin Small Letter O with diaeresis' },
472             # Latin-1: Math
473             { code_point => 247, name => 'Division sign' },
474             # Latin-1 Letter: Lowercase
475             { code_point => 248, name => 'Latin Small Letter O with stroke' },
476             { code_point => 249, name => 'Latin Small Letter U with grave' },
477             { code_point => 250, name => 'Latin Small Letter U with acute' },
478             { code_point => 251, name => 'Latin Small Letter U with circumflex' },
479             { code_point => 252, name => 'Latin Small Letter U with diaeresis' },
480             { code_point => 253, name => 'Latin Small Letter Y with acute' },
481             { code_point => 254, name => 'Latin Small Letter Thorn' },
482             { code_point => 255, name => 'Latin Small Letter Y with diaeresis' },
483             ];
484             }
485              
486             =head1 AUTHORS
487              
488             Mohammad S Anwar (MANWAR) C<< >>
489              
490             =head1 REPOSITORY
491              
492             L
493              
494             =head1 COPYRIGHT
495              
496             Copyright 1999-2001,Fabien Tassin.All rights reserved.It may be used and modified
497             freely, but I do request that this copyright notice remain attached to the file.
498             You may modify this module as you wish,but if you redistribute a modified version
499             , please attach a note listing the modifications you have made.
500              
501             Copyright 2007 Markus Baertschi
502              
503             Copyright 2010 Gary Lieberman
504              
505             =head1 LICENSE
506              
507             This is free software; you can redistribute it and / or modify it under the same
508             terms as Perl 5.6.0.
509              
510             =cut
511              
512             1; # End of PDF::Font