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,149 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: PostScript Hinting
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# PostScript Hinting
|
|
6
|
+
|
|
7
|
+
PostScript hints are declarative values stored in the CFF Private dictionary.
|
|
8
|
+
|
|
9
|
+
## Hint Parameters
|
|
10
|
+
|
|
11
|
+
### Blue Values
|
|
12
|
+
|
|
13
|
+
Alignment zones for vertical positioning:
|
|
14
|
+
|
|
15
|
+
| Parameter | Description | Max Values |
|
|
16
|
+
|-----------|-------------|------------|
|
|
17
|
+
| `blue_values` | Baseline and top zones | 14 (7 pairs) |
|
|
18
|
+
| `other_blues` | Descender zones | 10 (5 pairs) |
|
|
19
|
+
|
|
20
|
+
```ruby
|
|
21
|
+
# Example blue values
|
|
22
|
+
blue_values = [-20, 0, 700, 720] # Baseline zone and cap height zone
|
|
23
|
+
other_blues = [-250, -230] # Descender zone
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Stem Widths
|
|
27
|
+
|
|
28
|
+
Standard stem dimensions:
|
|
29
|
+
|
|
30
|
+
| Parameter | Description | Max Values |
|
|
31
|
+
|-----------|-------------|------------|
|
|
32
|
+
| `std_hw` | Standard horizontal stem | 1 |
|
|
33
|
+
| `std_vw` | Standard vertical stem | 1 |
|
|
34
|
+
| `stem_snap_h` | Horizontal stem snap values | 12 |
|
|
35
|
+
| `stem_snap_v` | Vertical stem snap values | 12 |
|
|
36
|
+
|
|
37
|
+
```ruby
|
|
38
|
+
# Example stem values
|
|
39
|
+
std_hw = 80 # Standard horizontal stem width
|
|
40
|
+
std_vw = 100 # Standard vertical stem width
|
|
41
|
+
stem_snap_h = [80, 90, 100] # Common H stem widths
|
|
42
|
+
stem_snap_v = [100, 110, 120] # Common V stem widths
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Other Parameters
|
|
46
|
+
|
|
47
|
+
| Parameter | Description | Default |
|
|
48
|
+
|-----------|-------------|---------|
|
|
49
|
+
| `blue_scale` | Threshold for alignment zones | 0.039625 |
|
|
50
|
+
| `blue_shift` | Overshoot threshold | 7 |
|
|
51
|
+
| `blue_fuzz` | Blue zone expansion | 1 |
|
|
52
|
+
| `force_bold` | Force bold rendering | false |
|
|
53
|
+
| `language_group` | 0=Latin, 1=CJK | 0 |
|
|
54
|
+
|
|
55
|
+
## Reading Hints
|
|
56
|
+
|
|
57
|
+
```ruby
|
|
58
|
+
font = Fontisan::FontLoader.load('font.otf')
|
|
59
|
+
cff = font.tables['CFF']
|
|
60
|
+
|
|
61
|
+
# Get Private DICT
|
|
62
|
+
private = cff.top_dicts.first[:private]
|
|
63
|
+
|
|
64
|
+
# Read hint parameters
|
|
65
|
+
puts "Blue scale: #{private[:blue_scale]}"
|
|
66
|
+
puts "Std H width: #{private[:std_hw]}"
|
|
67
|
+
puts "Std V width: #{private[:std_vw]}"
|
|
68
|
+
puts "Blue values: #{private[:blue_values]}"
|
|
69
|
+
puts "Other blues: #{private[:other_blues]}"
|
|
70
|
+
puts "Stem snap H: #{private[:stem_snap_h]}"
|
|
71
|
+
puts "Stem snap V: #{private[:stem_snap_v]}"
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Validation
|
|
75
|
+
|
|
76
|
+
```ruby
|
|
77
|
+
validator = Fontisan::Hints::HintValidator.new
|
|
78
|
+
|
|
79
|
+
hints = {
|
|
80
|
+
blue_scale: 0.039625,
|
|
81
|
+
std_hw: 80,
|
|
82
|
+
blue_values: [-20, 0, 700, 720]
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
result = validator.validate_postscript_hints(hints)
|
|
86
|
+
|
|
87
|
+
if result[:valid]
|
|
88
|
+
puts "Valid PostScript hints"
|
|
89
|
+
else
|
|
90
|
+
result[:errors].each { |err| puts "Error: #{err}" }
|
|
91
|
+
end
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Validation Checks
|
|
95
|
+
|
|
96
|
+
- **Value Ranges** — Validates hint parameter bounds
|
|
97
|
+
- **Pair Validation** — Ensures blue zones are in pairs (even count)
|
|
98
|
+
- **Array Limits** — Enforces CFF specification limits
|
|
99
|
+
- **Positive Values** — Verifies stem widths are positive
|
|
100
|
+
- **Language Group** — Validates value is 0 or 1
|
|
101
|
+
|
|
102
|
+
## Blue Zone Examples
|
|
103
|
+
|
|
104
|
+
### Latin Font
|
|
105
|
+
|
|
106
|
+
```ruby
|
|
107
|
+
blue_values = [
|
|
108
|
+
-20, 0, # Baseline zone (-20 to 0)
|
|
109
|
+
470, 490, # x-height zone (470 to 490)
|
|
110
|
+
700, 720 # Cap height zone (700 to 720)
|
|
111
|
+
]
|
|
112
|
+
|
|
113
|
+
other_blues = [
|
|
114
|
+
-250, -230 # Descender zone (-250 to -230)
|
|
115
|
+
]
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### CJK Font
|
|
119
|
+
|
|
120
|
+
```ruby
|
|
121
|
+
blue_values = [
|
|
122
|
+
-20, 0, # Baseline
|
|
123
|
+
880, 900 # Top zone
|
|
124
|
+
]
|
|
125
|
+
|
|
126
|
+
other_blues = []
|
|
127
|
+
|
|
128
|
+
language_group = 1 # CJK
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Stem Snap Values
|
|
132
|
+
|
|
133
|
+
Stem snaps tell the rasterizer which widths are "standard":
|
|
134
|
+
|
|
135
|
+
```ruby
|
|
136
|
+
# If stems in the font are primarily 80, 90, or 100 units
|
|
137
|
+
stem_snap_h = [80, 90, 100]
|
|
138
|
+
|
|
139
|
+
# The rasterizer will snap stems to these values
|
|
140
|
+
# when they're close enough
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Best Practices
|
|
144
|
+
|
|
145
|
+
1. **Keep blue zones in pairs** — Each zone needs top and bottom
|
|
146
|
+
2. **Use realistic values** — Stems should match actual glyph stems
|
|
147
|
+
3. **Don't over-specify** — 4-5 blue zones are usually enough
|
|
148
|
+
4. **Test at small sizes** — Verify hints improve rendering
|
|
149
|
+
5. **Consider font size** — Adjust blue_scale for text vs display
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: TrueType Hinting
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# TrueType Hinting
|
|
6
|
+
|
|
7
|
+
TrueType hinting uses bytecode instructions to control glyph rendering.
|
|
8
|
+
|
|
9
|
+
## Storage
|
|
10
|
+
|
|
11
|
+
TrueType hints are stored in three tables:
|
|
12
|
+
|
|
13
|
+
| Table | Purpose |
|
|
14
|
+
|-------|---------|
|
|
15
|
+
| `prep` | Control Value Program |
|
|
16
|
+
| `fpgm` | Font Program |
|
|
17
|
+
| `cvt` | Control Value Table |
|
|
18
|
+
|
|
19
|
+
## Instructions
|
|
20
|
+
|
|
21
|
+
### Stack Operations
|
|
22
|
+
|
|
23
|
+
| Opcode | Name | Purpose |
|
|
24
|
+
|--------|------|---------|
|
|
25
|
+
| `0x40` | NPUSHB | Push n bytes onto stack |
|
|
26
|
+
| `0x41` | NPUSHW | Push n words onto stack |
|
|
27
|
+
| `0xB0-0xB7` | PUSHB[0-7] | Push 1-8 bytes |
|
|
28
|
+
| `0xB8-0xBF` | PUSHW[0-7] | Push 1-8 words |
|
|
29
|
+
|
|
30
|
+
### Control Value Instructions
|
|
31
|
+
|
|
32
|
+
| Opcode | Name | Purpose |
|
|
33
|
+
|--------|------|---------|
|
|
34
|
+
| `0x1D` | SCVTCI | Set CVT cut-in |
|
|
35
|
+
| `0x1E` | SSWCI | Set single width cut-in |
|
|
36
|
+
| `0x1F` | SSW | Set single width |
|
|
37
|
+
| `0x44` | WCVTP | Write CVT in pixels |
|
|
38
|
+
| `0x70` | WCVTF | Write CVT in FUnits |
|
|
39
|
+
|
|
40
|
+
## Reading Instructions
|
|
41
|
+
|
|
42
|
+
```ruby
|
|
43
|
+
font = Fontisan::FontLoader.load('font.ttf')
|
|
44
|
+
|
|
45
|
+
# Get prep table
|
|
46
|
+
prep = font.tables['prep']
|
|
47
|
+
if prep
|
|
48
|
+
puts "Prep program: #{prep.bytecode.length} bytes"
|
|
49
|
+
|
|
50
|
+
# Parse instructions
|
|
51
|
+
parser = Fontisan::Hints::InstructionParser.new
|
|
52
|
+
instructions = parser.parse(prep.bytecode)
|
|
53
|
+
|
|
54
|
+
instructions.each do |inst|
|
|
55
|
+
puts "#{inst.opcode.to_s(16)}: #{inst.name}"
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Get CVT table
|
|
60
|
+
cvt = font.tables['cvt']
|
|
61
|
+
if cvt
|
|
62
|
+
puts "CVT entries: #{cvt.values.length}"
|
|
63
|
+
cvt.values.each_with_index do |value, i|
|
|
64
|
+
puts " CVT[#{i}] = #{value}"
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Validation
|
|
70
|
+
|
|
71
|
+
```ruby
|
|
72
|
+
validator = Fontisan::Hints::HintValidator.new
|
|
73
|
+
|
|
74
|
+
# Validate prep instructions
|
|
75
|
+
prep = font.tables['prep']
|
|
76
|
+
result = validator.validate_truetype_instructions(prep.bytecode)
|
|
77
|
+
|
|
78
|
+
if result[:valid]
|
|
79
|
+
puts "Valid instructions"
|
|
80
|
+
else
|
|
81
|
+
result[:errors].each do |error|
|
|
82
|
+
puts "Error: #{error}"
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Validation Checks
|
|
88
|
+
|
|
89
|
+
- **Bytecode Structure** — Validates instruction opcodes and parameters
|
|
90
|
+
- **Stack Operations** — Ensures proper stack depth management
|
|
91
|
+
- **Parameter Counts** — Verifies correct number of operands
|
|
92
|
+
- **Truncation Detection** — Identifies incomplete instructions
|
|
93
|
+
- **Stack Neutrality** — Checks if sequences maintain stack balance
|
|
94
|
+
|
|
95
|
+
## Instruction Encoding
|
|
96
|
+
|
|
97
|
+
The generator automatically selects efficient encoding:
|
|
98
|
+
|
|
99
|
+
### Byte Values (0-255)
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
Value 17: PUSHB[0] 17 (2 bytes)
|
|
103
|
+
Values [10,20,30]: NPUSHB 3 10 20 30 (5 bytes)
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Word Values (256-65535)
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
Value 300: PUSHW[0] 0x01 0x2C (3 bytes, big-endian)
|
|
110
|
+
Values [300,400]: NPUSHW 2 0x01 0x2C 0x01 0x90 (7 bytes)
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## CVT Values
|
|
114
|
+
|
|
115
|
+
The Control Value Table stores frequently used values:
|
|
116
|
+
|
|
117
|
+
```ruby
|
|
118
|
+
cvt = font.tables['cvt']
|
|
119
|
+
|
|
120
|
+
# Typical CVT layout
|
|
121
|
+
# CVT[0] - Standard vertical stem width
|
|
122
|
+
# CVT[1] - Standard horizontal stem width
|
|
123
|
+
# CVT[2-7] - Blue zone values
|
|
124
|
+
# CVT[8+] - Other common values
|
|
125
|
+
|
|
126
|
+
puts "Standard V stem: #{cvt.values[0]}"
|
|
127
|
+
puts "Standard H stem: #{cvt.values[1]}"
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Best Practices
|
|
131
|
+
|
|
132
|
+
1. **Use CVT for common values** — Reduces bytecode size
|
|
133
|
+
2. **Keep prep simple** — Complex programs can cause compatibility issues
|
|
134
|
+
3. **Test cross-platform** — Hinting behavior varies by rasterizer
|
|
135
|
+
4. **Validate before release** — Ensure instructions are well-formed
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Font Hinting
|
|
2
|
+
|
|
3
|
+
Fontisan provides tools for working with font hinting data.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Font hinting (also known as instructing) is the process of adjusting the display of fonts to align with a pixel grid, improving legibility at small sizes.
|
|
8
|
+
|
|
9
|
+
## Hinting Formats
|
|
10
|
+
|
|
11
|
+
- **fpgm/cvt/prep** - TrueType instructions
|
|
12
|
+
- **gasp** - Grid-fitting and scan-conversion procedure
|
|
13
|
+
- **GPOS/GSUB** - OpenType positioning and substitution
|
|
14
|
+
|
|
15
|
+
## Reading Hinting Data
|
|
16
|
+
|
|
17
|
+
```ruby
|
|
18
|
+
require 'fontisan'
|
|
19
|
+
|
|
20
|
+
font = Fontisan.load('font.ttf')
|
|
21
|
+
|
|
22
|
+
# Check for TrueType instructions
|
|
23
|
+
if font.trueType_instructions?
|
|
24
|
+
puts "Font has TrueType hinting"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Get gasp table
|
|
28
|
+
if font.gasp_table
|
|
29
|
+
font.gasp_table.ranges.each do |range|
|
|
30
|
+
puts "Size #{range.range_max_ppem}: #{range.behavior}"
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Auto-Hinting
|
|
36
|
+
|
|
37
|
+
```ruby
|
|
38
|
+
# Apply auto-hinting
|
|
39
|
+
Fontisan.autohint('font.ttf', output: 'font-hinted.ttf')
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Related
|
|
43
|
+
|
|
44
|
+
- [Font Conversion](/guide/conversion) - Convert fonts while preserving hinting
|
data/docs/guide/index.md
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Getting Started
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Getting Started
|
|
6
|
+
|
|
7
|
+
Fontisan is a font processing library for Ruby that provides tools for font conversion, validation, and manipulation.
|
|
8
|
+
|
|
9
|
+
::: warning Font License Considerations
|
|
10
|
+
Commercial fonts often come with restrictive licenses that may prohibit:
|
|
11
|
+
|
|
12
|
+
- **Subsetting** — Reducing the character set
|
|
13
|
+
- **Format conversion** — Converting between TTF, OTF, WOFF, etc.
|
|
14
|
+
- **Variable font instancing** — Generating static instances
|
|
15
|
+
- **Glyph modification** — Altering or extracting individual glyphs
|
|
16
|
+
- **Redistribution** — Sharing converted or modified fonts
|
|
17
|
+
|
|
18
|
+
Always check your font's End User License Agreement (EULA) before processing. Many foundries require additional licenses for web embedding, subsetting, or format conversion. **Fontisan provides the tools — you are responsible for ensuring you have the rights to use them.**
|
|
19
|
+
:::
|
|
20
|
+
|
|
21
|
+
## Features
|
|
22
|
+
|
|
23
|
+
Fontisan provides comprehensive font processing capabilities:
|
|
24
|
+
|
|
25
|
+
- **🔄 Font Conversion** — Convert between TTF, OTF, WOFF, WOFF2, Type 1, and SVG formats
|
|
26
|
+
- **✅ Font Validation** — Validate fonts with 5 profiles and 56 helpers
|
|
27
|
+
- **📦 Type 1 Support** — Adobe Type 1 fonts (PFB/PFA) with eexec decryption
|
|
28
|
+
- **🎨 Color Fonts** — COLR/CPAL, sbix, and SVG color fonts
|
|
29
|
+
- **⚡ Variable Fonts** — Instance generation, format conversion, named instances
|
|
30
|
+
- **🔧 Font Hinting** — Bidirectional TrueType ↔ PostScript hint conversion
|
|
31
|
+
- **📚 Collections** — TTC/OTC/dfont pack, unpack, and deduplication
|
|
32
|
+
- **💎 Pure Ruby** — No Python, no C++, no C# dependencies
|
|
33
|
+
|
|
34
|
+
## Installation
|
|
35
|
+
|
|
36
|
+
Add this line to your application's Gemfile:
|
|
37
|
+
|
|
38
|
+
```ruby
|
|
39
|
+
gem 'fontisan'
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
And then execute:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
bundle install
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Or install it yourself as:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
gem install fontisan
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Quick Start
|
|
55
|
+
|
|
56
|
+
### Load a Font
|
|
57
|
+
|
|
58
|
+
```ruby
|
|
59
|
+
require 'fontisan'
|
|
60
|
+
|
|
61
|
+
# Automatic format detection
|
|
62
|
+
font = Fontisan::FontLoader.load('font.ttf')
|
|
63
|
+
|
|
64
|
+
# Works with any format
|
|
65
|
+
font = Fontisan::FontLoader.load('font.otf') # OpenType
|
|
66
|
+
font = Fontisan::FontLoader.load('font.woff2') # WOFF2
|
|
67
|
+
font = Fontisan::FontLoader.load('font.pfb') # Type 1
|
|
68
|
+
font = Fontisan::FontLoader.load('fonts.ttc') # Collection
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Get Font Information
|
|
72
|
+
|
|
73
|
+
```ruby
|
|
74
|
+
# Get basic info
|
|
75
|
+
info = Fontisan::Commands::InfoCommand.new(font: font).run
|
|
76
|
+
puts info.family_name
|
|
77
|
+
puts info.style
|
|
78
|
+
puts info.version
|
|
79
|
+
|
|
80
|
+
# Get table information
|
|
81
|
+
tables = font.tables
|
|
82
|
+
puts tables.keys
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Convert Fonts
|
|
86
|
+
|
|
87
|
+
```ruby
|
|
88
|
+
# Simple conversion
|
|
89
|
+
Fontisan.convert('input.ttf', output_format: :woff2)
|
|
90
|
+
|
|
91
|
+
# With custom options
|
|
92
|
+
options = Fontisan::ConversionOptions.new(
|
|
93
|
+
from: :ttf,
|
|
94
|
+
to: :otf,
|
|
95
|
+
opening: { autohint: true, convert_curves: true }
|
|
96
|
+
)
|
|
97
|
+
Fontisan.convert('input.ttf', output_format: :otf, options: options)
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Validate Fonts
|
|
101
|
+
|
|
102
|
+
```ruby
|
|
103
|
+
# Validate with a profile
|
|
104
|
+
result = Fontisan::FontValidator.validate('font.ttf', profile: :google_fonts)
|
|
105
|
+
|
|
106
|
+
# Check results
|
|
107
|
+
if result.passed?
|
|
108
|
+
puts "Font is valid!"
|
|
109
|
+
else
|
|
110
|
+
result.errors.each do |error|
|
|
111
|
+
puts "#{error.code}: #{error.message}"
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## CLI Usage
|
|
117
|
+
|
|
118
|
+
Fontisan includes a comprehensive CLI:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
# Get font information
|
|
122
|
+
fontisan info font.ttf
|
|
123
|
+
|
|
124
|
+
# List fonts in a collection
|
|
125
|
+
fontisan ls fonts.ttc
|
|
126
|
+
|
|
127
|
+
# Convert fonts
|
|
128
|
+
fontisan convert input.ttf --to otf --output output.otf
|
|
129
|
+
|
|
130
|
+
# Validate fonts
|
|
131
|
+
fontisan validate font.ttf --profile google_fonts
|
|
132
|
+
|
|
133
|
+
# Extract fonts from collection
|
|
134
|
+
fontisan unpack fonts.ttc --output-dir ./extracted
|
|
135
|
+
|
|
136
|
+
# Pack fonts into collection
|
|
137
|
+
fontisan pack font1.ttf font2.ttf --output fonts.ttc
|
|
138
|
+
|
|
139
|
+
# Export to TTX
|
|
140
|
+
fontisan export font.ttf --format ttx
|
|
141
|
+
|
|
142
|
+
# Subset fonts
|
|
143
|
+
fontisan subset font.ttf --chars "ABC123"
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Next Steps
|
|
147
|
+
|
|
148
|
+
- [Installation Details](/guide/installation) — Detailed installation options
|
|
149
|
+
- [Quick Start Guide](/guide/quick-start) — Common workflows
|
|
150
|
+
- [CLI Reference](/guide/cli/) — Command-line documentation
|
|
151
|
+
- [Font Formats](/guide/formats/) — Supported format details
|
|
152
|
+
- [Conversion Guide](/guide/conversion/) — Conversion options and best practices
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Installation
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Installation
|
|
6
|
+
|
|
7
|
+
## Requirements
|
|
8
|
+
|
|
9
|
+
- Ruby 3.0 or higher
|
|
10
|
+
- No external dependencies (pure Ruby)
|
|
11
|
+
|
|
12
|
+
## Installing the Gem
|
|
13
|
+
|
|
14
|
+
### With Bundler
|
|
15
|
+
|
|
16
|
+
Add this line to your application's Gemfile:
|
|
17
|
+
|
|
18
|
+
```ruby
|
|
19
|
+
gem 'fontisan'
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
And then execute:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
bundle install
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Manual Installation
|
|
29
|
+
|
|
30
|
+
Install it yourself as:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
gem install fontisan
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Verifying Installation
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
# Check if CLI is available
|
|
40
|
+
fontisan --version
|
|
41
|
+
|
|
42
|
+
# Get help
|
|
43
|
+
fontisan --help
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Installing from Source
|
|
47
|
+
|
|
48
|
+
For development or to use the latest features:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
git clone https://github.com/fontist/fontisan.git
|
|
52
|
+
cd fontisan
|
|
53
|
+
bundle install
|
|
54
|
+
bundle exec rake install
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Dependencies
|
|
58
|
+
|
|
59
|
+
Fontisan is **100% pure Ruby** with no external dependencies:
|
|
60
|
+
|
|
61
|
+
- No Python required
|
|
62
|
+
- No C++ compilation needed
|
|
63
|
+
- No native extensions
|
|
64
|
+
- Works on Linux, macOS, Windows, and BSD
|
|
65
|
+
|
|
66
|
+
### Optional Dependencies
|
|
67
|
+
|
|
68
|
+
For development:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
# Install development dependencies
|
|
72
|
+
bundle install
|
|
73
|
+
|
|
74
|
+
# Run tests
|
|
75
|
+
bundle exec rspec
|
|
76
|
+
|
|
77
|
+
# Run linter
|
|
78
|
+
bundle exec rubocop
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Troubleshooting
|
|
82
|
+
|
|
83
|
+
### Ruby Version
|
|
84
|
+
|
|
85
|
+
Fontisan requires Ruby 3.0 or higher. Check your version:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
ruby --version
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Permission Issues
|
|
92
|
+
|
|
93
|
+
If you encounter permission errors, try:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
# Install to user directory
|
|
97
|
+
gem install fontisan --user-install
|
|
98
|
+
|
|
99
|
+
# Or use sudo (not recommended)
|
|
100
|
+
sudo gem install fontisan
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Bundler Issues
|
|
104
|
+
|
|
105
|
+
If Bundler has issues:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
# Update Bundler
|
|
109
|
+
gem update bundler
|
|
110
|
+
|
|
111
|
+
# Clear cache
|
|
112
|
+
bundle clean --force
|
|
113
|
+
|
|
114
|
+
# Reinstall
|
|
115
|
+
bundle install --redownload
|
|
116
|
+
```
|