fontisan 0.2.11 → 0.2.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop_todo.yml +294 -52
- data/Gemfile +5 -0
- data/README.adoc +163 -2
- data/docs/CONVERSION_GUIDE.adoc +633 -0
- data/docs/TYPE1_FONTS.adoc +445 -0
- data/lib/fontisan/cli.rb +177 -6
- data/lib/fontisan/commands/convert_command.rb +32 -1
- data/lib/fontisan/commands/info_command.rb +83 -2
- data/lib/fontisan/config/conversion_matrix.yml +132 -4
- data/lib/fontisan/constants.rb +12 -0
- data/lib/fontisan/conversion_options.rb +378 -0
- data/lib/fontisan/converters/collection_converter.rb +45 -10
- data/lib/fontisan/converters/format_converter.rb +17 -5
- data/lib/fontisan/converters/outline_converter.rb +78 -4
- data/lib/fontisan/converters/type1_converter.rb +1234 -0
- data/lib/fontisan/font_loader.rb +46 -3
- data/lib/fontisan/hints/hint_converter.rb +4 -1
- data/lib/fontisan/type1/afm_generator.rb +436 -0
- data/lib/fontisan/type1/afm_parser.rb +298 -0
- data/lib/fontisan/type1/agl.rb +456 -0
- data/lib/fontisan/type1/cff_to_type1_converter.rb +302 -0
- data/lib/fontisan/type1/charstring_converter.rb +240 -0
- data/lib/fontisan/type1/charstrings.rb +408 -0
- data/lib/fontisan/type1/conversion_options.rb +243 -0
- data/lib/fontisan/type1/decryptor.rb +183 -0
- data/lib/fontisan/type1/encodings.rb +697 -0
- data/lib/fontisan/type1/font_dictionary.rb +576 -0
- data/lib/fontisan/type1/generator.rb +220 -0
- data/lib/fontisan/type1/inf_generator.rb +332 -0
- data/lib/fontisan/type1/pfa_generator.rb +369 -0
- data/lib/fontisan/type1/pfa_parser.rb +159 -0
- data/lib/fontisan/type1/pfb_generator.rb +314 -0
- data/lib/fontisan/type1/pfb_parser.rb +166 -0
- data/lib/fontisan/type1/pfm_generator.rb +610 -0
- data/lib/fontisan/type1/pfm_parser.rb +433 -0
- data/lib/fontisan/type1/private_dict.rb +342 -0
- data/lib/fontisan/type1/seac_expander.rb +501 -0
- data/lib/fontisan/type1/ttf_to_type1_converter.rb +327 -0
- data/lib/fontisan/type1/upm_scaler.rb +118 -0
- data/lib/fontisan/type1.rb +75 -0
- data/lib/fontisan/type1_font.rb +318 -0
- data/lib/fontisan/version.rb +1 -1
- data/lib/fontisan.rb +2 -0
- metadata +30 -3
- data/docs/DOCUMENTATION_SUMMARY.md +0 -141
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "type1"
|
|
4
|
+
|
|
5
|
+
module Fontisan
|
|
6
|
+
# Adobe Type 1 Font handler
|
|
7
|
+
#
|
|
8
|
+
# [`Type1Font`](lib/fontisan/type1_font.rb) provides parsing and conversion
|
|
9
|
+
# capabilities for Adobe Type 1 fonts in PFB (Printer Font Binary) and
|
|
10
|
+
# PFA (Printer Font ASCII) formats.
|
|
11
|
+
#
|
|
12
|
+
# Type 1 fonts were the standard for digital typography in the 1980s-1990s
|
|
13
|
+
# and consist of:
|
|
14
|
+
# - Font dictionary with metadata (FontInfo, FontName, Encoding, etc.)
|
|
15
|
+
# - Private dictionary with hinting and spacing information
|
|
16
|
+
# - CharStrings (glyph outline descriptions)
|
|
17
|
+
# - eexec encryption for protection
|
|
18
|
+
#
|
|
19
|
+
# @example Load a PFB file
|
|
20
|
+
# font = Fontisan::Type1Font.from_file('font.pfb')
|
|
21
|
+
# puts font.font_name
|
|
22
|
+
# puts font.version
|
|
23
|
+
#
|
|
24
|
+
# @example Load a PFA file
|
|
25
|
+
# font = Fontisan::Type1Font.from_file('font.pfa')
|
|
26
|
+
# puts font.full_name
|
|
27
|
+
#
|
|
28
|
+
# @example Access decrypted font data
|
|
29
|
+
# font = Fontisan::Type1Font.from_file('font.pfb')
|
|
30
|
+
# puts font.decrypted_data
|
|
31
|
+
#
|
|
32
|
+
# @see https://www.adobe.com/devnet/font/pdfs/Type1.pdf
|
|
33
|
+
class Type1Font
|
|
34
|
+
# @return [String, nil] File path if loaded from file
|
|
35
|
+
attr_reader :file_path
|
|
36
|
+
|
|
37
|
+
# @return [Symbol] Format type (:pfb or :pfa)
|
|
38
|
+
attr_reader :format
|
|
39
|
+
|
|
40
|
+
# @return [Symbol] Loading mode (:metadata or :full)
|
|
41
|
+
attr_reader :loading_mode
|
|
42
|
+
|
|
43
|
+
# @return [String, nil] Decrypted font data
|
|
44
|
+
attr_reader :decrypted_data
|
|
45
|
+
|
|
46
|
+
# @return [FontDictionary, nil] Font dictionary
|
|
47
|
+
def font_dictionary
|
|
48
|
+
parse_dictionaries! unless @font_dictionary
|
|
49
|
+
@font_dictionary
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# @return [PrivateDict, nil] Private dictionary
|
|
53
|
+
def private_dict
|
|
54
|
+
parse_dictionaries! unless @private_dict
|
|
55
|
+
@private_dict
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# @return [CharStrings, nil] CharStrings dictionary
|
|
59
|
+
def charstrings
|
|
60
|
+
parse_dictionaries! unless @charstrings
|
|
61
|
+
@charstrings
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Initialize a new Type1Font instance
|
|
65
|
+
#
|
|
66
|
+
# @param data [String] Font file data (binary or text)
|
|
67
|
+
# @param format [Symbol] Format type (:pfb or :pfa, auto-detected if nil)
|
|
68
|
+
# @param file_path [String, nil] Optional file path for reference
|
|
69
|
+
# @param mode [Symbol] Loading mode (:metadata or :full, default: :full)
|
|
70
|
+
def initialize(data, format: nil, file_path: nil, mode: :full)
|
|
71
|
+
@file_path = file_path
|
|
72
|
+
@format = format || detect_format(data)
|
|
73
|
+
@data = data
|
|
74
|
+
@loading_mode = mode
|
|
75
|
+
|
|
76
|
+
parse_font_data
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Load Type 1 font from file
|
|
80
|
+
#
|
|
81
|
+
# @param file_path [String] Path to PFB or PFA file
|
|
82
|
+
# @param mode [Symbol] Loading mode (:metadata or :full, default: :full)
|
|
83
|
+
# @return [Type1Font] Loaded font instance
|
|
84
|
+
# @raise [ArgumentError] If file_path is nil
|
|
85
|
+
# @raise [Fontisan::Error] If file cannot be read or parsed
|
|
86
|
+
#
|
|
87
|
+
# @example Load PFB file
|
|
88
|
+
# font = Fontisan::Type1Font.from_file('font.pfb')
|
|
89
|
+
#
|
|
90
|
+
# @example Load PFA file
|
|
91
|
+
# font = Fontisan::Type1Font.from_file('font.pfa')
|
|
92
|
+
def self.from_file(file_path, mode: :full)
|
|
93
|
+
raise ArgumentError, "File path cannot be nil" if file_path.nil?
|
|
94
|
+
|
|
95
|
+
unless File.exist?(file_path)
|
|
96
|
+
raise Fontisan::Error, "File not found: #{file_path}"
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Read file
|
|
100
|
+
data = File.binread(file_path)
|
|
101
|
+
|
|
102
|
+
new(data, file_path: file_path, mode: mode)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Get clear text portion (before eexec)
|
|
106
|
+
#
|
|
107
|
+
# @return [String] Clear text font dictionary
|
|
108
|
+
def clear_text
|
|
109
|
+
@clear_text ||= ""
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Get encrypted portion (as hex string for PFA)
|
|
113
|
+
#
|
|
114
|
+
# @return [String] Encrypted portion
|
|
115
|
+
def encrypted_portion
|
|
116
|
+
@encrypted_portion ||= ""
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Check if font has been decrypted
|
|
120
|
+
#
|
|
121
|
+
# @return [Boolean] True if font data has been decrypted
|
|
122
|
+
def decrypted?
|
|
123
|
+
!@decrypted_data.nil?
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# Check if font is encrypted
|
|
127
|
+
#
|
|
128
|
+
# @return [Boolean] True if font has eexec encrypted portion
|
|
129
|
+
def encrypted?
|
|
130
|
+
!@encrypted_portion.nil? && !@encrypted_portion.empty?
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# Decrypt the font if not already decrypted
|
|
134
|
+
#
|
|
135
|
+
# @return [String] Decrypted font data
|
|
136
|
+
def decrypt!
|
|
137
|
+
return @decrypted_data if decrypted?
|
|
138
|
+
|
|
139
|
+
if @encrypted_portion.nil? || @encrypted_portion.empty?
|
|
140
|
+
@decrypted_data = @clear_text
|
|
141
|
+
else
|
|
142
|
+
encrypted_binary = if @format == :pfa
|
|
143
|
+
# Convert hex string to binary
|
|
144
|
+
[@encrypted_portion.gsub(/\s/, "")].pack("H*")
|
|
145
|
+
else
|
|
146
|
+
@encrypted_portion
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
@decrypted_data = @clear_text +
|
|
150
|
+
Type1::Decryptor.eexec_decrypt(encrypted_binary)
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
@decrypted_data
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# Parse font dictionaries from decrypted data
|
|
157
|
+
#
|
|
158
|
+
# Parses the font dictionary, private dictionary, and CharStrings
|
|
159
|
+
# from the decrypted font data.
|
|
160
|
+
#
|
|
161
|
+
# @return [void]
|
|
162
|
+
def parse_dictionaries!
|
|
163
|
+
decrypt! unless decrypted?
|
|
164
|
+
|
|
165
|
+
# Parse font dictionary
|
|
166
|
+
@font_dictionary = Type1::FontDictionary.parse(@decrypted_data)
|
|
167
|
+
|
|
168
|
+
# Parse private dictionary
|
|
169
|
+
@private_dict = Type1::PrivateDict.parse(@decrypted_data)
|
|
170
|
+
|
|
171
|
+
# Parse CharStrings
|
|
172
|
+
@charstrings = Type1::CharStrings.parse(@decrypted_data, @private_dict)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# Get font name from font dictionary
|
|
176
|
+
#
|
|
177
|
+
# @return [String, nil] Font name or nil if not found
|
|
178
|
+
def font_name
|
|
179
|
+
return @font_dictionary&.font_name if @font_dictionary
|
|
180
|
+
|
|
181
|
+
extract_dictionary_value("/FontName")
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# Get full name from FontInfo
|
|
185
|
+
#
|
|
186
|
+
# @return [String, nil] Full name or nil if not found
|
|
187
|
+
def full_name
|
|
188
|
+
return @font_dictionary&.font_info&.full_name if @font_dictionary
|
|
189
|
+
|
|
190
|
+
extract_fontinfo_value("FullName")
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
# Get family name from FontInfo
|
|
194
|
+
#
|
|
195
|
+
# @return [String, nil] Family name or nil if not found
|
|
196
|
+
def family_name
|
|
197
|
+
return @font_dictionary&.font_info&.family_name if @font_dictionary
|
|
198
|
+
|
|
199
|
+
extract_fontinfo_value("FamilyName")
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
# Get version from FontInfo
|
|
203
|
+
#
|
|
204
|
+
# @return [String, nil] Version or nil if not found
|
|
205
|
+
def version
|
|
206
|
+
return @font_dictionary&.font_info&.version if @font_dictionary
|
|
207
|
+
|
|
208
|
+
extract_fontinfo_value("version")
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
# Get list of glyph names
|
|
212
|
+
#
|
|
213
|
+
# @return [Array<String>] Glyph names
|
|
214
|
+
def glyph_names
|
|
215
|
+
return [] unless @charstrings
|
|
216
|
+
|
|
217
|
+
@charstrings.glyph_names
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
# Check if dictionaries have been parsed
|
|
221
|
+
#
|
|
222
|
+
# @return [Boolean] True if dictionaries have been parsed
|
|
223
|
+
def parsed_dictionaries?
|
|
224
|
+
!@font_dictionary.nil?
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
private
|
|
228
|
+
|
|
229
|
+
# Parse font data based on format
|
|
230
|
+
def parse_font_data
|
|
231
|
+
case @format
|
|
232
|
+
when :pfb
|
|
233
|
+
parse_pfb
|
|
234
|
+
when :pfa
|
|
235
|
+
parse_pfa
|
|
236
|
+
else
|
|
237
|
+
raise Fontisan::Error, "Unknown format: #{@format}"
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
# Parse PFB format
|
|
242
|
+
def parse_pfb
|
|
243
|
+
parser = Type1::PFBParser.new
|
|
244
|
+
parser.parse(@data)
|
|
245
|
+
|
|
246
|
+
# PFB has alternating ASCII and binary parts
|
|
247
|
+
# ASCII parts contain font dictionary
|
|
248
|
+
# Binary parts contain encrypted CharStrings
|
|
249
|
+
@clear_text = parser.ascii_text
|
|
250
|
+
@encrypted_portion = parser.binary_data
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
# Parse PFA format
|
|
254
|
+
def parse_pfa
|
|
255
|
+
parser = Type1::PFAParser.new
|
|
256
|
+
parser.parse(@data)
|
|
257
|
+
|
|
258
|
+
@clear_text = parser.clear_text
|
|
259
|
+
@encrypted_portion = parser.encrypted_hex
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
# Detect format from data
|
|
263
|
+
#
|
|
264
|
+
# @param data [String] Font data
|
|
265
|
+
# @return [Symbol] Detected format (:pfb or :pfa)
|
|
266
|
+
def detect_format(data)
|
|
267
|
+
if Type1::PFBParser.pfb_file?(data)
|
|
268
|
+
:pfb
|
|
269
|
+
elsif Type1::PFAParser.pfa_file?(data)
|
|
270
|
+
:pfa
|
|
271
|
+
else
|
|
272
|
+
raise Fontisan::Error,
|
|
273
|
+
"Cannot detect Type 1 format: not a valid PFB or PFA file"
|
|
274
|
+
end
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
# Extract value from font dictionary
|
|
278
|
+
#
|
|
279
|
+
# @param key [String] Dictionary key (e.g., "/FontName")
|
|
280
|
+
# @return [String, nil] Value or nil if not found
|
|
281
|
+
def extract_dictionary_value(key)
|
|
282
|
+
text = decrypted? ? @decrypted_data : @clear_text
|
|
283
|
+
|
|
284
|
+
# Look for /FontName /name def pattern
|
|
285
|
+
pattern = /#{Regexp.escape(key)}\s+\/([^\s]+)\s+def/
|
|
286
|
+
match = text.match(pattern)
|
|
287
|
+
return nil unless match
|
|
288
|
+
|
|
289
|
+
match[1]
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
# Extract value from FontInfo dictionary
|
|
293
|
+
#
|
|
294
|
+
# @param key [String] FontInfo key (e.g., "FullName")
|
|
295
|
+
# @return [String, nil] Value or nil if not found
|
|
296
|
+
def extract_fontinfo_value(key)
|
|
297
|
+
text = decrypted? ? @decrypted_data : @clear_text
|
|
298
|
+
|
|
299
|
+
# Look for (FullName) readonly (value) readonly pattern
|
|
300
|
+
# This pattern handles nested parentheses in values
|
|
301
|
+
pattern = /\(#{Regexp.escape(key)}\)\s+readonly\s+(\([^()]*\)|\((?:[^()]*\([^()]*\)[^()]*)*\))\s+readonly/
|
|
302
|
+
match = text.match(pattern)
|
|
303
|
+
return match[1].gsub(/^\(|\)$/, "") if match
|
|
304
|
+
|
|
305
|
+
# Look for /FullName (value) def pattern
|
|
306
|
+
pattern = /\/#{Regexp.escape(key)}\s+\(([^)]+)\)\s+def/
|
|
307
|
+
match = text.match(pattern)
|
|
308
|
+
return match[1] if match
|
|
309
|
+
|
|
310
|
+
# Look for /FullName (value) readonly readonly pattern
|
|
311
|
+
pattern = /\/#{Regexp.escape(key)}\s+(\([^()]*\)|\((?:[^()]*\([^()]*\)[^()]*)*\))\s+readonly\s+readonly/
|
|
312
|
+
match = text.match(pattern)
|
|
313
|
+
return match[1].gsub(/^\(|\)$/, "") if match
|
|
314
|
+
|
|
315
|
+
nil
|
|
316
|
+
end
|
|
317
|
+
end
|
|
318
|
+
end
|
data/lib/fontisan/version.rb
CHANGED
data/lib/fontisan.rb
CHANGED
|
@@ -83,6 +83,7 @@ require_relative "fontisan/true_type_collection"
|
|
|
83
83
|
require_relative "fontisan/open_type_collection"
|
|
84
84
|
require_relative "fontisan/woff_font"
|
|
85
85
|
require_relative "fontisan/woff2_font"
|
|
86
|
+
require_relative "fontisan/type1_font"
|
|
86
87
|
|
|
87
88
|
# Font extensions for table-based construction
|
|
88
89
|
require_relative "fontisan/true_type_font_extensions"
|
|
@@ -166,6 +167,7 @@ require_relative "fontisan/collection/writer"
|
|
|
166
167
|
require_relative "fontisan/collection/builder"
|
|
167
168
|
|
|
168
169
|
# Format conversion infrastructure
|
|
170
|
+
require_relative "fontisan/conversion_options"
|
|
169
171
|
require_relative "fontisan/converters/conversion_strategy"
|
|
170
172
|
require_relative "fontisan/converters/table_copier"
|
|
171
173
|
require_relative "fontisan/converters/outline_converter"
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: fontisan
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.13
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-01-
|
|
11
|
+
date: 2026-01-21 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: base64
|
|
@@ -120,9 +120,10 @@ files:
|
|
|
120
120
|
- docs/APPLE_LEGACY_FONTS.adoc
|
|
121
121
|
- docs/COLLECTION_VALIDATION.adoc
|
|
122
122
|
- docs/COLOR_FONTS.adoc
|
|
123
|
-
- docs/
|
|
123
|
+
- docs/CONVERSION_GUIDE.adoc
|
|
124
124
|
- docs/EXTRACT_TTC_MIGRATION.md
|
|
125
125
|
- docs/FONT_HINTING.adoc
|
|
126
|
+
- docs/TYPE1_FONTS.adoc
|
|
126
127
|
- docs/VALIDATION.adoc
|
|
127
128
|
- docs/VARIABLE_FONT_OPERATIONS.adoc
|
|
128
129
|
- docs/WOFF_WOFF2_FORMATS.adoc
|
|
@@ -168,6 +169,7 @@ files:
|
|
|
168
169
|
- lib/fontisan/config/variable_settings.yml
|
|
169
170
|
- lib/fontisan/config/woff2_settings.yml
|
|
170
171
|
- lib/fontisan/constants.rb
|
|
172
|
+
- lib/fontisan/conversion_options.rb
|
|
171
173
|
- lib/fontisan/converters/cff_table_builder.rb
|
|
172
174
|
- lib/fontisan/converters/collection_converter.rb
|
|
173
175
|
- lib/fontisan/converters/conversion_strategy.rb
|
|
@@ -178,6 +180,7 @@ files:
|
|
|
178
180
|
- lib/fontisan/converters/outline_optimizer.rb
|
|
179
181
|
- lib/fontisan/converters/svg_generator.rb
|
|
180
182
|
- lib/fontisan/converters/table_copier.rb
|
|
183
|
+
- lib/fontisan/converters/type1_converter.rb
|
|
181
184
|
- lib/fontisan/converters/woff2_encoder.rb
|
|
182
185
|
- lib/fontisan/converters/woff_writer.rb
|
|
183
186
|
- lib/fontisan/dfont_collection.rb
|
|
@@ -348,6 +351,30 @@ files:
|
|
|
348
351
|
- lib/fontisan/true_type_collection.rb
|
|
349
352
|
- lib/fontisan/true_type_font.rb
|
|
350
353
|
- lib/fontisan/true_type_font_extensions.rb
|
|
354
|
+
- lib/fontisan/type1.rb
|
|
355
|
+
- lib/fontisan/type1/afm_generator.rb
|
|
356
|
+
- lib/fontisan/type1/afm_parser.rb
|
|
357
|
+
- lib/fontisan/type1/agl.rb
|
|
358
|
+
- lib/fontisan/type1/cff_to_type1_converter.rb
|
|
359
|
+
- lib/fontisan/type1/charstring_converter.rb
|
|
360
|
+
- lib/fontisan/type1/charstrings.rb
|
|
361
|
+
- lib/fontisan/type1/conversion_options.rb
|
|
362
|
+
- lib/fontisan/type1/decryptor.rb
|
|
363
|
+
- lib/fontisan/type1/encodings.rb
|
|
364
|
+
- lib/fontisan/type1/font_dictionary.rb
|
|
365
|
+
- lib/fontisan/type1/generator.rb
|
|
366
|
+
- lib/fontisan/type1/inf_generator.rb
|
|
367
|
+
- lib/fontisan/type1/pfa_generator.rb
|
|
368
|
+
- lib/fontisan/type1/pfa_parser.rb
|
|
369
|
+
- lib/fontisan/type1/pfb_generator.rb
|
|
370
|
+
- lib/fontisan/type1/pfb_parser.rb
|
|
371
|
+
- lib/fontisan/type1/pfm_generator.rb
|
|
372
|
+
- lib/fontisan/type1/pfm_parser.rb
|
|
373
|
+
- lib/fontisan/type1/private_dict.rb
|
|
374
|
+
- lib/fontisan/type1/seac_expander.rb
|
|
375
|
+
- lib/fontisan/type1/ttf_to_type1_converter.rb
|
|
376
|
+
- lib/fontisan/type1/upm_scaler.rb
|
|
377
|
+
- lib/fontisan/type1_font.rb
|
|
351
378
|
- lib/fontisan/utilities/brotli_wrapper.rb
|
|
352
379
|
- lib/fontisan/utilities/checksum_calculator.rb
|
|
353
380
|
- lib/fontisan/utils/thread_pool.rb
|
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
# Fontisan Documentation Summary
|
|
2
|
-
|
|
3
|
-
This document provides an overview of all Fontisan documentation files and their purpose.
|
|
4
|
-
|
|
5
|
-
## Main Documentation
|
|
6
|
-
|
|
7
|
-
### README.adoc
|
|
8
|
-
Primary user guide and reference documentation for Fontisan.
|
|
9
|
-
|
|
10
|
-
## Feature Guides
|
|
11
|
-
|
|
12
|
-
### Font Hinting
|
|
13
|
-
- **File**: `docs/FONT_HINTING.adoc`
|
|
14
|
-
- **Purpose**: Documentation for font hinting features in Fontisan
|
|
15
|
-
- **Topics**: TrueType and PostScript hinting, hint extraction and application
|
|
16
|
-
|
|
17
|
-
### Variable Font Operations
|
|
18
|
-
- **File**: `docs/VARIABLE_FONT_OPERATIONS.adoc`
|
|
19
|
-
- **Purpose**: Guide for working with variable fonts
|
|
20
|
-
- **Topics**: Instance generation, axis manipulation, variation preservation
|
|
21
|
-
|
|
22
|
-
### TTC Migration Guide
|
|
23
|
-
- **File**: `docs/EXTRACT_TTC_MIGRATION.md`
|
|
24
|
-
- **Purpose**: Migration guide for users of the `extract-ttc` gem
|
|
25
|
-
- **Topics**: Moving from extract-ttc to Fontisan pack/unpack commands
|
|
26
|
-
|
|
27
|
-
### Web Font Formats
|
|
28
|
-
- **File**: `docs/WOFF_WOFF2_FORMATS.adoc`
|
|
29
|
-
- **Purpose**: Documentation for WOFF and WOFF2 web font formats
|
|
30
|
-
- **Topics**: Conversion to/from WOFF/WOFF2, web optimization
|
|
31
|
-
|
|
32
|
-
### Color Fonts
|
|
33
|
-
- **File**: `docs/COLOR_FONTS.adoc`
|
|
34
|
-
- **Purpose**: Guide for color font formats
|
|
35
|
-
- **Topics**: COLR/CPAL, SVG-in-OpenType, sbix color fonts
|
|
36
|
-
|
|
37
|
-
### Validation
|
|
38
|
-
- **File**: `docs/VALIDATION.adoc`
|
|
39
|
-
- **Purpose**: Font validation framework documentation
|
|
40
|
-
- **Topics**: Validation profiles, quality checks, OpenType spec compliance
|
|
41
|
-
|
|
42
|
-
### Apple Legacy Fonts
|
|
43
|
-
- **File**: `docs/APPLE_LEGACY_FONTS.adoc`
|
|
44
|
-
- **Purpose**: Documentation for Apple legacy font formats
|
|
45
|
-
- **Topics**: dfont format, Mac suitcase fonts
|
|
46
|
-
|
|
47
|
-
### Collection Validation
|
|
48
|
-
- **File**: `docs/COLLECTION_VALIDATION.adoc`
|
|
49
|
-
- **Purpose**: Guide for validating font collections (TTC/OTC/dfont)
|
|
50
|
-
- **Topics**: Collection-specific validation, profile selection
|
|
51
|
-
|
|
52
|
-
## CLI Commands Reference
|
|
53
|
-
|
|
54
|
-
Fontisan provides the following CLI commands:
|
|
55
|
-
|
|
56
|
-
| Command | Purpose |
|
|
57
|
-
|---------|---------|
|
|
58
|
-
| `info` | Display font information |
|
|
59
|
-
| `ls` | List contents (fonts in collection or font summary) |
|
|
60
|
-
| `tables` | List OpenType tables |
|
|
61
|
-
| `glyphs` | List glyph names |
|
|
62
|
-
| `unicode` | List Unicode to glyph mappings |
|
|
63
|
-
| `variable` | Display variable font information |
|
|
64
|
-
| `optical-size` | Display optical size information |
|
|
65
|
-
| `scripts` | List supported scripts from GSUB/GPOS tables |
|
|
66
|
-
| `features` | List GSUB/GPOS features |
|
|
67
|
-
| `subset` | Subset a font to specific glyphs |
|
|
68
|
-
| `convert` | Convert font to different format |
|
|
69
|
-
| `instance` | Generate static font instance from variable font |
|
|
70
|
-
| `pack` | Pack multiple fonts into TTC/OTC collection |
|
|
71
|
-
| `unpack` | Unpack fonts from TTC/OTC collection |
|
|
72
|
-
| `validate` | Validate font file |
|
|
73
|
-
| `export` | Export font to TTX/YAML/JSON format |
|
|
74
|
-
| `dump-table` | Dump raw table data to stdout |
|
|
75
|
-
| `version` | Display version information |
|
|
76
|
-
|
|
77
|
-
## Ruby API Reference
|
|
78
|
-
|
|
79
|
-
### Fontisan Module Methods
|
|
80
|
-
|
|
81
|
-
#### `Fontisan.info(path, brief: false, font_index: 0)`
|
|
82
|
-
Get font information. Supports both full and brief modes.
|
|
83
|
-
|
|
84
|
-
- **Parameters**:
|
|
85
|
-
- `path` (String): Path to font file
|
|
86
|
-
- `brief` (Boolean): Use brief mode for fast identification (default: false)
|
|
87
|
-
- `font_index` (Integer): Index for TTC/OTC files (default: 0)
|
|
88
|
-
- **Returns**: `Models::FontInfo`, `Models::CollectionInfo`, or `Models::CollectionBriefInfo`
|
|
89
|
-
- **Example**:
|
|
90
|
-
```ruby
|
|
91
|
-
info = Fontisan.info("font.ttf", brief: true)
|
|
92
|
-
puts info.family_name
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
#### `Fontisan.validate(path, profile: :default, options: {})`
|
|
96
|
-
Validate a font file using specified profile.
|
|
97
|
-
|
|
98
|
-
- **Parameters**:
|
|
99
|
-
- `path` (String): Path to font file
|
|
100
|
-
- `profile` (Symbol/String): Validation profile (default: :default)
|
|
101
|
-
- `options` (Hash): Additional validation options
|
|
102
|
-
- **Available Profiles**:
|
|
103
|
-
- `:indexability` - Fast validation for font discovery
|
|
104
|
-
- `:usability` - Basic usability for installation
|
|
105
|
-
- `:production` - Comprehensive quality checks (default)
|
|
106
|
-
- `:web` - Web embedding and optimization
|
|
107
|
-
- `:spec_compliance` - Full OpenType spec compliance
|
|
108
|
-
- `:default` - Alias for production profile
|
|
109
|
-
- **Returns**: `Models::ValidationReport`
|
|
110
|
-
- **Example**:
|
|
111
|
-
```ruby
|
|
112
|
-
report = Fontisan.validate("font.ttf", profile: :web)
|
|
113
|
-
puts "Errors: #{report.summary.errors}"
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
### Fontisan::FontLoader
|
|
117
|
-
|
|
118
|
-
Module for loading fonts in different modes.
|
|
119
|
-
|
|
120
|
-
- **Methods**:
|
|
121
|
-
- `load(path, mode: :full)` - Load a font file
|
|
122
|
-
- **Loading Modes**:
|
|
123
|
-
- `:full` - Load all tables
|
|
124
|
-
- `:metadata` - Load only metadata tables (name, head, hhea, maxp, OS/2, post)
|
|
125
|
-
- `:tables` - Load specific tables only
|
|
126
|
-
- `:structure` - Load structure tables only
|
|
127
|
-
|
|
128
|
-
## Verification
|
|
129
|
-
|
|
130
|
-
Documentation examples are verified by `spec/documentation_examples_spec.rb`.
|
|
131
|
-
|
|
132
|
-
This spec ensures that:
|
|
133
|
-
1. All CLI commands referenced in documentation exist
|
|
134
|
-
2. All Ruby API methods are available
|
|
135
|
-
3. All documentation files are present
|
|
136
|
-
4. Command examples reference valid commands
|
|
137
|
-
|
|
138
|
-
Run verification with:
|
|
139
|
-
```bash
|
|
140
|
-
bundle exec rspec spec/documentation_examples_spec.rb -v
|
|
141
|
-
```
|