Class: Fontisan::Type1Font
- Inherits:
-
Object
- Object
- Fontisan::Type1Font
- Defined in:
- lib/fontisan/type1_font.rb
Overview
Adobe Type 1 Font handler
[‘Type1Font`](lib/fontisan/type1_font.rb) provides parsing and conversion capabilities for Adobe Type 1 fonts in PFB (Printer Font Binary) and PFA (Printer Font ASCII) formats.
Type 1 fonts were the standard for digital typography in the 1980s-1990s and consist of:
-
Font dictionary with metadata (FontInfo, FontName, Encoding, etc.)
-
Private dictionary with hinting and spacing information
-
CharStrings (glyph outline descriptions)
-
eexec encryption for protection
Instance Attribute Summary collapse
-
#charstrings ⇒ CharStrings?
readonly
CharStrings dictionary.
-
#decrypted_data ⇒ String?
readonly
Decrypted font data.
-
#file_path ⇒ String?
readonly
File path if loaded from file.
-
#font_dictionary ⇒ FontDictionary?
readonly
Font dictionary.
-
#format ⇒ Symbol
readonly
Format type (:pfb or :pfa).
-
#private_dict ⇒ PrivateDict?
readonly
Private dictionary.
Class Method Summary collapse
-
.from_file(file_path) ⇒ Type1Font
Load Type 1 font from file.
Instance Method Summary collapse
-
#clear_text ⇒ String
Get clear text portion (before eexec).
-
#decrypt! ⇒ String
Decrypt the font if not already decrypted.
-
#decrypted? ⇒ Boolean
Check if font has been decrypted.
-
#encrypted? ⇒ Boolean
Check if font is encrypted.
-
#encrypted_portion ⇒ String
Get encrypted portion (as hex string for PFA).
-
#family_name ⇒ String?
Get family name from FontInfo.
-
#font_name ⇒ String?
Get font name from font dictionary.
-
#full_name ⇒ String?
Get full name from FontInfo.
-
#glyph_names ⇒ Array<String>
Get list of glyph names.
-
#initialize(data, format: nil, file_path: nil) ⇒ Type1Font
constructor
Initialize a new Type1Font instance.
-
#parse_dictionaries! ⇒ void
Parse font dictionaries from decrypted data.
-
#parsed_dictionaries? ⇒ Boolean
Check if dictionaries have been parsed.
-
#version ⇒ String?
Get version from FontInfo.
Constructor Details
#initialize(data, format: nil, file_path: nil) ⇒ Type1Font
Initialize a new Type1Font instance
57 58 59 60 61 62 63 |
# File 'lib/fontisan/type1_font.rb', line 57 def initialize(data, format: nil, file_path: nil) @file_path = file_path @format = format || detect_format(data) @data = data parse_font_data end |
Instance Attribute Details
#charstrings ⇒ CharStrings? (readonly)
Returns CharStrings dictionary.
50 51 52 |
# File 'lib/fontisan/type1_font.rb', line 50 def charstrings @charstrings end |
#decrypted_data ⇒ String? (readonly)
Returns Decrypted font data.
41 42 43 |
# File 'lib/fontisan/type1_font.rb', line 41 def decrypted_data @decrypted_data end |
#file_path ⇒ String? (readonly)
Returns File path if loaded from file.
35 36 37 |
# File 'lib/fontisan/type1_font.rb', line 35 def file_path @file_path end |
#font_dictionary ⇒ FontDictionary? (readonly)
Returns Font dictionary.
44 45 46 |
# File 'lib/fontisan/type1_font.rb', line 44 def font_dictionary @font_dictionary end |
#format ⇒ Symbol (readonly)
Returns Format type (:pfb or :pfa).
38 39 40 |
# File 'lib/fontisan/type1_font.rb', line 38 def format @format end |
#private_dict ⇒ PrivateDict? (readonly)
Returns Private dictionary.
47 48 49 |
# File 'lib/fontisan/type1_font.rb', line 47 def private_dict @private_dict end |
Class Method Details
.from_file(file_path) ⇒ Type1Font
Load Type 1 font from file
77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/fontisan/type1_font.rb', line 77 def self.from_file(file_path) raise ArgumentError, "File path cannot be nil" if file_path.nil? unless File.exist?(file_path) raise Fontisan::Error, "File not found: #{file_path}" end # Read file data = File.binread(file_path) new(data, file_path: file_path) end |
Instance Method Details
#clear_text ⇒ String
Get clear text portion (before eexec)
93 94 95 |
# File 'lib/fontisan/type1_font.rb', line 93 def clear_text @clear_text ||= "" end |
#decrypt! ⇒ String
Decrypt the font if not already decrypted
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
# File 'lib/fontisan/type1_font.rb', line 149 def decrypt! return @decrypted_data if decrypted? if @encrypted_portion.nil? || @encrypted_portion.empty? @decrypted_data = @clear_text else encrypted_binary = if @format == :pfa # Convert hex string to binary [@encrypted_portion.gsub(/\s/, "")].pack("H*") else @encrypted_portion end @decrypted_data = @clear_text + Type1::Decryptor.eexec_decrypt(encrypted_binary) end @decrypted_data end |
#decrypted? ⇒ Boolean
Check if font has been decrypted
135 136 137 |
# File 'lib/fontisan/type1_font.rb', line 135 def decrypted? !@decrypted_data.nil? end |
#encrypted? ⇒ Boolean
Check if font is encrypted
142 143 144 |
# File 'lib/fontisan/type1_font.rb', line 142 def encrypted? !@encrypted_portion.nil? && !@encrypted_portion.empty? end |
#encrypted_portion ⇒ String
Get encrypted portion (as hex string for PFA)
100 101 102 |
# File 'lib/fontisan/type1_font.rb', line 100 def encrypted_portion @encrypted_portion ||= "" end |
#family_name ⇒ String?
Get family name from FontInfo
121 122 123 |
# File 'lib/fontisan/type1_font.rb', line 121 def family_name extract_fontinfo_value("FamilyName") end |
#font_name ⇒ String?
Get font name from font dictionary
107 108 109 |
# File 'lib/fontisan/type1_font.rb', line 107 def font_name extract_dictionary_value("/FontName") end |
#full_name ⇒ String?
Get full name from FontInfo
114 115 116 |
# File 'lib/fontisan/type1_font.rb', line 114 def full_name extract_fontinfo_value("FullName") end |
#glyph_names ⇒ Array<String>
Get list of glyph names
227 228 229 230 231 |
# File 'lib/fontisan/type1_font.rb', line 227 def glyph_names return [] unless @charstrings @charstrings.glyph_names end |
#parse_dictionaries! ⇒ void
This method returns an undefined value.
Parse font dictionaries from decrypted data
Parses the font dictionary, private dictionary, and CharStrings from the decrypted font data.
175 176 177 178 179 180 181 182 183 184 185 186 |
# File 'lib/fontisan/type1_font.rb', line 175 def parse_dictionaries! decrypt! unless decrypted? # Parse font dictionary @font_dictionary = Type1::FontDictionary.parse(@decrypted_data) # Parse private dictionary @private_dict = Type1::PrivateDict.parse(@decrypted_data) # Parse CharStrings @charstrings = Type1::CharStrings.parse(@decrypted_data, @private_dict) end |
#parsed_dictionaries? ⇒ Boolean
Check if dictionaries have been parsed
236 237 238 |
# File 'lib/fontisan/type1_font.rb', line 236 def parsed_dictionaries? !@font_dictionary.nil? end |
#version ⇒ String?
Get version from FontInfo
128 129 130 |
# File 'lib/fontisan/type1_font.rb', line 128 def version extract_fontinfo_value("version") end |