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,187 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Instance Generation
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Instance Generation
|
|
6
|
+
|
|
7
|
+
Generate static font instances from variable fonts at specific variation coordinates.
|
|
8
|
+
|
|
9
|
+
## CLI Usage
|
|
10
|
+
|
|
11
|
+
### Basic Instance Generation
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# Generate at specific weight
|
|
15
|
+
fontisan instance variable.ttf --wght 700 --output bold.ttf
|
|
16
|
+
|
|
17
|
+
# Generate at specific weight and width
|
|
18
|
+
fontisan instance variable.ttf --wght 700 --wdth 75 --output condensed-bold.ttf
|
|
19
|
+
|
|
20
|
+
# Generate with all axes
|
|
21
|
+
fontisan instance variable.ttf --wght 600 --wdth 90 --slnt -12 --output custom.ttf
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Using Named Instances
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# List available instances
|
|
28
|
+
fontisan instance variable.ttf --list-instances
|
|
29
|
+
|
|
30
|
+
# Generate using instance index
|
|
31
|
+
fontisan instance variable.ttf --named-instance 0 --output thin.ttf
|
|
32
|
+
|
|
33
|
+
# Generate using instance name
|
|
34
|
+
fontisan instance variable.ttf --named-instance "Bold" --output bold.ttf
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Output Format
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
# Generate as TrueType (default)
|
|
41
|
+
fontisan instance variable.ttf --wght 700 --output bold.ttf
|
|
42
|
+
|
|
43
|
+
# Generate as OpenType/CFF
|
|
44
|
+
fontisan instance variable.ttf --wght 700 --to otf --output bold.otf
|
|
45
|
+
|
|
46
|
+
# Generate as WOFF2
|
|
47
|
+
fontisan instance.ttf --wght 700 --to woff2 --output bold.woff2
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Ruby API
|
|
51
|
+
|
|
52
|
+
### Basic Generation
|
|
53
|
+
|
|
54
|
+
```ruby
|
|
55
|
+
require 'fontisan'
|
|
56
|
+
|
|
57
|
+
# Load variable font
|
|
58
|
+
font = Fontisan::FontLoader.load('variable.ttf')
|
|
59
|
+
|
|
60
|
+
# Generate instance at specific coordinates
|
|
61
|
+
writer = Fontisan::Variation::InstanceWriter.new(font)
|
|
62
|
+
instance_font = writer.generate_instance(wght: 700)
|
|
63
|
+
|
|
64
|
+
# Write to file
|
|
65
|
+
Fontisan::FontWriter.write(
|
|
66
|
+
instance_font,
|
|
67
|
+
'bold.ttf'
|
|
68
|
+
)
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Multiple Axes
|
|
72
|
+
|
|
73
|
+
```ruby
|
|
74
|
+
# Generate instance with multiple axis values
|
|
75
|
+
instance_font = writer.generate_instance(
|
|
76
|
+
wght: 700,
|
|
77
|
+
wdth: 75,
|
|
78
|
+
slnt: -8
|
|
79
|
+
)
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Using Named Instances
|
|
83
|
+
|
|
84
|
+
```ruby
|
|
85
|
+
# Get named instance information
|
|
86
|
+
fvar = font.tables['fvar']
|
|
87
|
+
instance = fvar.instances[0]
|
|
88
|
+
|
|
89
|
+
# Extract coordinates from named instance
|
|
90
|
+
coordinates = {}
|
|
91
|
+
fvar.axes.each_with_index do |axis, i|
|
|
92
|
+
coordinates[axis.tag] = instance.coordinates[i]
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Generate instance
|
|
96
|
+
instance_font = writer.generate_instance(coordinates)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Batch Generation
|
|
100
|
+
|
|
101
|
+
### Generate All Named Instances
|
|
102
|
+
|
|
103
|
+
```ruby
|
|
104
|
+
font = Fontisan::FontLoader.load('variable.ttf')
|
|
105
|
+
fvar = font.tables['fvar']
|
|
106
|
+
writer = Fontisan::Variation::InstanceWriter.new(font)
|
|
107
|
+
|
|
108
|
+
fvar.instances.each do |instance|
|
|
109
|
+
# Build coordinates hash
|
|
110
|
+
coordinates = {}
|
|
111
|
+
fvar.axes.each_with_index do |axis, i|
|
|
112
|
+
coordinates[axis.tag] = instance.coordinates[i]
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Generate instance
|
|
116
|
+
instance_font = writer.generate_instance(coordinates)
|
|
117
|
+
|
|
118
|
+
# Write with instance name
|
|
119
|
+
filename = instance.name.downcase.gsub(/\s+/, '-') + '.ttf'
|
|
120
|
+
Fontisan::FontWriter.write(instance_font, filename)
|
|
121
|
+
end
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Generate Weight Range
|
|
125
|
+
|
|
126
|
+
```ruby
|
|
127
|
+
# Generate instances for common weights
|
|
128
|
+
weights = {
|
|
129
|
+
'thin' => 100,
|
|
130
|
+
'light' => 300,
|
|
131
|
+
'regular' => 400,
|
|
132
|
+
'medium' => 500,
|
|
133
|
+
'semibold' => 600,
|
|
134
|
+
'bold' => 700,
|
|
135
|
+
'black' => 900
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
weights.each do |name, wght|
|
|
139
|
+
instance_font = writer.generate_instance(wght: wght)
|
|
140
|
+
Fontisan::FontWriter.write(instance_font, "#{name}.ttf")
|
|
141
|
+
end
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Instance Quality
|
|
145
|
+
|
|
146
|
+
### Coordinate Validation
|
|
147
|
+
|
|
148
|
+
Coordinates must be within axis ranges:
|
|
149
|
+
|
|
150
|
+
```ruby
|
|
151
|
+
fvar = font.tables['fvar']
|
|
152
|
+
|
|
153
|
+
fvar.axes.each do |axis|
|
|
154
|
+
min = axis.min_value
|
|
155
|
+
max = axis.max_value
|
|
156
|
+
|
|
157
|
+
if value < min || value > max
|
|
158
|
+
raise "Value #{value} out of range for #{axis.tag}"
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Default Values
|
|
164
|
+
|
|
165
|
+
When an axis is not specified, the default value is used:
|
|
166
|
+
|
|
167
|
+
```ruby
|
|
168
|
+
# If wght is not specified, uses default from fvar
|
|
169
|
+
instance_font = writer.generate_instance(wdth: 75)
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## Performance
|
|
173
|
+
|
|
174
|
+
### Caching
|
|
175
|
+
|
|
176
|
+
Fontisan caches intermediate computations for faster instance generation:
|
|
177
|
+
|
|
178
|
+
```ruby
|
|
179
|
+
# Create writer once
|
|
180
|
+
writer = Fontisan::Variation::InstanceWriter.new(font)
|
|
181
|
+
|
|
182
|
+
# Generate multiple instances efficiently
|
|
183
|
+
(100..900).step(100).each do |wght|
|
|
184
|
+
instance_font = writer.generate_instance(wght: wght)
|
|
185
|
+
# ...
|
|
186
|
+
end
|
|
187
|
+
```
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Named Instances
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Named Instances
|
|
6
|
+
|
|
7
|
+
Work with named instances in variable fonts.
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
Named instances are predefined points in the design space with specific names. They provide:
|
|
12
|
+
- User-friendly names for common variations
|
|
13
|
+
- Consistent styling across applications
|
|
14
|
+
- Easy access to frequently used configurations
|
|
15
|
+
|
|
16
|
+
## Listing Named Instances
|
|
17
|
+
|
|
18
|
+
### CLI
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
fontisan instance variable.ttf --list-instances
|
|
22
|
+
|
|
23
|
+
# Example output:
|
|
24
|
+
# Named Instances: 6
|
|
25
|
+
# 0: Thin (wght=100)
|
|
26
|
+
# 1: Light (wght=300)
|
|
27
|
+
# 2: Regular (wght=400)
|
|
28
|
+
# 3: Medium (wght=500)
|
|
29
|
+
# 4: Bold (wght=700)
|
|
30
|
+
# 5: Black (wght=900)
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### API
|
|
34
|
+
|
|
35
|
+
```ruby
|
|
36
|
+
font = Fontisan::FontLoader.load('variable.ttf')
|
|
37
|
+
fvar = font.tables['fvar']
|
|
38
|
+
|
|
39
|
+
fvar.instances.each_with_index do |instance, index|
|
|
40
|
+
puts "#{index}: #{instance.name}"
|
|
41
|
+
instance.coordinates.each do |tag, value|
|
|
42
|
+
puts " #{tag} = #{value}"
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Instance Properties
|
|
48
|
+
|
|
49
|
+
| Property | Description |
|
|
50
|
+
|----------|-------------|
|
|
51
|
+
| `name` | Human-readable instance name |
|
|
52
|
+
| `coordinates` | Hash of axis tag → value |
|
|
53
|
+
|
|
54
|
+
## Generating Named Instances
|
|
55
|
+
|
|
56
|
+
### By Index
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
# Generate first named instance
|
|
60
|
+
fontisan instance variable.ttf --named-instance 0 --output thin.ttf
|
|
61
|
+
|
|
62
|
+
# Generate third named instance
|
|
63
|
+
fontisan instance variable.ttf --named-instance 2 --output regular.ttf
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### By Name
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
# Generate by name
|
|
70
|
+
fontisan instance variable.ttf --named-instance "Bold" --output bold.ttf
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### API
|
|
74
|
+
|
|
75
|
+
```ruby
|
|
76
|
+
font = Fontisan::FontLoader.load('variable.ttf')
|
|
77
|
+
fvar = font.tables['fvar']
|
|
78
|
+
writer = Fontisan::Variation::InstanceWriter.new(font)
|
|
79
|
+
|
|
80
|
+
# Find instance by name
|
|
81
|
+
bold_instance = fvar.instances.find { |i| i.name == "Bold" }
|
|
82
|
+
|
|
83
|
+
if bold_instance
|
|
84
|
+
# Build coordinates hash
|
|
85
|
+
coordinates = {}
|
|
86
|
+
fvar.axes.each_with_index do |axis, i|
|
|
87
|
+
coordinates[axis.tag] = bold_instance.coordinates[i]
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Generate instance
|
|
91
|
+
bold_font = writer.generate_instance(coordinates)
|
|
92
|
+
Fontisan::FontWriter.write(bold_font, 'bold.ttf')
|
|
93
|
+
end
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Generating All Named Instances
|
|
97
|
+
|
|
98
|
+
```ruby
|
|
99
|
+
font = Fontisan::FontLoader.load('variable.ttf')
|
|
100
|
+
fvar = font.tables['fvar']
|
|
101
|
+
writer = Fontisan::Variation::InstanceWriter.new(font)
|
|
102
|
+
|
|
103
|
+
fvar.instances.each do |instance|
|
|
104
|
+
# Build coordinates
|
|
105
|
+
coordinates = {}
|
|
106
|
+
fvar.axes.each_with_index do |axis, i|
|
|
107
|
+
coordinates[axis.tag] = instance.coordinates[i]
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Generate instance
|
|
111
|
+
instance_font = writer.generate_instance(coordinates)
|
|
112
|
+
|
|
113
|
+
# Create safe filename
|
|
114
|
+
filename = instance.name.downcase.gsub(/[^a-z0-9]+, '-') + '.ttf'
|
|
115
|
+
|
|
116
|
+
Fontisan::FontWriter.write(instance_font, filename)
|
|
117
|
+
puts "Generated: #{filename}"
|
|
118
|
+
end
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Instance Names
|
|
122
|
+
|
|
123
|
+
Instance names follow conventions:
|
|
124
|
+
|
|
125
|
+
### Weight-Based
|
|
126
|
+
|
|
127
|
+
- Thin
|
|
128
|
+
- Extra Light
|
|
129
|
+
- Light
|
|
130
|
+
- Regular
|
|
131
|
+
- Medium
|
|
132
|
+
- Semi Bold
|
|
133
|
+
- Bold
|
|
134
|
+
- Extra Bold
|
|
135
|
+
- Black
|
|
136
|
+
|
|
137
|
+
### Width-Based
|
|
138
|
+
|
|
139
|
+
- Ultra Condensed
|
|
140
|
+
- Extra Condensed
|
|
141
|
+
- Condensed
|
|
142
|
+
- Semi Condensed
|
|
143
|
+
- Normal
|
|
144
|
+
- Semi Expanded
|
|
145
|
+
- Expanded
|
|
146
|
+
- Extra Expanded
|
|
147
|
+
- Ultra Expanded
|
|
148
|
+
|
|
149
|
+
### Combinations
|
|
150
|
+
|
|
151
|
+
- Condensed Bold
|
|
152
|
+
- Expanded Light
|
|
153
|
+
- Semi Condensed Medium
|
|
154
|
+
|
|
155
|
+
## STAT Table
|
|
156
|
+
|
|
157
|
+
The STAT table provides additional instance information:
|
|
158
|
+
|
|
159
|
+
```ruby
|
|
160
|
+
stat = font.tables['STAT']
|
|
161
|
+
|
|
162
|
+
if stat
|
|
163
|
+
stat.axis_values.each do |axis_value|
|
|
164
|
+
puts "#{axis_value.name}"
|
|
165
|
+
puts " Axis: #{axis_value.axis_tag}"
|
|
166
|
+
puts " Value: #{axis_value.value}"
|
|
167
|
+
puts " Linked: #{axis_value.linked_value}" if axis_value.linked_value
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## Instance Validation
|
|
173
|
+
|
|
174
|
+
Validate instances before generation:
|
|
175
|
+
|
|
176
|
+
```ruby
|
|
177
|
+
fvar = font.tables['fvar']
|
|
178
|
+
|
|
179
|
+
fvar.instances.each do |instance|
|
|
180
|
+
valid = true
|
|
181
|
+
|
|
182
|
+
fvar.axes.each_with_index do |axis, i|
|
|
183
|
+
value = instance.coordinates[i]
|
|
184
|
+
if value < axis.min_value || value > axis.max_value
|
|
185
|
+
puts "Warning: #{instance.name} has #{axis.tag}=#{value} out of range"
|
|
186
|
+
valid = false
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
if valid
|
|
191
|
+
puts "#{instance.name}: Valid"
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
```
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Static Fonts
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Static Fonts
|
|
6
|
+
|
|
7
|
+
Convert variable fonts to static fonts.
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
Static fonts are traditional fonts with fixed designs. Converting a variable font to static creates a snapshot at specific coordinates.
|
|
12
|
+
|
|
13
|
+
## When to Use Static Fonts
|
|
14
|
+
|
|
15
|
+
- **Legacy Compatibility** — Older systems that don't support variable fonts
|
|
16
|
+
- **Performance** — Smaller file size for single weights
|
|
17
|
+
- **Simplicity** — No need for variation handling
|
|
18
|
+
- **Distribution** — Some platforms don't support variable fonts
|
|
19
|
+
|
|
20
|
+
## Creating Static Fonts
|
|
21
|
+
|
|
22
|
+
### At Default Coordinates
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
# Create static font at default variation
|
|
26
|
+
fontisan convert variable.ttf --to ttf --output static.ttf
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### At Specific Coordinates
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
# Create static bold font
|
|
33
|
+
fontisan instance variable.ttf --wght 700 --output bold-static.ttf
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Remove Variation Data
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
# Explicitly remove variation tables
|
|
40
|
+
fontisan convert variable.ttf --to ttf --no-preserve-variation --output static.ttf
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## API Usage
|
|
44
|
+
|
|
45
|
+
### Default Coordinates
|
|
46
|
+
|
|
47
|
+
```ruby
|
|
48
|
+
font = Fontisan::FontLoader.load('variable.ttf')
|
|
49
|
+
|
|
50
|
+
# Generate at default (empty hash = all default values)
|
|
51
|
+
writer = Fontisan::Variation::InstanceWriter.new(font)
|
|
52
|
+
static_font = writer.generate_instance({})
|
|
53
|
+
|
|
54
|
+
Fontisan::FontWriter.write(static_font, 'static.ttf')
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Specific Coordinates
|
|
58
|
+
|
|
59
|
+
```ruby
|
|
60
|
+
# Generate static at specific coordinates
|
|
61
|
+
static_bold = writer.generate_instance(wght: 700)
|
|
62
|
+
Fontisan::FontWriter.write(static_bold, 'bold-static.ttf')
|
|
63
|
+
|
|
64
|
+
# Generate static with multiple axes
|
|
65
|
+
static_condensed_bold = writer.generate_instance(wght: 700, wdth: 75)
|
|
66
|
+
Fontisan::FontWriter.write(static_condensed_bold, 'condensed-bold.ttf')
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## What Gets Removed
|
|
70
|
+
|
|
71
|
+
When creating a static font, these tables are removed:
|
|
72
|
+
|
|
73
|
+
| Table | Status |
|
|
74
|
+
|-------|--------|
|
|
75
|
+
| fvar | Removed |
|
|
76
|
+
| gvar | Removed |
|
|
77
|
+
| CFF2 | Converted to CFF |
|
|
78
|
+
| avar | Removed |
|
|
79
|
+
| HVAR | Applied to hmtx, removed |
|
|
80
|
+
| VVAR | Applied to vmtx, removed |
|
|
81
|
+
| MVAR | Applied to tables, removed |
|
|
82
|
+
|
|
83
|
+
## What Gets Generated
|
|
84
|
+
|
|
85
|
+
The static font contains:
|
|
86
|
+
|
|
87
|
+
| Table | Source |
|
|
88
|
+
|-------|--------|
|
|
89
|
+
| glyf | Interpolated from gvar |
|
|
90
|
+
| CFF | Interpolated from CFF2 |
|
|
91
|
+
| hmtx | Interpolated from HVAR |
|
|
92
|
+
| vmtx | Interpolated from VVAR |
|
|
93
|
+
| Other tables | Copied unchanged |
|
|
94
|
+
|
|
95
|
+
## Batch Generation
|
|
96
|
+
|
|
97
|
+
### Generate Weight Range
|
|
98
|
+
|
|
99
|
+
```ruby
|
|
100
|
+
font = Fontisan::FontLoader.load('variable.ttf')
|
|
101
|
+
writer = Fontisan::Variation::InstanceWriter.new(font)
|
|
102
|
+
|
|
103
|
+
weights = {
|
|
104
|
+
'thin' => 100,
|
|
105
|
+
'light' => 300,
|
|
106
|
+
'regular' => 400,
|
|
107
|
+
'medium' => 500,
|
|
108
|
+
'semibold' => 600,
|
|
109
|
+
'bold' => 700,
|
|
110
|
+
'extrabold' => 800,
|
|
111
|
+
'black' => 900
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
weights.each do |name, wght|
|
|
115
|
+
static_font = writer.generate_instance(wght: wght)
|
|
116
|
+
|
|
117
|
+
# Also convert to WOFF2 for web
|
|
118
|
+
options = Fontisan::ConversionOptions.from_preset(:web_optimized)
|
|
119
|
+
Fontisan::FontWriter.write(static_font, "#{name}.woff2", options: options)
|
|
120
|
+
end
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Generate 2D Grid
|
|
124
|
+
|
|
125
|
+
```ruby
|
|
126
|
+
# Generate grid of weight × width combinations
|
|
127
|
+
weights = [100, 400, 700]
|
|
128
|
+
widths = [75, 100, 125]
|
|
129
|
+
|
|
130
|
+
weights.each do |wght|
|
|
131
|
+
widths.each do |wdth|
|
|
132
|
+
static_font = writer.generate_instance(wght: wght, wdth: wdth)
|
|
133
|
+
filename = "wght-#{wght}-wdth-#{wdth}.ttf"
|
|
134
|
+
Fontisan::FontWriter.write(static_font, filename)
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## File Size Comparison
|
|
140
|
+
|
|
141
|
+
| Font Type | Typical Size |
|
|
142
|
+
|-----------|--------------|
|
|
143
|
+
| Variable font | 100-300 KB |
|
|
144
|
+
| Static (single) | 20-50 KB |
|
|
145
|
+
| Static (9 weights) | 180-450 KB |
|
|
146
|
+
|
|
147
|
+
Variable fonts are smaller when you need multiple variations. Static fonts are smaller for single variations.
|
|
148
|
+
|
|
149
|
+
## Quality Considerations
|
|
150
|
+
|
|
151
|
+
### Interpolation Accuracy
|
|
152
|
+
|
|
153
|
+
Static fonts are mathematically precise interpolations:
|
|
154
|
+
|
|
155
|
+
```ruby
|
|
156
|
+
# The interpolated outlines match the variable font exactly
|
|
157
|
+
# at the specified coordinates
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Hinting
|
|
161
|
+
|
|
162
|
+
- TrueType hints are interpolated along with outlines
|
|
163
|
+
- Some hint instructions may not apply to new coordinates
|
|
164
|
+
- Consider re-hinting after generation
|
|
165
|
+
|
|
166
|
+
### Subpixel Rendering
|
|
167
|
+
|
|
168
|
+
Static fonts may render differently than variable fonts at the same coordinates due to hinting differences.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Variable Fonts
|
|
2
|
+
|
|
3
|
+
Fontisan provides tools for working with OpenType variable fonts.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Variable fonts (OpenType Font Variations) allow a single font file to contain multiple variations along design axes (weight, width, slant, etc.).
|
|
8
|
+
|
|
9
|
+
## Reading Variable Fonts
|
|
10
|
+
|
|
11
|
+
```ruby
|
|
12
|
+
require 'fontisan'
|
|
13
|
+
|
|
14
|
+
# Load a variable font
|
|
15
|
+
font = Fontisan.load('variable-font.ttf')
|
|
16
|
+
|
|
17
|
+
# Check if font is variable
|
|
18
|
+
if font.variable?
|
|
19
|
+
puts "This is a variable font"
|
|
20
|
+
end
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Font Axes
|
|
24
|
+
|
|
25
|
+
```ruby
|
|
26
|
+
# Get available axes
|
|
27
|
+
font.axes.each do |axis|
|
|
28
|
+
puts "#{axis.tag}: #{axis.name}"
|
|
29
|
+
puts " Range: #{axis.min} - #{axis.max}"
|
|
30
|
+
puts " Default: #{axis.default}"
|
|
31
|
+
end
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Named Instances
|
|
35
|
+
|
|
36
|
+
```ruby
|
|
37
|
+
# Get named instances
|
|
38
|
+
font.named_instances.each do |instance|
|
|
39
|
+
puts "#{instance.name}:"
|
|
40
|
+
instance.coordinates.each do |tag, value|
|
|
41
|
+
puts " #{tag}: #{value}"
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Working with Variations
|
|
47
|
+
|
|
48
|
+
```ruby
|
|
49
|
+
# Create a variation
|
|
50
|
+
variation = font.variation('wght' => 700, 'wdth' => 100)
|
|
51
|
+
|
|
52
|
+
# Export as static font
|
|
53
|
+
variation.export('font-bold.ttf')
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Related
|
|
57
|
+
|
|
58
|
+
- [Color Fonts](/guide/color) - Color font support
|
data/docs/guide/woff.md
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# WOFF/WOFF2 Formats
|
|
2
|
+
|
|
3
|
+
Fontisan supports the Web Open Font Format (WOFF and WOFF2).
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
WOFF and WOFF2 are web font formats optimized for use on websites:
|
|
8
|
+
|
|
9
|
+
- **WOFF** - Compressed version of TrueType/OpenType with metadata support
|
|
10
|
+
- **WOFF2** - Improved compression using Brotli algorithm (typically 30% smaller than WOFF)
|
|
11
|
+
|
|
12
|
+
## Converting to WOFF
|
|
13
|
+
|
|
14
|
+
```ruby
|
|
15
|
+
require 'fontisan'
|
|
16
|
+
|
|
17
|
+
# Convert to WOFF
|
|
18
|
+
Fontisan.convert('font.ttf', output_format: :woff)
|
|
19
|
+
|
|
20
|
+
# Convert to WOFF2 (recommended for web)
|
|
21
|
+
Fontisan.convert('font.ttf', output_format: :woff2)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Metadata
|
|
25
|
+
|
|
26
|
+
WOFF files can contain extended metadata:
|
|
27
|
+
|
|
28
|
+
```ruby
|
|
29
|
+
# Add metadata when converting
|
|
30
|
+
Fontisan.convert('font.ttf',
|
|
31
|
+
output_format: :woff2,
|
|
32
|
+
metadata: {
|
|
33
|
+
unique_id: 'my-font-1.0',
|
|
34
|
+
license: 'OFL',
|
|
35
|
+
license_url: 'https://scripts.sil.org/OFL',
|
|
36
|
+
description: 'My custom font'
|
|
37
|
+
}
|
|
38
|
+
)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Extracting from WOFF
|
|
42
|
+
|
|
43
|
+
```ruby
|
|
44
|
+
# Extract original font from WOFF
|
|
45
|
+
Fontisan.convert('font.woff', output_format: :ttf)
|
|
46
|
+
Fontisan.convert('font.woff2', output_format: :otf)
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Compression Comparison
|
|
50
|
+
|
|
51
|
+
| Format | Size (relative) |
|
|
52
|
+
|--------|----------------|
|
|
53
|
+
| TTF/OTF | 100% |
|
|
54
|
+
| WOFF | ~70% |
|
|
55
|
+
| WOFF2 | ~50% |
|
|
56
|
+
|
|
57
|
+
## Related
|
|
58
|
+
|
|
59
|
+
- [Font Conversion](/guide/conversion) - General conversion guide
|