fontisan 0.2.13 → 0.2.16

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.
Files changed (145) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +56 -196
  3. data/Gemfile +1 -1
  4. data/docs/.gitignore +17 -0
  5. data/docs/.vitepress/config.ts +317 -0
  6. data/docs/.vitepress/theme/components/ApiMethod.vue +127 -0
  7. data/docs/.vitepress/theme/components/Badge.vue +51 -0
  8. data/docs/.vitepress/theme/components/FeatureComparison.vue +87 -0
  9. data/docs/.vitepress/theme/components/HeroCodeBlock.vue +98 -0
  10. data/docs/.vitepress/theme/components/WithinHero.vue +30 -0
  11. data/docs/.vitepress/theme/index.ts +22 -0
  12. data/docs/.vitepress/theme/style.css +330 -0
  13. data/docs/api/conversion-options.md +141 -0
  14. data/docs/api/converters/curve-converter.md +34 -0
  15. data/docs/api/converters/hint-converter.md +34 -0
  16. data/docs/api/converters/outline-converter.md +27 -0
  17. data/docs/api/font-loader.md +111 -0
  18. data/docs/api/font-writer.md +103 -0
  19. data/docs/api/index.md +79 -0
  20. data/docs/api/models/glyph-accessor.md +43 -0
  21. data/docs/api/models/glyph.md +40 -0
  22. data/docs/api/models/table-analyzer.md +35 -0
  23. data/docs/api/sfnt-font.md +53 -0
  24. data/docs/api/type1-font.md +43 -0
  25. data/docs/api/validators/font-validator.md +31 -0
  26. data/docs/api/validators/helper.md +36 -0
  27. data/docs/api/validators/profile.md +39 -0
  28. data/docs/cli/convert.md +87 -0
  29. data/docs/cli/dump-table.md +110 -0
  30. data/docs/cli/export.md +176 -0
  31. data/docs/cli/features.md +124 -0
  32. data/docs/cli/glyphs.md +90 -0
  33. data/docs/cli/index.md +208 -0
  34. data/docs/cli/info.md +254 -0
  35. data/docs/cli/instance.md +122 -0
  36. data/docs/cli/ls.md +95 -0
  37. data/docs/cli/optical-size.md +94 -0
  38. data/docs/cli/pack.md +125 -0
  39. data/docs/cli/scripts.md +105 -0
  40. data/docs/cli/subset.md +39 -0
  41. data/docs/cli/tables.md +84 -0
  42. data/docs/cli/unicode.md +101 -0
  43. data/docs/cli/validate.md +48 -0
  44. data/docs/cli/variable.md +126 -0
  45. data/docs/cli/version.md +46 -0
  46. data/docs/guide/cli/convert.md +108 -0
  47. data/docs/guide/cli/export.md +138 -0
  48. data/docs/guide/cli/index.md +99 -0
  49. data/docs/guide/cli/info.md +144 -0
  50. data/docs/guide/cli/pack.md +155 -0
  51. data/docs/guide/cli/subset.md +118 -0
  52. data/docs/guide/cli/validate.md +139 -0
  53. data/docs/guide/color-fonts/bitmaps.md +177 -0
  54. data/docs/guide/color-fonts/colr-cpal.md +175 -0
  55. data/docs/guide/color-fonts/index.md +140 -0
  56. data/docs/guide/color-fonts/svg.md +154 -0
  57. data/docs/guide/color.md +51 -0
  58. data/docs/guide/comparisons/font-validator.md +222 -0
  59. data/docs/guide/comparisons/fonttools.md +200 -0
  60. data/docs/guide/comparisons/index.md +83 -0
  61. data/docs/guide/comparisons/lcdf-typetools.md +205 -0
  62. data/docs/guide/contributing.md +279 -0
  63. data/docs/guide/conversion/collections.md +251 -0
  64. data/docs/guide/conversion/curves.md +246 -0
  65. data/docs/guide/conversion/index.md +157 -0
  66. data/docs/guide/conversion/options.md +251 -0
  67. data/docs/guide/conversion/ttf-otf.md +184 -0
  68. data/docs/guide/conversion/type1.md +208 -0
  69. data/docs/guide/conversion/web.md +240 -0
  70. data/docs/guide/conversion.md +39 -0
  71. data/docs/guide/formats/collections.md +147 -0
  72. data/docs/guide/formats/dfont.md +99 -0
  73. data/docs/guide/formats/index.md +65 -0
  74. data/docs/guide/formats/otf.md +103 -0
  75. data/docs/guide/formats/svg.md +97 -0
  76. data/docs/guide/formats/ttf.md +105 -0
  77. data/docs/guide/formats/type1.md +118 -0
  78. data/docs/guide/formats/woff.md +115 -0
  79. data/docs/guide/hinting/autohint.md +141 -0
  80. data/docs/guide/hinting/conversion.md +161 -0
  81. data/docs/guide/hinting/index.md +86 -0
  82. data/docs/guide/hinting/postscript.md +149 -0
  83. data/docs/guide/hinting/truetype.md +135 -0
  84. data/docs/guide/hinting.md +44 -0
  85. data/docs/guide/index.md +152 -0
  86. data/docs/guide/installation.md +116 -0
  87. data/docs/guide/migrations/extract-ttc.md +549 -0
  88. data/docs/guide/migrations/font-validator.md +260 -0
  89. data/docs/guide/migrations/fonttools.md +208 -0
  90. data/docs/guide/migrations/index.md +64 -0
  91. data/docs/guide/migrations/otfinfo.md +197 -0
  92. data/docs/guide/quick-start.md +204 -0
  93. data/docs/guide/type1.md +58 -0
  94. data/docs/guide/universal-outline.md +151 -0
  95. data/docs/guide/validation/custom.md +195 -0
  96. data/docs/guide/validation/helpers.md +188 -0
  97. data/docs/guide/validation/index.md +132 -0
  98. data/docs/guide/validation/profiles.md +156 -0
  99. data/docs/guide/validation.md +47 -0
  100. data/docs/guide/variable-fonts/advanced.md +231 -0
  101. data/docs/guide/variable-fonts/axes.md +209 -0
  102. data/docs/guide/variable-fonts/conversion.md +197 -0
  103. data/docs/guide/variable-fonts/index.md +84 -0
  104. data/docs/guide/variable-fonts/instances.md +187 -0
  105. data/docs/guide/variable-fonts/named-instances.md +194 -0
  106. data/docs/guide/variable-fonts/static.md +168 -0
  107. data/docs/guide/variable.md +58 -0
  108. data/docs/guide/woff.md +59 -0
  109. data/docs/index.md +136 -0
  110. data/docs/lychee.toml +37 -0
  111. data/docs/package-lock.json +2560 -0
  112. data/docs/package.json +15 -0
  113. data/docs/public/apple-touch-icon.png +0 -0
  114. data/docs/public/favicon-96x96.png +0 -0
  115. data/docs/public/favicon.ico +0 -0
  116. data/docs/public/favicon.svg +1 -0
  117. data/docs/public/logo-full.svg +1 -0
  118. data/docs/public/logo.svg +1 -0
  119. data/docs/public/site.webmanifest +21 -0
  120. data/docs/public/web-app-manifest-192x192.png +0 -0
  121. data/docs/public/web-app-manifest-512x512.png +0 -0
  122. data/fontisan.gemspec +1 -1
  123. data/lib/fontisan/commands/features_command.rb +0 -1
  124. data/lib/fontisan/commands/info_command.rb +5 -5
  125. data/lib/fontisan/commands/scripts_command.rb +0 -1
  126. data/lib/fontisan/converters/format_converter.rb +2 -1
  127. data/lib/fontisan/converters/type1_converter.rb +65 -60
  128. data/lib/fontisan/hints/hint_converter.rb +2 -1
  129. data/lib/fontisan/loading_modes.rb +0 -2
  130. data/lib/fontisan/open_type_font.rb +0 -40
  131. data/lib/fontisan/sfnt_font.rb +41 -22
  132. data/lib/fontisan/tables/glyf/compound_glyph.rb +0 -1
  133. data/lib/fontisan/true_type_collection.rb +8 -8
  134. data/lib/fontisan/true_type_font.rb +1 -59
  135. data/lib/fontisan/type1/afm_parser.rb +2 -1
  136. data/lib/fontisan/type1/cff_to_type1_converter.rb +24 -19
  137. data/lib/fontisan/type1/private_dict.rb +28 -7
  138. data/lib/fontisan/type1/seac_expander.rb +22 -17
  139. data/lib/fontisan/variable/delta_applicator.rb +3 -3
  140. data/lib/fontisan/variation/optimizer.rb +0 -1
  141. data/lib/fontisan/version.rb +1 -1
  142. data/lib/fontisan/woff2_font.rb +2 -2
  143. data/lib/fontisan/woff_font.rb +3 -3
  144. data/lib/fontisan.rb +3 -2
  145. metadata +122 -4
@@ -0,0 +1,118 @@
1
+ ---
2
+ title: Type 1 (PFB/PFA)
3
+ ---
4
+
5
+ # Type 1 (PFB/PFA)
6
+
7
+ Adobe Type 1 fonts are legacy PostScript fonts.
8
+
9
+ ## Overview
10
+
11
+ - **Curve Type**: Cubic Bézier
12
+ - **Hinting**: PostScript hints
13
+ - **Formats**: PFB (binary), PFA (ASCII)
14
+
15
+ ## File Formats
16
+
17
+ | Format | Extension | Description |
18
+ |--------|-----------|-------------|
19
+ | PFB | .pfb | Binary format |
20
+ | PFA | .pfa | ASCII format |
21
+
22
+ ## Structure
23
+
24
+ Type 1 fonts contain:
25
+
26
+ 1. **Font Dictionary** — Font info, encoding
27
+ 2. **Private Dictionary** — Hinting parameters
28
+ 3. **CharStrings** — Glyph outlines
29
+ 4. **Subroutines** — Reusable outline segments
30
+
31
+ ## Encryption
32
+
33
+ Type 1 fonts use encryption:
34
+
35
+ | Section | Key |
36
+ |---------|-----|
37
+ | eexec | 55665 |
38
+ | CharStrings | 4330 |
39
+
40
+ Fontisan handles decryption automatically.
41
+
42
+ ## Loading
43
+
44
+ ```ruby
45
+ font = Fontisan::FontLoader.load('font.pfb')
46
+
47
+ # Access font info
48
+ puts "Family: #{font.family_name}"
49
+ puts "Glyphs: #{font.glyph_count}"
50
+ ```
51
+
52
+ ## CharStrings
53
+
54
+ ```ruby
55
+ # Type 1 CharStrings use operators
56
+ # hstem, vstem, moveto, lineto, curveto, etc.
57
+
58
+ font.charstrings.each do |glyph_name, charstring|
59
+ puts "#{glyph_name}: #{charstring.length} bytes"
60
+ end
61
+ ```
62
+
63
+ ## seac Composites
64
+
65
+ Type 1 supports composite characters via `seac`:
66
+
67
+ ```
68
+ # Example: é = e + acute accent
69
+ # seac references two glyphs by name
70
+ ```
71
+
72
+ When converting to CFF, seac must be expanded (CFF doesn't support it).
73
+
74
+ ## Converting
75
+
76
+ ### Type 1 to OTF
77
+
78
+ ```bash
79
+ fontisan convert font.pfb --to otf --output font.otf
80
+ ```
81
+
82
+ ### Type 1 to TTF
83
+
84
+ ```bash
85
+ fontisan convert font.pfb --to ttf --output font.ttf
86
+ ```
87
+
88
+ ### With Unicode Generation
89
+
90
+ ```bash
91
+ # Generate Unicode mappings from glyph names
92
+ fontisan convert font.pfb --to otf --generate-unicode --output font.otf
93
+ ```
94
+
95
+ ## Characteristics
96
+
97
+ ### Advantages
98
+
99
+ - **Print workflows** — PostScript native
100
+ - **High quality** — Professional fonts
101
+ - **Cubic curves** — Fewer points
102
+
103
+ ### Limitations
104
+
105
+ - **Legacy format** — Modern systems prefer OTF
106
+ - **Limited Unicode** — Requires glyph name mapping
107
+ - **No native Unicode** — Must be generated
108
+
109
+ ## seac Expansion
110
+
111
+ seac (Standard Encoding Accented Character) must be expanded for CFF:
112
+
113
+ ```ruby
114
+ # Fontisan automatically expands seac during conversion
115
+ options = Fontisan::ConversionOptions.new(
116
+ opening: { decompose_composites: true }
117
+ )
118
+ ```
@@ -0,0 +1,115 @@
1
+ ---
2
+ title: WOFF & WOFF2
3
+ ---
4
+
5
+ # WOFF & WOFF2
6
+
7
+ Web Open Font Format (WOFF and WOFF2) are optimized for web delivery.
8
+
9
+ ## Overview
10
+
11
+ | Format | Compression | Browser Support |
12
+ |--------|-------------|-----------------|
13
+ | WOFF | zlib | All modern browsers |
14
+ | WOFF2 | brotli | Modern browsers |
15
+
16
+ ## WOFF2 Benefits
17
+
18
+ - 30-50% smaller than TTF/OTF
19
+ - Preprocessing transforms for better compression
20
+ - Modern browser support
21
+
22
+ ## Converting to WOFF
23
+
24
+ ```bash
25
+ # From TTF
26
+ fontisan convert font.ttf --to woff --output font.woff
27
+
28
+ # From OTF
29
+ fontisan convert font.otf --to woff --output font.woff
30
+ ```
31
+
32
+ ## Converting to WOFF2
33
+
34
+ ```bash
35
+ # From TTF
36
+ fontisan convert font.ttf --to woff2 --output font.woff2
37
+
38
+ # From OTF
39
+ fontisan convert font.otf --to woff2 --output font.woff2
40
+
41
+ # From Type 1
42
+ fontisan convert font.pfb --to woff2 --output font.woff2
43
+ ```
44
+
45
+ ## API Usage
46
+
47
+ ```ruby
48
+ options = Fontisan::ConversionOptions.from_preset(:web_optimized)
49
+ # From: :otf, To: :woff2
50
+ # generating: { compression: "brotli", transform_tables: true }
51
+
52
+ Fontisan::FontWriter.write(font, 'font.woff2', options: options)
53
+ ```
54
+
55
+ ## Compression Options
56
+
57
+ ### brotli (WOFF2)
58
+
59
+ ```ruby
60
+ generating: { compression: "brotli" }
61
+ ```
62
+
63
+ Best compression ratio.
64
+
65
+ ### zlib (WOFF)
66
+
67
+ ```ruby
68
+ generating: { compression: "zlib" }
69
+ ```
70
+
71
+ Wide compatibility.
72
+
73
+ ## Table Transforms
74
+
75
+ WOFF2 supports table transformations:
76
+
77
+ | Table | Transform |
78
+ |-------|-----------|
79
+ | glyf | Combined with loca |
80
+ | hmtx | Combined with hhea |
81
+ | CFF | De-subroutinization |
82
+
83
+ ```ruby
84
+ options = Fontisan::ConversionOptions.new(
85
+ to: :woff2,
86
+ generating: { transform_tables: true }
87
+ )
88
+ ```
89
+
90
+ ## Converting from WOFF
91
+
92
+ ```bash
93
+ # WOFF to TTF
94
+ fontisan convert font.woff --to ttf --output font.ttf
95
+
96
+ # WOFF2 to OTF
97
+ fontisan convert font.woff2 --to otf --output font.otf
98
+ ```
99
+
100
+ ## Browser Support
101
+
102
+ | Browser | WOFF | WOFF2 |
103
+ |---------|------|-------|
104
+ | Chrome | 5+ | 36+ |
105
+ | Firefox | 3.6+ | 35+ |
106
+ | Safari | 5.1+ | 12+ |
107
+ | Edge | All | 14+ |
108
+ | IE | 9+ | — |
109
+
110
+ ## Best Practices
111
+
112
+ 1. **Use WOFF2 primarily** — Best compression
113
+ 2. **Provide WOFF fallback** — For older browsers
114
+ 3. **Keep original** — For editing
115
+ 4. **Preserve metadata** — Unless stripping for size
@@ -0,0 +1,141 @@
1
+ ---
2
+ title: Autohint
3
+ ---
4
+
5
+ # Autohint
6
+
7
+ Fontisan supports automatic hint generation for fonts without hints or when converting between formats.
8
+
9
+ ## Overview
10
+
11
+ Autohinting generates hint data automatically based on glyph outlines. This is useful when:
12
+
13
+ - Source font lacks hints
14
+ - Converting between incompatible hint systems
15
+ - Improving rendering quality
16
+
17
+ ## CLI Usage
18
+
19
+ ```bash
20
+ # Enable autohinting during conversion
21
+ fontisan convert font.ttf --to otf --autohint --output font.otf
22
+
23
+ # With specific hinting mode
24
+ fontisan convert font.ttf --to otf --autohint --hinting-mode auto
25
+ ```
26
+
27
+ ## API Usage
28
+
29
+ ```ruby
30
+ options = Fontisan::ConversionOptions.new(
31
+ opening: { autohint: true },
32
+ generating: { hinting_mode: "auto" }
33
+ )
34
+
35
+ converter = Fontisan::Converters::OutlineConverter.new
36
+ result = converter.convert(font, options: options)
37
+ ```
38
+
39
+ ## Hinting Modes
40
+
41
+ | Mode | Description | Use Case |
42
+ |------|-------------|----------|
43
+ | `preserve` | Keep original hints | Same-format conversions |
44
+ | `auto` | Apply automatic hinting | Cross-format, missing hints |
45
+ | `none` | Remove all hints | Smallest file size |
46
+ | `full` | Full hint conversion | Maximum quality |
47
+
48
+ ## When to Use Autohint
49
+
50
+ ### Use Autohint When:
51
+
52
+ - Converting TTF to OTF (different hint systems)
53
+ - Converting OTF to TTF (different hint systems)
54
+ - Source font has no hints
55
+ - Source hints are corrupt or incomplete
56
+
57
+ ### Don't Use Autohint When:
58
+
59
+ - Converting same format (TTF → TTF, OTF → OTF)
60
+ - Source has good TrueType instructions
61
+ - Source has good PostScript hints
62
+ - Target application doesn't use hints
63
+
64
+ ## Autohint Process
65
+
66
+ ### For TrueType Output
67
+
68
+ 1. Analyze glyph outlines
69
+ 2. Detect stem widths and positions
70
+ 3. Generate CVT table with common values
71
+ 4. Create prep program with basic setup
72
+ 5. Leave fpgm empty (no glyph programs)
73
+
74
+ ### For OpenType Output
75
+
76
+ 1. Analyze glyph outlines
77
+ 2. Detect blue zones (baseline, x-height, cap height)
78
+ 3. Detect stem widths
79
+ 4. Generate Private DICT parameters
80
+ 5. Create stem hints in CharStrings
81
+
82
+ ## Quality
83
+
84
+ ### Autohint Limitations
85
+
86
+ - **No glyph-specific instructions** — Only global hints
87
+ - **May not match hand-tuned hints** — Quality varies
88
+ - **Better than no hints** — Generally improves rendering
89
+
90
+ ### Comparison
91
+
92
+ | Source | Autohint | Hand-Tuned |
93
+ |--------|----------|------------|
94
+ | Quality | Good | Best |
95
+ | Consistency | High | Varies |
96
+ | Time | Fast | Slow |
97
+ | Cost | Free | Expensive |
98
+
99
+ ## Examples
100
+
101
+ ### Convert with Autohint
102
+
103
+ ```bash
104
+ # Type 1 to OTF with autohint
105
+ fontisan convert font.pfb --to otf --autohint --output font.otf
106
+ ```
107
+
108
+ ### Remove and Regenerate Hints
109
+
110
+ ```bash
111
+ # Remove existing hints, add autohints
112
+ fontisan convert font.ttf --to ttf --hinting-mode none --autohint --output font-rehinted.ttf
113
+ ```
114
+
115
+ ### Batch Processing
116
+
117
+ ```ruby
118
+ Dir.glob('fonts/*.ttf').each do |input|
119
+ output = input.sub('.ttf', '-hinted.ttf')
120
+ options = Fontisan::ConversionOptions.new(
121
+ opening: { autohint: true },
122
+ generating: { hinting_mode: "auto" }
123
+ )
124
+
125
+ font = Fontisan::FontLoader.load(input)
126
+ converter = Fontisan::Converters::OutlineConverter.new
127
+ result = converter.convert(font, options: options)
128
+ Fontisan::FontWriter.write(result, output)
129
+ end
130
+ ```
131
+
132
+ ## Testing Hints
133
+
134
+ After autohinting, test rendering quality:
135
+
136
+ ```bash
137
+ # Generate sample images at small sizes
138
+ fontisan render font-hinted.ttf --size 8 --output sample-8pt.png
139
+ fontisan render font-hinted.ttf --size 10 --output sample-10pt.png
140
+ fontisan render font-hinted.ttf --size 12 --output sample-12pt.png
141
+ ```
@@ -0,0 +1,161 @@
1
+ ---
2
+ title: Hint Conversion
3
+ ---
4
+
5
+ # Hint Conversion
6
+
7
+ Fontisan provides bidirectional hint conversion between TrueType and PostScript formats.
8
+
9
+ ## Overview
10
+
11
+ | Direction | From | To | Process |
12
+ |-----------|------|-----|---------|
13
+ | TTF → OTF | TrueType instructions | PostScript hints | Analyze bytecode |
14
+ | OTF → TTF | PostScript hints | TrueType instructions | Generate bytecode |
15
+
16
+ ## TTF → OTF Conversion
17
+
18
+ ### Process
19
+
20
+ ```
21
+ TrueType Font → Instruction Analysis → PostScript Parameters → CFF Table
22
+ (Input) (prep/fpgm/cvt) (Hint Dict) (Output)
23
+ ```
24
+
25
+ ### Analysis Steps
26
+
27
+ 1. Parse prep (Control Value Program) bytecode
28
+ 2. Analyze fpgm (Font Program) for complexity indicators
29
+ 3. Extract blue zones from CVT (Control Value Table) values
30
+ 4. Extract stem widths and alignment zones
31
+
32
+ ### Generated Parameters
33
+
34
+ | Parameter | Source |
35
+ |-----------|--------|
36
+ | `blue_scale` | CVT analysis |
37
+ | `std_hw` | CVT[0] (standard horizontal stem) |
38
+ | `std_vw` | CVT[1] (standard vertical stem) |
39
+ | `stem_snap_h` | CVT analysis |
40
+ | `stem_snap_v` | CVT analysis |
41
+ | `blue_values` | CVT analysis (baseline, cap) |
42
+ | `other_blues` | CVT analysis (descender) |
43
+
44
+ ### CLI
45
+
46
+ ```bash
47
+ fontisan convert font.ttf --to otf --hinting-mode preserve
48
+ ```
49
+
50
+ ### API
51
+
52
+ ```ruby
53
+ converter = Fontisan::Converters::HintConverter.new
54
+
55
+ # Convert TrueType hints to PostScript
56
+ ps_hints = converter.truetype_to_postscript(font)
57
+
58
+ # Result contains:
59
+ # {
60
+ # blue_scale: 0.039625,
61
+ # std_hw: 80,
62
+ # std_vw: 100,
63
+ # blue_values: [-20, 0, 700, 720],
64
+ # stem_snap_h: [80, 90],
65
+ # stem_snap_v: [100, 110]
66
+ # }
67
+ ```
68
+
69
+ ## OTF → TTF Conversion
70
+
71
+ ### Process
72
+
73
+ ```
74
+ OTF Font → Parameter Extraction → Instruction Generation → TrueType Tables
75
+ (Input) (CFF Private Dict) (prep/fpgm/cvt) (Output)
76
+ ```
77
+
78
+ ### Generation Steps
79
+
80
+ 1. Generate prep program with CVT cut-in, single width settings
81
+ 2. Build CVT table with stem widths and blue zone values
82
+ 3. Create fpgm program (typically empty for converted fonts)
83
+ 4. Encode instructions using optimal PUSH opcodes
84
+
85
+ ### Generated Tables
86
+
87
+ | Table | Content |
88
+ |-------|---------|
89
+ | `prep` | Control Value Program with hint setup |
90
+ | `cvt` | Control Value Table with stems and blue zones |
91
+ | `fpgm` | Font Program (empty for converted fonts) |
92
+
93
+ ### CLI
94
+
95
+ ```bash
96
+ fontisan convert font.otf --to ttf --hinting-mode preserve
97
+ ```
98
+
99
+ ### API
100
+
101
+ ```ruby
102
+ converter = Fontisan::Converters::HintConverter.new
103
+
104
+ # Convert PostScript hints to TrueType
105
+ ttf_tables = converter.postscript_to_truetype(font)
106
+
107
+ # Result contains:
108
+ # {
109
+ # prep: "\xB0\x11\x1D", # Bytecode
110
+ # cvt: [80, 100, -20, 0, 700, 720],
111
+ # fpgm: ""
112
+ # }
113
+ ```
114
+
115
+ ## Round-Trip Conversion
116
+
117
+ Fontisan ensures hint integrity through round-trip conversion:
118
+
119
+ ```
120
+ Original PS Hints → TrueType → PostScript → Validation
121
+ (Input) (Convert) (Convert) (Verify)
122
+ ```
123
+
124
+ ### Round-Trip Guarantees
125
+
126
+ - CVT values preserved (sorted and deduplicated)
127
+ - Standard widths (std_hw, std_vw) maintained
128
+ - Blue zone values retained
129
+ - <10% loss tolerance for approximations
130
+
131
+ ### Known Limitations
132
+
133
+ - CVT sorting may change positions (optimization trade-off)
134
+ - blue_scale not perfectly round-trippable (conversion approximation)
135
+ - Standard widths extracted from CVT[0] and CVT[1] positions
136
+
137
+ ## Example
138
+
139
+ ```ruby
140
+ # Round-trip test
141
+ font = Fontisan::FontLoader.load('font.otf')
142
+ original_hints = font.tables['CFF'].top_dicts.first[:private]
143
+
144
+ # Convert to TrueType
145
+ ttf_converter = Fontisan::Converters::HintConverter.new
146
+ ttf_tables = ttf_converter.postscript_to_truetype(font)
147
+
148
+ # Convert back to PostScript
149
+ ps_hints = ttf_converter.truetype_to_postscript(ttf_font)
150
+
151
+ # Compare
152
+ puts "Original std_hw: #{original_hints[:std_hw]}"
153
+ puts "Round-trip std_hw: #{ps_hints[:std_hw]}"
154
+ ```
155
+
156
+ ## Best Practices
157
+
158
+ 1. **Test round-trip** — Verify hint preservation
159
+ 2. **Use autohint for cross-format** — Consider `--hinting-mode auto`
160
+ 3. **Validate after conversion** — Check hint validity
161
+ 4. **Test rendering** — Verify visual quality at small sizes
@@ -0,0 +1,86 @@
1
+ ---
2
+ title: Font Hinting Overview
3
+ ---
4
+
5
+ # Font Hinting Overview
6
+
7
+ Fontisan provides comprehensive support for font hints, including extraction, conversion, validation, and preservation. Hints are rendering instructions embedded in fonts that improve appearance at small sizes and low resolutions.
8
+
9
+ ## Hinting Systems
10
+
11
+ Fontisan supports two hinting systems:
12
+
13
+ | System | Format | Storage | Type |
14
+ |--------|--------|---------|------|
15
+ | TrueType | TTF | prep, fpgm, cvt tables | Bytecode instructions |
16
+ | PostScript | OTF | CFF Private DICT | Declarative hints |
17
+
18
+ ### TrueType Instructions
19
+
20
+ Bytecode-based hints using instruction opcodes:
21
+
22
+ - `SSW` — Set Single Width
23
+ - `SCVTCI` — Set CVT Cut-In
24
+ - `WCVTP` — Write CVT in Pixels
25
+ - And many more...
26
+
27
+ Stored in:
28
+ - `prep` — Control Value Program
29
+ - `fpgm` — Font Program
30
+ - `cvt` — Control Value Table
31
+
32
+ ### PostScript Hints
33
+
34
+ Declarative hints using operators:
35
+
36
+ - `hstem` — Horizontal stem hints
37
+ - `vstem` — Vertical stem hints
38
+ - `hintmask` — Hint activation mask
39
+
40
+ Stored in CFF Private dictionaries.
41
+
42
+ ## Features
43
+
44
+ - **Bidirectional Conversion** — Convert hints between TrueType and PostScript
45
+ - **Hint Extraction** — Extract existing hints from TTF and OTF fonts
46
+ - **Hint Application** — Apply hints during format conversion
47
+ - **Validation** — Comprehensive validation of hint data
48
+ - **Round-Trip Preservation** — Maintain hint integrity during conversion cycles
49
+
50
+ ## Guides
51
+
52
+ - [TrueType Hinting](/guide/hinting/truetype) — TrueType instruction details
53
+ - [PostScript Hinting](/guide/hinting/postscript) — CFF hint parameters
54
+ - [Hint Conversion](/guide/hinting/conversion) — Bidirectional conversion
55
+ - [Autohint](/guide/hinting/autohint) — Automatic hinting
56
+
57
+ ## Quick Start
58
+
59
+ ### Check for Hints
60
+
61
+ ```ruby
62
+ font = Fontisan::FontLoader.load('font.ttf')
63
+
64
+ # Check TrueType hints
65
+ if font.tables['prep'] || font.tables['fpgm']
66
+ puts "TrueType hints present"
67
+ end
68
+
69
+ # Check PostScript hints
70
+ if cff = font.tables['CFF']
71
+ private_dict = cff.top_dicts.first[:private]
72
+ if private_dict[:blue_values]
73
+ puts "PostScript hints present"
74
+ end
75
+ end
76
+ ```
77
+
78
+ ### Convert with Hints
79
+
80
+ ```bash
81
+ # Preserve hints during conversion
82
+ fontisan convert font.ttf --to otf --hinting-mode preserve
83
+
84
+ # Apply autohinting
85
+ fontisan convert font.ttf --to otf --autohint --hinting-mode auto
86
+ ```