package PDF::Font; our $VERSION = '1.46'; =head1 NAME PDF::Font - Base font class for PDF::Create. =head1 VERSION Version 1.46 =cut use 5.006; use strict; use warnings; use utf8; use Carp qw(croak); use Data::Dumper; use JSON; use File::Share ':all'; =encoding utf8 =head1 DESCRIPTION Base font class to support font families approved by L. This is used in the method C inside the package L. =head1 SYNOPSIS use strict; use warnings; use PDF::Font; my $font = PDF::Font->new('Helvetica'); my $char_widths = $font->char_width; print "Character width: ", $font->get_char_width(ord('A')), "\n"; print "Character name: ", $font->get_char_name(ord('A')) , "\n"; =head1 CONSTRUCTOR Expects C as the only parameter. It can be one of the following names: =over 4 =item * Courier =item * Courier-Bold =item * Courier-BoldOblique =item * Courier-Oblique =item * Helvetica =item * Helvetica-Bold =item * Helvetica-BoldOblique =item * Helvetica-Oblique =item * Times-Bold =item * Times-BoldItalic =item * Times-Italic =item * Times-Roman =item * Symbol =back =cut our $DEBUG = 0; our $SUPPORTED_FONTS = { 'Courier' => 1, 'Courier-Bold' => 1, 'Courier-BoldOblique' => 1, 'Courier-Oblique' => 1, 'Helvetica' => 1, 'Helvetica-Bold' => 1, 'Helvetica-BoldOblique' => 1, 'Helvetica-Oblique' => 1, 'Times-Bold' => 1, 'Times-BoldItalic' => 1, 'Times-Italic' => 1, 'Times-Roman' => 1, 'Symbol' => 1, }; sub new { my ($class, $font_name) = @_; croak "Missing font name." unless defined $font_name; croak "Invalid font name [$font_name]." unless (exists $SUPPORTED_FONTS->{$font_name}); my $self = { debug => $DEBUG, font_name => $font_name }; bless $self, $class; $self->{char_width} = $self->_generate_char_width; $self->{charset} = $self->_generate_charset; return $self; } =head1 METHODS =head2 char_width() Returns arrayref of all characters width (0..255). =cut sub char_width { my ($self) = @_; return $self->{char_width}; } =head2 get_char_width($codepoint) Returns the character width for the given C<$codepoint>. =cut sub get_char_width { my ($self, $codepoint) = @_; croak "Invalid codepoint [$codepoint] received." unless (exists $self->{charset}->{$codepoint}); return $self->{charset}->{$codepoint}->{char_width}; } =head2 get_char_name($codepoint) Returns the character name for the given C<$codepoint>. =cut sub get_char_name { my ($self, $codepoint) = @_; croak "Invalid codepoint [$codepoint] received." unless (exists $self->{charset}->{$codepoint}); return $self->{charset}->{$codepoint}->{name}; } # # # PRIVATE METHODS sub _generate_char_width { my ($self) = @_; my $name = sprintf("%s.json", lc($self->{font_name})); my $file = dist_file('PDF-Create', $name); my $data = _load_data($file); my $sorted_data = [ sort { $a->{codepoint} <=> $b->{codepoint} } @$data ]; my $char_width = []; foreach my $char (@$sorted_data) { push @$char_width, $char->{width}; } return $char_width; } sub _generate_charset { my ($self) = @_; my $charset = {}; my $char_width = $self->{char_width}; my $supported_characters = _supported_characters(); foreach my $index (0..$#$char_width) { if ($self->{debug}) { print "Code Point [$index]: ", $supported_characters->[$index]->{code_point}; print "Width: ", $char_width->[$index], "\n"; } $supported_characters->[$index]->{char_width} = $char_width->[$index]; $charset->{$supported_characters->[$index]->{code_point}} = $supported_characters->[$index]; } return $charset; } sub _load_data { my ($file) = @_; open(my $fh, $file); local $/; my $json = <$fh>; my $data = from_json($json); close($fh); return $data; } sub _supported_characters { return [ # Control Codes: C0 { code_point => 0, name => 'Null character NUL' }, { code_point => 1, name => 'Start of Heading SOH' }, { code_point => 2, name => 'Start of Text STX' }, { code_point => 3, name => 'End-of-text character ETX' }, { code_point => 4, name => 'End-of-transmission character EOT' }, { code_point => 5, name => 'Enquiry character ENQ' }, { code_point => 6, name => 'Acknowledge character ACK' }, { code_point => 7, name => 'Bell character BEL' }, { code_point => 8, name => 'Backspace BS' }, { code_point => 9, name => 'Horizontal tab HT' }, { code_point => 10, name => 'Line feed LF' }, { code_point => 11, name => 'Vertical tab VT' }, { code_point => 12, name => 'Form feed FF' }, { code_point => 13, name => 'Carriage return CR' }, { code_point => 14, name => 'Shift Out SO' }, { code_point => 15, name => 'Shift In SI' }, { code_point => 16, name => 'Data Link Escape DLE' }, { code_point => 17, name => 'Device Control 1 DC1' }, { code_point => 18, name => 'Device Control 2 DC2' }, { code_point => 19, name => 'Device Control 3 DC3' }, { code_point => 20, name => 'Device Control 4 DC4' }, { code_point => 21, name => 'Negative-acknowledge character NAK' }, { code_point => 22, name => 'Synchronous Idle SYN' }, { code_point => 23, name => 'End of Transmission Block ETB' }, { code_point => 24, name => 'Cancel character CAN' }, { code_point => 25, name => 'End of Medium EM' }, { code_point => 26, name => 'Substitute character SUB' }, { code_point => 27, name => 'Escape character ESC' }, { code_point => 28, name => 'File Separator FS' }, { code_point => 29, name => 'Group Separator GS' }, { code_point => 30, name => 'Record Separator RS' }, { code_point => 31, name => 'Unit Separator US' }, # ASCII Punctuation & Symbols { code_point => 32, name => 'Space' }, { code_point => 33, name => 'Exclamation' }, { code_point => 34, name => 'Quotation mark' }, { code_point => 35, name => 'Number sign, Hashtag, Octothorpe, Sharp' }, { code_point => 36, name => 'Dollar sign' }, { code_point => 37, name => 'Percent sign' }, { code_point => 38, name => 'Ampersand' }, { code_point => 39, name => 'Apostrophe' }, { code_point => 40, name => 'Left parenthesis' }, { code_point => 41, name => 'Right parenthesis' }, { code_point => 42, name => 'Asterisk' }, { code_point => 43, name => 'Plus sign' }, { code_point => 44, name => 'Comma' }, { code_point => 45, name => 'Hyphen-minus' }, { code_point => 46, name => 'Full stop' }, { code_point => 47, name => 'Slash (Solidus)' }, # ASCII Digits { code_point => 48, name => 'Digit Zero' }, { code_point => 49, name => 'Digit One' }, { code_point => 50, name => 'Digit Two' }, { code_point => 51, name => 'Digit Three' }, { code_point => 52, name => 'Digit Four' }, { code_point => 53, name => 'Digit Five' }, { code_point => 54, name => 'Digit Six' }, { code_point => 55, name => 'Digit Seven' }, { code_point => 56, name => 'Digit Eight' }, { code_point => 57, name => 'Digit Nine' }, # ASCII Punctuation & Symbols { code_point => 58, name => 'Colon' }, { code_point => 59, name => 'Semicolon' }, { code_point => 60, name => 'Less-than sign' }, { code_point => 61, name => 'Equal sign' }, { code_point => 62, name => 'Greater-than sign' }, { code_point => 63, name => 'Question mark' }, { code_point => 64, name => 'At sign' }, # Latin Alphabet: Uppercase { code_point => 65, name => 'Latin Capital letter A' }, { code_point => 66, name => 'Latin Capital letter B' }, { code_point => 67, name => 'Latin Capital letter C' }, { code_point => 68, name => 'Latin Capital letter D' }, { code_point => 69, name => 'Latin Capital letter E' }, { code_point => 70, name => 'Latin Capital letter F' }, { code_point => 71, name => 'Latin Capital letter G' }, { code_point => 72, name => 'Latin Capital letter H' }, { code_point => 73, name => 'Latin Capital letter I' }, { code_point => 74, name => 'Latin Capital letter J' }, { code_point => 75, name => 'Latin Capital letter K' }, { code_point => 76, name => 'Latin Capital letter L' }, { code_point => 77, name => 'Latin Capital letter M' }, { code_point => 78, name => 'Latin Capital letter N' }, { code_point => 79, name => 'Latin Capital letter O' }, { code_point => 80, name => 'Latin Capital letter P' }, { code_point => 81, name => 'Latin Capital letter Q' }, { code_point => 82, name => 'Latin Capital letter R' }, { code_point => 83, name => 'Latin Capital letter S' }, { code_point => 84, name => 'Latin Capital letter T' }, { code_point => 85, name => 'Latin Capital letter U' }, { code_point => 86, name => 'Latin Capital letter V' }, { code_point => 87, name => 'Latin Capital letter W' }, { code_point => 88, name => 'Latin Capital letter X' }, { code_point => 89, name => 'Latin Capital letter Y' }, { code_point => 90, name => 'Latin Capital letter Z' }, # ASCII Punctuation & Symbols { code_point => 91, name => 'Left Square Bracket' }, { code_point => 92, name => 'Backlash' }, { code_point => 93, name => 'Right Square Bracket' }, { code_point => 94, name => 'Circumflex' }, { code_point => 95, name => 'Low line' }, { code_point => 96, name => 'Grave' }, # Latin Alphabet: Smallcase { code_point => 97, name => 'Latin Small letter a' }, { code_point => 98, name => 'Latin Small letter b' }, { code_point => 99, name => 'Latin Small letter c' }, { code_point => 100, name => 'Latin Small letter d' }, { code_point => 101, name => 'Latin Small letter e' }, { code_point => 102, name => 'Latin Small letter f' }, { code_point => 103, name => 'Latin Small letter g' }, { code_point => 104, name => 'Latin Small letter h' }, { code_point => 105, name => 'Latin Small letter i' }, { code_point => 106, name => 'Latin Small letter j' }, { code_point => 107, name => 'Latin Small letter k' }, { code_point => 108, name => 'Latin Small letter l' }, { code_point => 109, name => 'Latin Small letter m' }, { code_point => 110, name => 'Latin Small letter n' }, { code_point => 111, name => 'Latin Small letter o' }, { code_point => 112, name => 'Latin Small letter p' }, { code_point => 113, name => 'Latin Small letter q' }, { code_point => 114, name => 'Latin Small letter r' }, { code_point => 115, name => 'Latin Small letter s' }, { code_point => 116, name => 'Latin Small letter t' }, { code_point => 117, name => 'Latin Small letter u' }, { code_point => 118, name => 'Latin Small letter v' }, { code_point => 119, name => 'Latin Small letter w' }, { code_point => 120, name => 'Latin Small letter x' }, { code_point => 121, name => 'Latin Small letter y' }, { code_point => 122, name => 'Latin Small letter z' }, # ASCII Punctuation & Symbols { code_point => 123, name => 'Left Curly Bracket' }, { code_point => 124, name => 'Vertical bar' }, { code_point => 125, name => 'Right Curly Bracket' }, { code_point => 126, name => 'Tilde' }, # Control Codes: C1 { code_point => 127, name => 'Delete DEL' }, { code_point => 128, name => 'Padding Character PAD' }, { code_point => 129, name => 'High Octet Preset HOP' }, { code_point => 130, name => 'Break Permitted Here BPH' }, { code_point => 131, name => 'No Break Here NBH' }, { code_point => 132, name => 'Index IND' }, { code_point => 133, name => 'Next Line NEL' }, { code_point => 134, name => 'Start of Selected Area SSA' }, { code_point => 135, name => 'End of Selected Area ESA' }, { code_point => 136, name => 'Character Tabulation Set HTS' }, { code_point => 137, name => 'Character Tabulation with Justification HTJ' }, { code_point => 138, name => 'Line Tabulation Set VTS' }, { code_point => 139, name => 'Partial Line Forward PLD' }, { code_point => 140, name => 'Partial Line Backward PLU' }, { code_point => 141, name => 'Reverse Line Feed RI' }, { code_point => 142, name => 'Single-Shift Two SS2' }, { code_point => 143, name => 'Single-Shift Three SS3' }, { code_point => 144, name => 'Device Control String DCS' }, { code_point => 145, name => 'Private Use 1 PU1' }, { code_point => 146, name => 'Private Use 2 PU2' }, { code_point => 147, name => 'Set Transmit State STS' }, { code_point => 148, name => 'Cancel character CCH' }, { code_point => 149, name => 'Message Waiting MW' }, { code_point => 150, name => 'Start of Protected Area SPA' }, { code_point => 151, name => 'End of Protected Area EPA' }, { code_point => 152, name => 'Start of String SOS' }, { code_point => 153, name => 'Single Graphic Character Introducer SGCI' }, { code_point => 154, name => 'Single Character Intro Introducer SCI' }, { code_point => 155, name => 'Control Sequence Introducer CSI' }, { code_point => 156, name => 'String Terminator ST' }, { code_point => 157, name => 'Operating System Command OSC' }, { code_point => 158, name => 'Private Message PM' }, { code_point => 159, name => 'Application Program Command APC' }, # Latin-1 Punctuation & Symbols { code_point => 160, name => 'Non-breaking space' }, { code_point => 161, name => 'Inverted Exclamation Mark' }, { code_point => 162, name => 'Cent sign' }, { code_point => 163, name => 'Pound sign' }, { code_point => 164, name => 'Currency sign' }, { code_point => 165, name => 'Yen sign' }, { code_point => 166, name => 'Broken bar' }, { code_point => 167, name => 'Section sign' }, { code_point => 168, name => 'Diaeresis (Umlaut)' }, { code_point => 169, name => 'Copyright sign' }, { code_point => 170, name => 'Feminine Ordinal Indicator' }, { code_point => 171, name => 'Left-pointing double angle quotation mark' }, { code_point => 172, name => 'Not sign' }, { code_point => 173, name => 'Soft hyphen' }, { code_point => 174, name => 'Registered sign' }, { code_point => 175, name => 'Macron' }, { code_point => 176, name => 'Degree symbol' }, { code_point => 177, name => 'Plus-minus sign' }, { code_point => 178, name => 'Superscript two' }, { code_point => 179, name => 'Superscript three' }, { code_point => 180, name => 'Acute accent' }, { code_point => 181, name => 'Micro sign' }, { code_point => 182, name => 'Pilcrow sign' }, { code_point => 183, name => 'Middle dot' }, { code_point => 184, name => 'Cedilla' }, { code_point => 185, name => 'Superscript one' }, { code_point => 186, name => 'Masculine ordinal indicator' }, { code_point => 187, name => 'Right-pointing double angle quotation mark' }, { code_point => 188, name => 'Vulgar fraction one quarter' }, { code_point => 189, name => 'Vulgar fraction one half' }, { code_point => 190, name => 'Vulgar fraction three quarters' }, { code_point => 191, name => 'Inverted Question Mark' }, # Latin-1 Letter: Uppercase { code_point => 192, name => 'Latin Capital Letter A with grave' }, { code_point => 193, name => 'Latin Capital letter A with acute' }, { code_point => 194, name => 'Latin Capital letter A with circumflex' }, { code_point => 195, name => 'Latin Capital letter A with tilde' }, { code_point => 196, name => 'Latin Capital letter A with diaeresis' }, { code_point => 197, name => 'Latin Capital letter A with ring above' }, { code_point => 198, name => 'Latin Capital letter Æ' }, { code_point => 199, name => 'Latin Capital letter C with cedilla' }, { code_point => 200, name => 'Latin Capital letter E with grave' }, { code_point => 201, name => 'Latin Capital letter E with acute' }, { code_point => 202, name => 'Latin Capital letter E with circumflex' }, { code_point => 203, name => 'Latin Capital letter E with diaeresis' }, { code_point => 204, name => 'Latin Capital letter I with grave' }, { code_point => 205, name => 'Latin Capital letter I with acute' }, { code_point => 206, name => 'Latin Capital letter I with circumflex' }, { code_point => 207, name => 'Latin Capital letter I with diaeresis' }, { code_point => 208, name => 'Latin Capital letter Eth' }, { code_point => 209, name => 'Latin Capital letter N with tilde' }, { code_point => 210, name => 'Latin Capital letter O with grave' }, { code_point => 211, name => 'Latin Capital letter O with acute' }, { code_point => 212, name => 'Latin Capital letter O with circumflex' }, { code_point => 213, name => 'Latin Capital letter O with tilde' }, { code_point => 214, name => 'Latin Capital letter O with diaeresis' }, # Latin-1: Math { code_point => 215, name => 'Multiplication sign' }, # Latin-1 Letter: Uppercase { code_point => 216, name => 'Latin Capital letter O with stroke' }, { code_point => 217, name => 'Latin Capital letter U with grave' }, { code_point => 218, name => 'Latin Capital letter U with acute' }, { code_point => 219, name => 'Latin Capital Letter U with circumflex' }, { code_point => 220, name => 'Latin Capital Letter U with diaeresis' }, { code_point => 221, name => 'Latin Capital Letter Y with acute' }, { code_point => 222, name => 'Latin Capital Letter Thorn' }, # Latin-1 Letter: Lowercase { code_point => 223, name => 'Latin Small Letter sharp' }, { code_point => 224, name => 'Latin Small Letter A with grave' }, { code_point => 225, name => 'Latin Small Letter A with acute' }, { code_point => 226, name => 'Latin Small Letter A with circumflex' }, { code_point => 227, name => 'Latin Small Letter A with tilde' }, { code_point => 228, name => 'Latin Small Letter A with diaeresis' }, { code_point => 229, name => 'Latin Small Letter A with ring above' }, { code_point => 230, name => 'Latin Small Letter Æ' }, { code_point => 231, name => 'Latin Small Letter C with cedilla' }, { code_point => 232, name => 'Latin Small Letter E with grave' }, { code_point => 233, name => 'Latin Small Letter E with acute' }, { code_point => 234, name => 'Latin Small Letter E with circumflex' }, { code_point => 235, name => 'Latin Small Letter E with diaeresis' }, { code_point => 236, name => 'Latin Small Letter I with grave' }, { code_point => 237, name => 'Latin Small Letter I with acute' }, { code_point => 238, name => 'Latin Small Letter I with circumflex' }, { code_point => 239, name => 'Latin Small Letter I with diaeresis' }, { code_point => 240, name => 'Latin Small Letter Eth' }, { code_point => 241, name => 'Latin Small Letter N with tilde' }, { code_point => 242, name => 'Latin Small Letter O with grave' }, { code_point => 243, name => 'Latin Small Letter O with acute' }, { code_point => 244, name => 'Latin Small Letter O with circumflex' }, { code_point => 245, name => 'Latin Small Letter O with tilde' }, { code_point => 246, name => 'Latin Small Letter O with diaeresis' }, # Latin-1: Math { code_point => 247, name => 'Division sign' }, # Latin-1 Letter: Lowercase { code_point => 248, name => 'Latin Small Letter O with stroke' }, { code_point => 249, name => 'Latin Small Letter U with grave' }, { code_point => 250, name => 'Latin Small Letter U with acute' }, { code_point => 251, name => 'Latin Small Letter U with circumflex' }, { code_point => 252, name => 'Latin Small Letter U with diaeresis' }, { code_point => 253, name => 'Latin Small Letter Y with acute' }, { code_point => 254, name => 'Latin Small Letter Thorn' }, { code_point => 255, name => 'Latin Small Letter Y with diaeresis' }, ]; } =head1 AUTHORS Mohammad S Anwar (MANWAR) C<< >> =head1 REPOSITORY L =head1 COPYRIGHT Copyright 1999-2001,Fabien Tassin.All rights reserved.It may be used and modified freely, but I do request that this copyright notice remain attached to the file. You may modify this module as you wish,but if you redistribute a modified version , please attach a note listing the modifications you have made. Copyright 2007 Markus Baertschi Copyright 2010 Gary Lieberman =head1 LICENSE This is free software; you can redistribute it and / or modify it under the same terms as Perl 5.6.0. =cut 1; # End of PDF::Font