fontisan 0.2.12 → 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.
@@ -0,0 +1,633 @@
1
+ = Font Conversion Guide
2
+
3
+ This guide provides comprehensive reference for Fontisan's conversion options system, including all supported formats, options, and best practices.
4
+
5
+ == Overview
6
+
7
+ Fontisan's conversion system is based on the TypeTool 3 manual's recommended options for different font format conversions. The system provides:
8
+
9
+ * Type-safe option validation
10
+ * Format-specific default options
11
+ * Named presets for common workflows
12
+ * Fine-grained control over conversion behavior
13
+
14
+ == Quick Reference
15
+
16
+ === Using the CLI
17
+
18
+ [source,shell]
19
+ ----
20
+ # Basic conversion
21
+ fontisan convert input.ttf --to otf --output output.otf
22
+
23
+ # Show recommended options
24
+ fontisan convert input.ttf --to otf --show-options
25
+
26
+ # Use a preset
27
+ fontisan convert font.pfb --to otf --preset type1_to_modern --output output.otf
28
+
29
+ # Custom options
30
+ fontisan convert input.ttf --to otf --autohint --hinting-mode auto --output output.otf
31
+ ----
32
+
33
+ === Using the API
34
+
35
+ [source,ruby]
36
+ ----
37
+ require 'fontisan'
38
+
39
+ # Get recommended options
40
+ options = Fontisan::ConversionOptions.recommended(from: :ttf, to: :otf)
41
+
42
+ # Use a preset
43
+ options = Fontisan::ConversionOptions.from_preset(:web_optimized)
44
+
45
+ # Build custom options
46
+ options = Fontisan::ConversionOptions.new(
47
+ from: :ttf,
48
+ to: :otf,
49
+ opening: { autohint: true, convert_curves: true },
50
+ generating: { hinting_mode: "auto" }
51
+ )
52
+
53
+ # Convert with options
54
+ converter = Fontisan::Converters::OutlineConverter.new
55
+ tables = converter.convert(font, options: options)
56
+ ----
57
+
58
+ == Supported Formats
59
+
60
+ === Input Formats
61
+
62
+ | Format | Description | Extensions |
63
+ |--------|-------------|------------|
64
+ | TTF | TrueType Font | .ttf |
65
+ | OTF | OpenType/CFF Font | .otf |
66
+ | Type 1 | Adobe Type 1 Font | .pfb, .pfa |
67
+ | TTC | TrueType Collection | .ttc |
68
+ | OTC | OpenType Collection | .otc |
69
+ | dfont | Apple Data Fork Font | .dfont |
70
+ | WOFF | Web Open Font Format | .woff |
71
+ | WOFF2 | Web Open Font Format 2 | .woff2 |
72
+ | SVG | SVG Font | .svg |
73
+
74
+ === Output Formats
75
+
76
+ All input formats can be converted to: TTF, OTF, WOFF, WOFF2
77
+
78
+ Collections (TTC, OTC, dfont) can be converted between each other.
79
+
80
+ == Conversion Options
81
+
82
+ === Opening Options
83
+
84
+ Opening options control how the source font is read and processed.
85
+
86
+ | Option | Type | Description | Use Case |
87
+ |--------|------|-------------|----------|
88
+ | `decompose_composites` | Boolean | Decompose composite glyphs into simple glyphs | When target format doesn't support composites |
89
+ | `convert_curves` | Boolean | Convert curve types during conversion | When converting between quadratic/cubic curves |
90
+ | `scale_to_1000` | Boolean | Scale UPM to 1000 | Type 1 → OTF conversions |
91
+ | `scale_from_1000` | Boolean | Scale from 1000 UPM | OTF → TTF conversions |
92
+ | `autohint` | Boolean | Auto-hint the font | When source lacks hints or hints are incompatible |
93
+ | `generate_unicode` | Boolean | Generate Unicode mappings from glyph names | Type 1 conversions |
94
+ | `store_custom_tables` | Boolean | Preserve non-standard tables | When custom tables need preservation |
95
+ | `store_native_hinting` | Boolean | Preserve native hinting data | When hints should be preserved for source format |
96
+ | `interpret_ot` | Boolean | Interpret OpenType layout features | When GSUB/GPOS features need processing |
97
+ | `read_all_records` | Boolean | Load all font dictionary records | Type 1 conversions with custom data |
98
+ | `preserve_encoding` | String | Preserve specific character encoding | When custom encoding must be maintained |
99
+
100
+ === Generating Options
101
+
102
+ Generating options control how the output font is written.
103
+
104
+ | Option | Type | Description | Use Case |
105
+ |--------|------|-------------|----------|
106
+ | `write_pfm` | Boolean | Write PFM file | Type 1 output |
107
+ | `write_afm` | Boolean | Write AFM file | Type 1 output |
108
+ | `write_inf` | Boolean | Write INF file | Type 1 output |
109
+ | `select_encoding_automatically` | Boolean | Auto-select encoding | Type 1 output |
110
+ | `hinting_mode` | String | Hint mode: preserve, auto, none, full | Control hinting behavior |
111
+ | `decompose_on_output` | Boolean | Decompose composites in output | When target doesn't support composites |
112
+ | `write_custom_tables` | Boolean | Write custom tables | Preserve non-standard tables |
113
+ | `optimize_tables` | Boolean | Enable table optimization | Reduce file size |
114
+ | `reencode_first_256` | Boolean | Reencode first 256 glyphs | Type 1 output |
115
+ | `encoding_vector` | String | Custom encoding vector | Type 1 output |
116
+ | `compression` | String | Compression: zlib, brotli, none | Web font output |
117
+ | `transform_tables` | Boolean | Transform tables for output | Format-specific transformations |
118
+ | `preserve_metadata` | Boolean | Preserve copyright/license metadata | Maintain font metadata |
119
+ | `strip_metadata` | Boolean | Remove metadata | Reduce file size |
120
+ | `target_format` | String | Collection target format | Collection conversions |
121
+
122
+ === CLI Option Mapping
123
+
124
+ ==== Opening Options
125
+
126
+ [source,shell]
127
+ ----
128
+ # Decompose composite glyphs
129
+ --decompose # Enable decomposition
130
+ --no-decompose # Preserve composite glyphs
131
+
132
+ # Curve conversion
133
+ --convert-curves # Convert curve types (quadratic ↔ cubic)
134
+
135
+ # UPM scaling
136
+ --scale-to-1000 # Scale to 1000 UPM (Type 1 standard)
137
+ --scale-from-1000 # Scale from 1000 UPM to target
138
+
139
+ # Hinting
140
+ --autohint # Apply automatic hinting
141
+
142
+ # Unicode and encoding
143
+ --generate-unicode # Generate Unicode from glyph names
144
+ --preserve-encoding # Preserve character encoding
145
+
146
+ # Table handling
147
+ --preserve-custom-tables # Preserve non-standard tables
148
+ --interpret-ot # Interpret OpenType tables (GSUB/GPOS)
149
+ ----
150
+
151
+ ==== Generating Options
152
+
153
+ [source,shell]
154
+ ----
155
+ # Type 1 metrics files
156
+ --write-pfm # Generate PFM file
157
+ --write-afm # Generate AFM file
158
+ --write-inf # Generate INF file
159
+
160
+ # Encoding
161
+ --auto-encoding # Auto-detect encoding
162
+ --encoding VECTOR # Use specific encoding vector
163
+
164
+ # Hinting
165
+ --hinting-mode MODE # preserve|auto|none|full
166
+
167
+ # Optimization
168
+ --optimize-tables # Enable table optimization
169
+ --no-optimization # Disable optimization
170
+
171
+ # Metadata
172
+ --preserve-metadata # Preserve copyright/license info
173
+ --strip-metadata # Remove metadata
174
+
175
+ # Collections
176
+ --target-format FORMAT # ttf|otf|preserve for collections
177
+ ----
178
+
179
+ ==== Preset Option
180
+
181
+ [source,shell]
182
+ ----
183
+ # Use named preset
184
+ --preset NAME # type1_to_modern, modern_to_type1, web_optimized, archive_to_modern
185
+ ----
186
+
187
+ == Conversion Matrix
188
+
189
+ === Same-Format Conversions
190
+
191
+ ==== TTF → TTF
192
+
193
+ Use case: Copy with optimization, metadata updates
194
+
195
+ [source,ruby]
196
+ ----
197
+ Fontisan::ConversionOptions.recommended(from: :ttf, to: :ttf)
198
+ # opening: { convert_curves: false, scale_to_1000: false,
199
+ # decompose_composites: false, autohint: false,
200
+ # store_custom_tables: true, store_native_hinting: true }
201
+ # generating: { hinting_mode: "preserve", write_custom_tables: true,
202
+ # optimize_tables: true }
203
+ ----
204
+
205
+ Notes: Same-format copy preserves all data. Optimization includes table reordering and checksum correction.
206
+
207
+ ==== OTF → OTF
208
+
209
+ Use case: Copy with optimization, metadata updates
210
+
211
+ [source,ruby]
212
+ ----
213
+ Fontisan::ConversionOptions.recommended(from: :otf, to: :otf)
214
+ # opening: { decompose_composites: false, store_custom_tables: true,
215
+ # interpret_ot: true }
216
+ # generating: { hinting_mode: "preserve", decompose_on_output: false,
217
+ # write_custom_tables: true, optimize_tables: true }
218
+ ----
219
+
220
+ Notes: CFF-based OTF requires different handling than TTF.
221
+
222
+ === TTF → OTF
223
+
224
+ Recommended options:
225
+
226
+ [source,ruby]
227
+ ----
228
+ Fontisan::ConversionOptions.recommended(from: :ttf, to: :otf)
229
+ # Returns:
230
+ # opening: { convert_curves: true, scale_to_1000: true, autohint: true,
231
+ # decompose_composites: false, store_custom_tables: true }
232
+ # generating: { hinting_mode: "auto", decompose_on_output: true }
233
+ ----
234
+
235
+ Key considerations:
236
+
237
+ * Curve conversion: Quadratic → Cubic (mathematically exact, but may increase point count)
238
+ * Hinting: TrueType instructions → CFF hints (lossy conversion)
239
+ * Scaling: Typically 2048 UPM → 1000 UPM
240
+
241
+ Limitations:
242
+
243
+ * TrueType hinting instructions are NOT converted to CFF hints
244
+ * GSUB/GPOS features preserved but table format changes
245
+
246
+ === OTF → TTF
247
+
248
+ Recommended options:
249
+
250
+ [source,ruby]
251
+ ----
252
+ Fontisan::ConversionOptions.recommended(from: :otf, to: :ttf)
253
+ # Returns:
254
+ # opening: { decompose_composites: false, read_all_records: true,
255
+ # interpret_ot: true, store_custom_tables: true,
256
+ # store_native_hinting: false }
257
+ # generating: { hinting_mode: "full", reencode_first_256: false }
258
+ ----
259
+
260
+ Key considerations:
261
+
262
+ * Curve conversion: Cubic → Quadratic (requires approximation)
263
+ * Hinting: CFF hints → TrueType instructions (lossy conversion)
264
+ * OpenType features: Interpreted before conversion
265
+
266
+ Limitations:
267
+
268
+ * CFF cubic curves must be approximated as TrueType quadratic curves
269
+ * Multiple quadratic curves may be needed for accuracy
270
+ * Some precision loss in curve approximation is unavoidable
271
+
272
+ === Type 1 Conversions
273
+
274
+ ==== Type 1 → OTF
275
+
276
+ Recommended options:
277
+
278
+ [source,ruby]
279
+ ----
280
+ Fontisan::ConversionOptions.recommended(from: :type1, to: :otf)
281
+ # Returns:
282
+ # opening: { decompose_composites: false, generate_unicode: true }
283
+ # generating: { hinting_mode: "none", decompose_on_output: true }
284
+ ----
285
+
286
+ Key considerations:
287
+
288
+ * Unicode: Generated from Adobe Glyph List
289
+ * CharStrings: Type 1 → CFF format (direct conversion)
290
+ * Hinting: PostScript hints preserved in CFF
291
+ * seac composites: Must be expanded (CFF doesn't support seac)
292
+
293
+ ==== Type 1 → TTF
294
+
295
+ Recommended options:
296
+
297
+ [source,ruby]
298
+ ----
299
+ Fontisan::ConversionOptions.recommended(from: :type1, to: :ttf)
300
+ # Returns:
301
+ # opening: { decompose_composites: false, generate_unicode: true }
302
+ # generating: { hinting_mode: "full" }
303
+ ----
304
+
305
+ Workflow: Type 1 → CFF (OTF) → TTF
306
+
307
+ Key considerations:
308
+
309
+ * Two-step conversion compounds approximation errors
310
+ * Curve conversion: CFF cubic → TrueType quadratic
311
+ * Unicode: Generated from glyph names
312
+
313
+ ==== Type 1 → Type 1 (Copy)
314
+
315
+ Use case: Re-encode Type 1 font, regenerate metrics
316
+
317
+ [source,ruby]
318
+ ----
319
+ Fontisan::ConversionOptions.recommended(from: :type1, to: :type1)
320
+ # opening: { decompose_composites: false, generate_unicode: true }
321
+ # generating: { write_pfm: true, write_afm: true, write_inf: true,
322
+ # select_encoding_automatically: true, hinting_mode: "preserve" }
323
+ ----
324
+
325
+ ==== OTF → Type 1
326
+
327
+ Use case: Generate Type 1 from OpenType for legacy workflows
328
+
329
+ [source,ruby]
330
+ ----
331
+ Fontisan::ConversionOptions.recommended(from: :otf, to: :type1)
332
+ # opening: { decompose_composites: false }
333
+ # generating: { write_pfm: true, write_afm: true, write_inf: true,
334
+ # select_encoding_automatically: true, hinting_mode: "preserve",
335
+ # decompose_on_output: false }
336
+ ----
337
+
338
+ Limitations:
339
+
340
+ * Reverse conversion from CFF to Type 1
341
+ * Modern OpenType features (GPOS, GSUB variations) lost in Type 1
342
+ * CFF hints may not translate exactly to Type 1 hints
343
+
344
+ === Collection Conversions
345
+
346
+ ==== TTC → OTC
347
+
348
+ [source,ruby]
349
+ ----
350
+ Fontisan::ConversionOptions.recommended(from: :ttc, to: :otc)
351
+ # opening: { convert_curves: true, decompose_composites: false, autohint: false }
352
+ # generating: { target_format: "otf", decompose_on_output: false,
353
+ # hinting_mode: "preserve" }
354
+ ----
355
+
356
+ Converts all TrueType fonts to OpenType/CFF, then repacks as OTC.
357
+
358
+ ==== OTC → TTC
359
+
360
+ [source,ruby]
361
+ ----
362
+ Fontisan::ConversionOptions.recommended(from: :otc, to: :ttc)
363
+ # opening: { convert_curves: true, decompose_composites: false, interpret_ot: true }
364
+ # generating: { target_format: "ttf", decompose_on_output: false,
365
+ # hinting_mode: "auto" }
366
+ ----
367
+
368
+ Converts all OpenType/CFF fonts to TrueType, then repacks as TTC.
369
+
370
+ ==== TTC/OTC → dfont
371
+
372
+ [source,ruby]
373
+ ----
374
+ Fontisan::ConversionOptions.recommended(from: :ttc, to: :dfont)
375
+ # opening: {}
376
+ # generating: { target_format: "preserve", decompose_on_output: false,
377
+ # write_custom_tables: true }
378
+ ----
379
+
380
+ Notes: dfont supports both TrueType and OpenType/CFF, or mixed formats.
381
+
382
+ === Web Font Conversions
383
+
384
+ ==== TTF/OTF → WOFF2
385
+
386
+ [source,ruby]
387
+ ----
388
+ Fontisan::ConversionOptions.from_preset(:web_optimized)
389
+ # From: :otf, To: :woff2
390
+ # opening: {}
391
+ # generating: { compression: "brotli", transform_tables: true,
392
+ # optimize_tables: true, preserve_metadata: true }
393
+ ----
394
+
395
+ Benefits: 30-50% smaller than TTF/OTF
396
+
397
+ ==== TTF/OTF → WOFF
398
+
399
+ [source,ruby]
400
+ ----
401
+ # generating: { compression: "zlib", preserve_metadata: true,
402
+ # add_private_data: false }
403
+ ----
404
+
405
+ ==== Type 1 → WOFF/WOFF2
406
+
407
+ Workflow: Type 1 → OTF → WOFF2
408
+
409
+ [source,ruby]
410
+ ----
411
+ # Via OTF intermediate
412
+ # opening: { decompose_composites: false, generate_unicode: true }
413
+ # generating: { compression: "brotli" } # WOFF2
414
+ # OR compression: "zlib" # WOFF
415
+ ----
416
+
417
+ === SVG Font Generation
418
+
419
+ ==== TTF/OTF → SVG
420
+
421
+ [source,ruby]
422
+ ----
423
+ # opening: {}
424
+ # generating: { include_metadata: true, include_unicode: true }
425
+ ----
426
+
427
+ Limitations:
428
+
429
+ * SVG fonts deprecated in favor of WOFF2
430
+ * No hinting information
431
+ * No advanced layout features
432
+
433
+ == Presets
434
+
435
+ === type1_to_modern
436
+
437
+ Optimize Type 1 fonts for modern use:
438
+
439
+ [source,ruby]
440
+ ----
441
+ Fontisan::ConversionOptions.from_preset(:type1_to_modern)
442
+ # From: :type1, To: :otf
443
+ # opening: { generate_unicode: true, decompose_composites: false }
444
+ # generating: { hinting_mode: "preserve", decompose_on_output: true }
445
+ ----
446
+
447
+ Use cases:
448
+
449
+ * Modernizing legacy Type 1 fonts
450
+ * Preparing fonts for web use
451
+ * Converting fonts for modern applications
452
+
453
+ === modern_to_type1
454
+
455
+ Convert modern fonts back to Type 1:
456
+
457
+ [source,ruby]
458
+ ----
459
+ Fontisan::ConversionOptions.from_preset(:modern_to_type1)
460
+ # From: :otf, To: :type1
461
+ # opening: { convert_curves: true, scale_to_1000: true,
462
+ # autohint: true, decompose_composites: false,
463
+ # store_custom_tables: false }
464
+ # generating: { write_pfm: true, write_afm: true, write_inf: true,
465
+ # select_encoding_automatically: true,
466
+ # hinting_mode: "preserve" }
467
+ ----
468
+
469
+ Use cases:
470
+
471
+ * Legacy system compatibility
472
+ * Font distribution for older applications
473
+ * Working with Type 1 workflows
474
+
475
+ === web_optimized
476
+
477
+ Optimize fonts for web delivery:
478
+
479
+ [source,ruby]
480
+ ----
481
+ Fontisan::ConversionOptions.from_preset(:web_optimized)
482
+ # From: :otf, To: :woff2
483
+ # opening: {}
484
+ # generating: { compression: "brotli", transform_tables: true,
485
+ # optimize_tables: true, preserve_metadata: true }
486
+ ----
487
+
488
+ Use cases:
489
+
490
+ * Web font delivery
491
+ * Reducing page load time
492
+ * Bandwidth optimization
493
+
494
+ === archive_to_modern
495
+
496
+ Convert font archives to modern format:
497
+
498
+ [source,ruby]
499
+ ----
500
+ Fontisan::ConversionOptions.from_preset(:archive_to_modern)
501
+ # From: :ttc, To: :otf
502
+ # opening: { convert_curves: true, decompose_composites: false }
503
+ # generating: { target_format: "otf", hinting_mode: "preserve" }
504
+ ----
505
+
506
+ Use cases:
507
+
508
+ * Extracting fonts from TTC archives
509
+ * Standardizing collection formats
510
+ * Converting legacy font collections
511
+
512
+ == Hinting Modes
513
+
514
+ === preserve
515
+
516
+ Preserve original hinting data when possible:
517
+
518
+ * Works best when source and target formats share hinting systems
519
+ * TTF → TTF: TrueType instructions preserved
520
+ * OTF → OTF: PostScript hints preserved
521
+ * Cross-format: May result in lost hints
522
+
523
+ === auto
524
+
525
+ Apply automatic hinting:
526
+
527
+ * TTF → OTF: Autohinting applied to CFF output
528
+ * OTF → TTF: Autohinting applied to TrueType output
529
+ * Type 1 → Modern: Autohinting based on outlines
530
+
531
+ === none
532
+
533
+ Remove all hinting:
534
+
535
+ * Smallest file size
536
+ * No rendering optimizations
537
+ * Useful for web fonts where file size matters more than rendering quality
538
+
539
+ === full
540
+
541
+ Full hinting conversion:
542
+
543
+ * Attempts to preserve all hint information
544
+ * May generate larger files
545
+ * Best quality for print applications
546
+
547
+ == Best Practices
548
+
549
+ === Choose the Right Options
550
+
551
+ 1. *Use presets when possible* - Presets are optimized for common workflows
552
+ 2. *Show options first* - Use `--show-options` to understand what will be applied
553
+ 3. *Test conversions* - Always verify output fonts in target applications
554
+ 4. *Preserve metadata* - Keep copyright and license information intact
555
+
556
+ === Performance Considerations
557
+
558
+ * Decompose composites only when necessary (increases file size)
559
+ * Enable optimization only for production (slower conversion)
560
+ * Use `--no-validate` for faster iterations during development
561
+
562
+ === Quality Considerations
563
+
564
+ * Use `preserve` hinting mode for best rendering quality
565
+ * Enable autohinting when converting between incompatible hint systems
566
+ * Generate Unicode mappings for Type 1 fonts to ensure proper character display
567
+
568
+ == Examples
569
+
570
+ === Convert Type 1 to Web Font
571
+
572
+ [source,shell]
573
+ ----
574
+ # Convert directly to WOFF2
575
+ fontisan convert font.pfb --to woff2 --output font.woff2 --preset type1_to_modern
576
+
577
+ # With custom options
578
+ fontisan convert font.pfb --to woff2 --output font.woff2 \
579
+ --generate-unicode --optimize-tables
580
+ ----
581
+
582
+ === Convert Collection with Standardization
583
+
584
+ [source,shell]
585
+ ----
586
+ # Convert TTC to OTC, standardizing all to OpenType
587
+ fontisan convert family.ttc --to otc --output family.otc \
588
+ --target-format otf --preset archive_to_modern
589
+ ----
590
+
591
+ === Convert with Hint Preservation
592
+
593
+ [source,shell]
594
+ ----
595
+ # Convert TTF to OTF, attempting to preserve hints
596
+ fontisan convert font.ttf --to otf --output font.otf \
597
+ --hinting-mode preserve --preserve-hints
598
+ ----
599
+
600
+ == Troubleshooting
601
+
602
+ === Conversion Fails
603
+
604
+ 1. Check if source file is valid: `fontisan info font.ttf`
605
+ 2. Validate source font: `fontisan validate font.ttf`
606
+ 3. Try with `--verbose` flag for detailed error messages
607
+ 4. Use `--no-validate` to skip output validation
608
+
609
+ === Output Font Too Large
610
+
611
+ 1. Enable table optimization: `--optimize-tables`
612
+ 2. Remove hinting: `--hinting-mode none`
613
+ 3. Use web font compression: `--to woff2`
614
+ 4. Decompose composites only if needed
615
+
616
+ === Poor Rendering Quality
617
+
618
+ 1. Use `--hinting-mode auto` or `preserve`
619
+ 2. Enable autohinting: `--autohint`
620
+ 3. Verify source font quality first
621
+ 4. Test in target application
622
+
623
+ === Missing Characters
624
+
625
+ 1. For Type 1: Enable `--generate-unicode`
626
+ 2. Check source font's glyph coverage
627
+ 3. Verify cmap table in output: `fontisan unicode output.ttf`
628
+
629
+ == See Also
630
+
631
+ * link:TYPE1_FONTS.adoc[Type 1 Font Support] - Type 1 specific documentation
632
+ * link:README.adoc[README] - Main Fontisan documentation
633
+ * https://github.com/fontist/fontisan[Fontisan on GitHub] - Report issues and contribute