Class: Fontisan::Type1Font
- Inherits:
-
Object
- Object
- Fontisan::Type1Font
- Defined in:
- lib/fontisan/type1_font.rb
Overview
Adobe Type 1 Font handler
Type1Font 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
-
#container_format ⇒ Symbol
readonly
Container variant (:pfb or :pfa) — the on-disk encoding of a Type 1 font (binary vs ASCII).
-
#decrypted_data ⇒ String?
readonly
Decrypted font data.
-
#file_path ⇒ String?
readonly
File path if loaded from file.
-
#loading_mode ⇒ Symbol
readonly
Loading mode (:metadata or :full).
Class Method Summary collapse
-
.from_file(file_path, mode: :full) ⇒ Type1Font
Load Type 1 font from file.
Instance Method Summary collapse
-
#charstrings ⇒ CharStrings?
CharStrings dictionary.
-
#clear_text ⇒ String
Get clear text portion (before eexec).
-
#collection? ⇒ Boolean
Whether this object represents a font collection rather than a single font.
-
#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_dictionary ⇒ FontDictionary?
Font dictionary.
-
#font_name ⇒ String?
Get font name from font dictionary.
-
#format ⇒ Symbol
High-level pipeline format identifier.
-
#full_name ⇒ String?
Get full name from FontInfo.
-
#glyph_names ⇒ Array<String>
Get list of glyph names.
-
#initialize(data, container_format: nil, file_path: nil, mode: :full) ⇒ Type1Font
constructor
Initialize a new Type1Font instance.
-
#outline_type ⇒ Symbol
Outline representation.
-
#parse_dictionaries! ⇒ void
Parse font dictionaries from decrypted data.
-
#parsed_dictionaries? ⇒ Boolean
Check if dictionaries have been parsed.
-
#private_dict ⇒ PrivateDict?
Private dictionary.
-
#table_names ⇒ Array<String>
Type 1 fonts have no SFNT table directory; the table-oriented pipeline introspection does not apply.
-
#variation_type ⇒ Symbol
Type 1 fonts are not OpenType variable fonts.
-
#version ⇒ String?
Get version from FontInfo.
Constructor Details
#initialize(data, container_format: nil, file_path: nil, mode: :full) ⇒ Type1Font
Initialize a new Type1Font instance
99 100 101 102 103 104 105 106 |
# File 'lib/fontisan/type1_font.rb', line 99 def initialize(data, container_format: nil, file_path: nil, mode: :full) @file_path = file_path @container_format = container_format || detect_format(data) @data = data @loading_mode = mode parse_font_data end |
Instance Attribute Details
#container_format ⇒ Symbol (readonly)
Returns Container variant (:pfb or :pfa) — the on-disk encoding of a Type 1 font (binary vs ASCII). Distinct from #format, which is the high-level pipeline format.
38 39 40 |
# File 'lib/fontisan/type1_font.rb', line 38 def container_format @container_format end |
#decrypted_data ⇒ String? (readonly)
Returns Decrypted font data.
72 73 74 |
# File 'lib/fontisan/type1_font.rb', line 72 def decrypted_data @decrypted_data end |
#file_path ⇒ String? (readonly)
Returns File path if loaded from file.
33 34 35 |
# File 'lib/fontisan/type1_font.rb', line 33 def file_path @file_path end |
#loading_mode ⇒ Symbol (readonly)
Returns Loading mode (:metadata or :full).
69 70 71 |
# File 'lib/fontisan/type1_font.rb', line 69 def loading_mode @loading_mode end |
Class Method Details
.from_file(file_path, mode: :full) ⇒ Type1Font
Load Type 1 font from file
121 122 123 124 125 126 127 128 129 130 131 132 |
# File 'lib/fontisan/type1_font.rb', line 121 def self.from_file(file_path, mode: :full) 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, mode: mode) end |
Instance Method Details
#charstrings ⇒ CharStrings?
Returns CharStrings dictionary.
87 88 89 90 |
# File 'lib/fontisan/type1_font.rb', line 87 def charstrings parse_dictionaries! unless @charstrings @charstrings end |
#clear_text ⇒ String
Get clear text portion (before eexec)
137 138 139 |
# File 'lib/fontisan/type1_font.rb', line 137 def clear_text @clear_text ||= "" end |
#collection? ⇒ Boolean
Whether this object represents a font collection rather than a single font. Each font class is the authority on this question.
50 |
# File 'lib/fontisan/type1_font.rb', line 50 def collection? = false |
#decrypt! ⇒ String
Decrypt the font if not already decrypted
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
# File 'lib/fontisan/type1_font.rb', line 165 def decrypt! return @decrypted_data if decrypted? if @encrypted_portion.nil? || @encrypted_portion.empty? @decrypted_data = @clear_text else encrypted_binary = if @container_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
151 152 153 |
# File 'lib/fontisan/type1_font.rb', line 151 def decrypted? !@decrypted_data.nil? end |
#encrypted? ⇒ Boolean
Check if font is encrypted
158 159 160 |
# File 'lib/fontisan/type1_font.rb', line 158 def encrypted? !@encrypted_portion.nil? && !@encrypted_portion.empty? end |
#encrypted_portion ⇒ String
Get encrypted portion (as hex string for PFA)
144 145 146 |
# File 'lib/fontisan/type1_font.rb', line 144 def encrypted_portion @encrypted_portion ||= "" end |
#family_name ⇒ String?
Get family name from FontInfo
225 226 227 228 229 |
# File 'lib/fontisan/type1_font.rb', line 225 def family_name return @font_dictionary&.font_info&.family_name if @font_dictionary extract_fontinfo_value("FamilyName") end |
#font_dictionary ⇒ FontDictionary?
Returns Font dictionary.
75 76 77 78 |
# File 'lib/fontisan/type1_font.rb', line 75 def font_dictionary parse_dictionaries! unless @font_dictionary @font_dictionary end |
#font_name ⇒ String?
Get font name from font dictionary
207 208 209 210 211 |
# File 'lib/fontisan/type1_font.rb', line 207 def font_name return @font_dictionary&.font_name if @font_dictionary extract_dictionary_value("/FontName") end |
#format ⇒ Symbol
High-level pipeline format identifier. Owned by the font class so the conversion pipeline can dispatch without case statements (OCP).
44 |
# File 'lib/fontisan/type1_font.rb', line 44 def format = :type1 |
#full_name ⇒ String?
Get full name from FontInfo
216 217 218 219 220 |
# File 'lib/fontisan/type1_font.rb', line 216 def full_name return @font_dictionary&.font_info&.full_name if @font_dictionary extract_fontinfo_value("FullName") end |
#glyph_names ⇒ Array<String>
Get list of glyph names
243 244 245 246 247 |
# File 'lib/fontisan/type1_font.rb', line 243 def glyph_names return [] unless @charstrings @charstrings.glyph_names end |
#outline_type ⇒ Symbol
Outline representation. Type 1 fonts use cubic PostScript CharStrings.
60 |
# File 'lib/fontisan/type1_font.rb', line 60 def outline_type = :postscript |
#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.
191 192 193 194 195 196 197 198 199 200 201 202 |
# File 'lib/fontisan/type1_font.rb', line 191 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
252 253 254 |
# File 'lib/fontisan/type1_font.rb', line 252 def parsed_dictionaries? !@font_dictionary.nil? end |
#private_dict ⇒ PrivateDict?
Returns Private dictionary.
81 82 83 84 |
# File 'lib/fontisan/type1_font.rb', line 81 def private_dict parse_dictionaries! unless @private_dict @private_dict end |
#table_names ⇒ Array<String>
Type 1 fonts have no SFNT table directory; the table-oriented pipeline introspection does not apply.
66 |
# File 'lib/fontisan/type1_font.rb', line 66 def table_names = [] |
#variation_type ⇒ Symbol
Type 1 fonts are not OpenType variable fonts.
55 |
# File 'lib/fontisan/type1_font.rb', line 55 def variation_type = :static |
#version ⇒ String?
Get version from FontInfo
234 235 236 237 238 |
# File 'lib/fontisan/type1_font.rb', line 234 def version return @font_dictionary&.font_info&.version if @font_dictionary extract_fontinfo_value("version") end |