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.
- checksums.yaml +4 -4
- data/.rubocop_todo.yml +56 -196
- data/Gemfile +1 -1
- data/docs/.gitignore +17 -0
- data/docs/.vitepress/config.ts +317 -0
- data/docs/.vitepress/theme/components/ApiMethod.vue +127 -0
- data/docs/.vitepress/theme/components/Badge.vue +51 -0
- data/docs/.vitepress/theme/components/FeatureComparison.vue +87 -0
- data/docs/.vitepress/theme/components/HeroCodeBlock.vue +98 -0
- data/docs/.vitepress/theme/components/WithinHero.vue +30 -0
- data/docs/.vitepress/theme/index.ts +22 -0
- data/docs/.vitepress/theme/style.css +330 -0
- data/docs/api/conversion-options.md +141 -0
- data/docs/api/converters/curve-converter.md +34 -0
- data/docs/api/converters/hint-converter.md +34 -0
- data/docs/api/converters/outline-converter.md +27 -0
- data/docs/api/font-loader.md +111 -0
- data/docs/api/font-writer.md +103 -0
- data/docs/api/index.md +79 -0
- data/docs/api/models/glyph-accessor.md +43 -0
- data/docs/api/models/glyph.md +40 -0
- data/docs/api/models/table-analyzer.md +35 -0
- data/docs/api/sfnt-font.md +53 -0
- data/docs/api/type1-font.md +43 -0
- data/docs/api/validators/font-validator.md +31 -0
- data/docs/api/validators/helper.md +36 -0
- data/docs/api/validators/profile.md +39 -0
- data/docs/cli/convert.md +87 -0
- data/docs/cli/dump-table.md +110 -0
- data/docs/cli/export.md +176 -0
- data/docs/cli/features.md +124 -0
- data/docs/cli/glyphs.md +90 -0
- data/docs/cli/index.md +208 -0
- data/docs/cli/info.md +254 -0
- data/docs/cli/instance.md +122 -0
- data/docs/cli/ls.md +95 -0
- data/docs/cli/optical-size.md +94 -0
- data/docs/cli/pack.md +125 -0
- data/docs/cli/scripts.md +105 -0
- data/docs/cli/subset.md +39 -0
- data/docs/cli/tables.md +84 -0
- data/docs/cli/unicode.md +101 -0
- data/docs/cli/validate.md +48 -0
- data/docs/cli/variable.md +126 -0
- data/docs/cli/version.md +46 -0
- data/docs/guide/cli/convert.md +108 -0
- data/docs/guide/cli/export.md +138 -0
- data/docs/guide/cli/index.md +99 -0
- data/docs/guide/cli/info.md +144 -0
- data/docs/guide/cli/pack.md +155 -0
- data/docs/guide/cli/subset.md +118 -0
- data/docs/guide/cli/validate.md +139 -0
- data/docs/guide/color-fonts/bitmaps.md +177 -0
- data/docs/guide/color-fonts/colr-cpal.md +175 -0
- data/docs/guide/color-fonts/index.md +140 -0
- data/docs/guide/color-fonts/svg.md +154 -0
- data/docs/guide/color.md +51 -0
- data/docs/guide/comparisons/font-validator.md +222 -0
- data/docs/guide/comparisons/fonttools.md +200 -0
- data/docs/guide/comparisons/index.md +83 -0
- data/docs/guide/comparisons/lcdf-typetools.md +205 -0
- data/docs/guide/contributing.md +279 -0
- data/docs/guide/conversion/collections.md +251 -0
- data/docs/guide/conversion/curves.md +246 -0
- data/docs/guide/conversion/index.md +157 -0
- data/docs/guide/conversion/options.md +251 -0
- data/docs/guide/conversion/ttf-otf.md +184 -0
- data/docs/guide/conversion/type1.md +208 -0
- data/docs/guide/conversion/web.md +240 -0
- data/docs/guide/conversion.md +39 -0
- data/docs/guide/formats/collections.md +147 -0
- data/docs/guide/formats/dfont.md +99 -0
- data/docs/guide/formats/index.md +65 -0
- data/docs/guide/formats/otf.md +103 -0
- data/docs/guide/formats/svg.md +97 -0
- data/docs/guide/formats/ttf.md +105 -0
- data/docs/guide/formats/type1.md +118 -0
- data/docs/guide/formats/woff.md +115 -0
- data/docs/guide/hinting/autohint.md +141 -0
- data/docs/guide/hinting/conversion.md +161 -0
- data/docs/guide/hinting/index.md +86 -0
- data/docs/guide/hinting/postscript.md +149 -0
- data/docs/guide/hinting/truetype.md +135 -0
- data/docs/guide/hinting.md +44 -0
- data/docs/guide/index.md +152 -0
- data/docs/guide/installation.md +116 -0
- data/docs/guide/migrations/extract-ttc.md +549 -0
- data/docs/guide/migrations/font-validator.md +260 -0
- data/docs/guide/migrations/fonttools.md +208 -0
- data/docs/guide/migrations/index.md +64 -0
- data/docs/guide/migrations/otfinfo.md +197 -0
- data/docs/guide/quick-start.md +204 -0
- data/docs/guide/type1.md +58 -0
- data/docs/guide/universal-outline.md +151 -0
- data/docs/guide/validation/custom.md +195 -0
- data/docs/guide/validation/helpers.md +188 -0
- data/docs/guide/validation/index.md +132 -0
- data/docs/guide/validation/profiles.md +156 -0
- data/docs/guide/validation.md +47 -0
- data/docs/guide/variable-fonts/advanced.md +231 -0
- data/docs/guide/variable-fonts/axes.md +209 -0
- data/docs/guide/variable-fonts/conversion.md +197 -0
- data/docs/guide/variable-fonts/index.md +84 -0
- data/docs/guide/variable-fonts/instances.md +187 -0
- data/docs/guide/variable-fonts/named-instances.md +194 -0
- data/docs/guide/variable-fonts/static.md +168 -0
- data/docs/guide/variable.md +58 -0
- data/docs/guide/woff.md +59 -0
- data/docs/index.md +136 -0
- data/docs/lychee.toml +37 -0
- data/docs/package-lock.json +2560 -0
- data/docs/package.json +15 -0
- data/docs/public/apple-touch-icon.png +0 -0
- data/docs/public/favicon-96x96.png +0 -0
- data/docs/public/favicon.ico +0 -0
- data/docs/public/favicon.svg +1 -0
- data/docs/public/logo-full.svg +1 -0
- data/docs/public/logo.svg +1 -0
- data/docs/public/site.webmanifest +21 -0
- data/docs/public/web-app-manifest-192x192.png +0 -0
- data/docs/public/web-app-manifest-512x512.png +0 -0
- data/fontisan.gemspec +1 -1
- data/lib/fontisan/commands/features_command.rb +0 -1
- data/lib/fontisan/commands/info_command.rb +5 -5
- data/lib/fontisan/commands/scripts_command.rb +0 -1
- data/lib/fontisan/converters/format_converter.rb +2 -1
- data/lib/fontisan/converters/type1_converter.rb +65 -60
- data/lib/fontisan/hints/hint_converter.rb +2 -1
- data/lib/fontisan/loading_modes.rb +0 -2
- data/lib/fontisan/open_type_font.rb +0 -40
- data/lib/fontisan/sfnt_font.rb +41 -22
- data/lib/fontisan/tables/glyf/compound_glyph.rb +0 -1
- data/lib/fontisan/true_type_collection.rb +8 -8
- data/lib/fontisan/true_type_font.rb +1 -59
- data/lib/fontisan/type1/afm_parser.rb +2 -1
- data/lib/fontisan/type1/cff_to_type1_converter.rb +24 -19
- data/lib/fontisan/type1/private_dict.rb +28 -7
- data/lib/fontisan/type1/seac_expander.rb +22 -17
- data/lib/fontisan/variable/delta_applicator.rb +3 -3
- data/lib/fontisan/variation/optimizer.rb +0 -1
- data/lib/fontisan/version.rb +1 -1
- data/lib/fontisan/woff2_font.rb +2 -2
- data/lib/fontisan/woff_font.rb +3 -3
- data/lib/fontisan.rb +3 -2
- 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
|
+
```
|