fontisan 0.2.8 → 0.2.10
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 +17 -101
- data/CHANGELOG.md +116 -0
- data/README.adoc +25 -13
- data/docs/APPLE_LEGACY_FONTS.adoc +173 -0
- data/docs/COLLECTION_VALIDATION.adoc +143 -0
- data/docs/COLOR_FONTS.adoc +127 -0
- data/docs/DOCUMENTATION_SUMMARY.md +141 -0
- data/docs/FONT_HINTING.adoc +9 -1
- data/docs/VALIDATION.adoc +254 -0
- data/docs/WOFF_WOFF2_FORMATS.adoc +94 -0
- data/lib/fontisan/open_type_font.rb +18 -424
- data/lib/fontisan/sfnt_font.rb +690 -0
- data/lib/fontisan/sfnt_table.rb +264 -0
- data/lib/fontisan/tables/cmap_table.rb +231 -0
- data/lib/fontisan/tables/glyf_table.rb +255 -0
- data/lib/fontisan/tables/head_table.rb +111 -0
- data/lib/fontisan/tables/hhea_table.rb +255 -0
- data/lib/fontisan/tables/hmtx_table.rb +191 -0
- data/lib/fontisan/tables/loca_table.rb +212 -0
- data/lib/fontisan/tables/maxp_table.rb +258 -0
- data/lib/fontisan/tables/name_table.rb +176 -0
- data/lib/fontisan/tables/os2_table.rb +329 -0
- data/lib/fontisan/tables/post_table.rb +183 -0
- data/lib/fontisan/true_type_font.rb +12 -463
- data/lib/fontisan/version.rb +1 -1
- data/lib/fontisan/woff_font.rb +45 -29
- metadata +21 -2
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
= Font Collection Validation
|
|
2
|
+
|
|
3
|
+
== General
|
|
4
|
+
|
|
5
|
+
Fontisan provides validation support for font collections (TTC, OTC, dfont),
|
|
6
|
+
enabling quality assurance across multiple fonts in a single file.
|
|
7
|
+
|
|
8
|
+
Collection validation ensures all fonts in a collection meet quality standards
|
|
9
|
+
while providing per-font and aggregate reporting.
|
|
10
|
+
|
|
11
|
+
== Collection validation output
|
|
12
|
+
|
|
13
|
+
When validating a collection, Fontisan displays:
|
|
14
|
+
|
|
15
|
+
* *Collection header* - Path, type, and number of fonts
|
|
16
|
+
* *Summary* - Total errors, warnings, and info across all fonts
|
|
17
|
+
* *Per-font sections* - Individual validation results for each font with:
|
|
18
|
+
** Font index and name
|
|
19
|
+
** Font path in `collection.ttc:index` format
|
|
20
|
+
** Individual font status (VALID/INVALID/VALID_WITH_WARNINGS)
|
|
21
|
+
** Font-specific errors and warnings
|
|
22
|
+
|
|
23
|
+
.Using the CLI to validate a font collection
|
|
24
|
+
[example]
|
|
25
|
+
====
|
|
26
|
+
[source,shell]
|
|
27
|
+
----
|
|
28
|
+
$ fontisan validate /path/to/font.ttc
|
|
29
|
+
|
|
30
|
+
Collection: /path/to/font.ttc
|
|
31
|
+
Type: TTC
|
|
32
|
+
Fonts: 4
|
|
33
|
+
|
|
34
|
+
Summary:
|
|
35
|
+
Total Errors: 14
|
|
36
|
+
Total Warnings: 8
|
|
37
|
+
Total Info: 0
|
|
38
|
+
|
|
39
|
+
=== Font 0: Lucida Grande ===
|
|
40
|
+
Font: /path/to/font.ttc:0
|
|
41
|
+
Status: INVALID
|
|
42
|
+
|
|
43
|
+
Errors:
|
|
44
|
+
name_table.family_name_present - Family name is empty
|
|
45
|
+
head_table.valid_magic - Invalid magic number
|
|
46
|
+
|
|
47
|
+
Warnings:
|
|
48
|
+
os2_table.valid_version - Version 5 requires Windows 10+
|
|
49
|
+
|
|
50
|
+
=== Font 1: Lucida Grande Bold ===
|
|
51
|
+
Font: /path/to/font.ttc:1
|
|
52
|
+
Status: VALID
|
|
53
|
+
...
|
|
54
|
+
----
|
|
55
|
+
====
|
|
56
|
+
|
|
57
|
+
== Validation profiles with collections
|
|
58
|
+
|
|
59
|
+
All validation profiles work with font collections. The selected profile determines:
|
|
60
|
+
|
|
61
|
+
* **Which tables are loaded** - metadata vs full mode
|
|
62
|
+
* **Which checks are performed** - number and type of validations
|
|
63
|
+
* **Performance characteristics** - indexability is ~5x faster than production
|
|
64
|
+
|
|
65
|
+
.Using validation profiles with collections
|
|
66
|
+
[example]
|
|
67
|
+
====
|
|
68
|
+
[source,shell]
|
|
69
|
+
----
|
|
70
|
+
# Quick validation for indexing (metadata mode, 8 checks, ~5x faster)
|
|
71
|
+
$ fontisan validate /path/to/font.ttc -t indexability
|
|
72
|
+
|
|
73
|
+
# Comprehensive validation (full mode, 37 checks)
|
|
74
|
+
$ fontisan validate /path/to/font.ttc -t production
|
|
75
|
+
|
|
76
|
+
# Web font readiness validation
|
|
77
|
+
$ fontisan validate /path/to/font.ttc -t web
|
|
78
|
+
----
|
|
79
|
+
====
|
|
80
|
+
|
|
81
|
+
== Collection validation exit codes
|
|
82
|
+
|
|
83
|
+
For collections, the validation command uses the "worst" status across all fonts:
|
|
84
|
+
|
|
85
|
+
* **0** = All fonts valid
|
|
86
|
+
* **2** = Any font has fatal errors
|
|
87
|
+
* **3** = Any font has errors (and no fatal)
|
|
88
|
+
* **4** = Any font has warnings (and no errors)
|
|
89
|
+
* **5** = Any font has info issues (and no errors or warnings)
|
|
90
|
+
|
|
91
|
+
.Checking collection validation exit codes
|
|
92
|
+
[example]
|
|
93
|
+
====
|
|
94
|
+
[source,shell]
|
|
95
|
+
----
|
|
96
|
+
$ fontisan validate font.ttc -S -R
|
|
97
|
+
|
|
98
|
+
Collection: font.ttc
|
|
99
|
+
Type: TTC
|
|
100
|
+
Fonts: 3
|
|
101
|
+
|
|
102
|
+
Summary:
|
|
103
|
+
Total Errors: 2
|
|
104
|
+
Total Warnings: 5
|
|
105
|
+
|
|
106
|
+
$ echo $?
|
|
107
|
+
3 # Exit code 3 indicates errors found
|
|
108
|
+
----
|
|
109
|
+
====
|
|
110
|
+
|
|
111
|
+
== Ruby API for collection validation
|
|
112
|
+
|
|
113
|
+
.Using the Ruby API for collection validation
|
|
114
|
+
[example]
|
|
115
|
+
====
|
|
116
|
+
[source,ruby]
|
|
117
|
+
----
|
|
118
|
+
require 'fontisan'
|
|
119
|
+
|
|
120
|
+
# Validate collection
|
|
121
|
+
report = Fontisan.validate('font.ttc', profile: :production)
|
|
122
|
+
|
|
123
|
+
# Check overall status
|
|
124
|
+
puts report.overall_status # "valid", "valid_with_warnings", "invalid"
|
|
125
|
+
|
|
126
|
+
# Access per-font reports
|
|
127
|
+
report.font_reports.each_with_index do |font_report, i|
|
|
128
|
+
puts "Font #{i}: #{font_report.font_name}"
|
|
129
|
+
puts " Status: #{font_report.report.status}"
|
|
130
|
+
puts " Errors: #{font_report.report.summary.errors}"
|
|
131
|
+
puts " Warnings: #{font_report.report.summary.warnings}"
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Get aggregate statistics
|
|
135
|
+
puts "Total fonts: #{report.num_fonts}"
|
|
136
|
+
|
|
137
|
+
# Count valid/invalid fonts (requires iteration)
|
|
138
|
+
valid_count = report.font_reports.count { |fr| fr.report.valid? }
|
|
139
|
+
invalid_count = report.font_reports.count { |fr| !fr.report.valid? }
|
|
140
|
+
puts "Valid fonts: #{valid_count}"
|
|
141
|
+
puts "Invalid fonts: #{invalid_count}"
|
|
142
|
+
----
|
|
143
|
+
====
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
= Color Font Support
|
|
2
|
+
|
|
3
|
+
== General
|
|
4
|
+
|
|
5
|
+
Fontisan provides support for color fonts through multiple formats:
|
|
6
|
+
|
|
7
|
+
* **COLR/CPAL** - OpenType color layered glyphs (SVG-like layering in font)
|
|
8
|
+
* **sbix** - Apple color bitmap glyphs (embedded raster images)
|
|
9
|
+
* **SVG** - OpenType SVG color glyphs (embedded SVG vector graphics)
|
|
10
|
+
|
|
11
|
+
Color fonts enable rich typography with gradients, images, and artistic effects
|
|
12
|
+
beyond standard outline fonts.
|
|
13
|
+
|
|
14
|
+
=== COLR/CPAL color layered glyphs
|
|
15
|
+
|
|
16
|
+
The COLR table defines color layers using base glyphs and paint layers,
|
|
17
|
+
with the CPAL table defining color palettes.
|
|
18
|
+
|
|
19
|
+
[source,shell]
|
|
20
|
+
----
|
|
21
|
+
$ fontisan tables FONT.ttf --format yaml | grep -A 50 "tag: COLR"
|
|
22
|
+
----
|
|
23
|
+
|
|
24
|
+
.COLR table structure
|
|
25
|
+
[example]
|
|
26
|
+
====
|
|
27
|
+
[source,yaml]
|
|
28
|
+
----
|
|
29
|
+
---
|
|
30
|
+
tag: COLR
|
|
31
|
+
version: 0
|
|
32
|
+
num_base_glyphs: 15
|
|
33
|
+
num_layers: 47
|
|
34
|
+
num_palettes: 1
|
|
35
|
+
color_records: 8
|
|
36
|
+
|
|
37
|
+
Base glyphs:
|
|
38
|
+
- base_glyph: emoji_smile
|
|
39
|
+
layers:
|
|
40
|
+
- glyph: emoji_smile_layer0
|
|
41
|
+
palette_index: 1
|
|
42
|
+
color_index: 0
|
|
43
|
+
- glyph: emoji_smile_layer1
|
|
44
|
+
palette_index: 1
|
|
45
|
+
color_index: 1
|
|
46
|
+
----
|
|
47
|
+
====
|
|
48
|
+
|
|
49
|
+
=== sbix color bitmap glyphs
|
|
50
|
+
|
|
51
|
+
Apple's sbix table embeds raster images (PNG, JPG) for color glyphs.
|
|
52
|
+
Each glyph can have multiple bitmap strikes at different sizes.
|
|
53
|
+
|
|
54
|
+
[source,shell]
|
|
55
|
+
----
|
|
56
|
+
$ fontisan tables FONT.ttf | grep -A 20 "tag: sbix"
|
|
57
|
+
----
|
|
58
|
+
|
|
59
|
+
.sbix structure
|
|
60
|
+
[example]
|
|
61
|
+
====
|
|
62
|
+
[source,text]
|
|
63
|
+
----
|
|
64
|
+
sbix 245892 bytes (offset: 542992, checksum: 0x12345678)
|
|
65
|
+
|
|
66
|
+
Strikes:
|
|
67
|
+
Strike 0: 72 PPI
|
|
68
|
+
Bitmaps: 150 glyphs
|
|
69
|
+
Format: PNG
|
|
70
|
+
Glyph 1 (emoji_smile): 128x128 pixels, 8.2 KB
|
|
71
|
+
Glyph 2 (emoji_heart): 128x128 pixels, 7.8 KB
|
|
72
|
+
----
|
|
73
|
+
====
|
|
74
|
+
|
|
75
|
+
=== SVG table color glyphs
|
|
76
|
+
|
|
77
|
+
The SVG table contains inline SVG graphics for color glyphs, supporting
|
|
78
|
+
gradients, transparency, and complex vector artwork.
|
|
79
|
+
|
|
80
|
+
[source,shell]
|
|
81
|
+
----
|
|
82
|
+
$ fontisan dump-table FONT.ttf SVG > svg_content.svg
|
|
83
|
+
----
|
|
84
|
+
|
|
85
|
+
.SVG table structure
|
|
86
|
+
[example]
|
|
87
|
+
====
|
|
88
|
+
[source,text]
|
|
89
|
+
----
|
|
90
|
+
svg 45678 bytes (offset: 788760, checksum: 0xABCDEF01)
|
|
91
|
+
|
|
92
|
+
SVG Documents: 12
|
|
93
|
+
Glyph 1 (emoji_flag_us): 1.2 KB
|
|
94
|
+
Glyph 2 (emoji_heart): 0.8 KB
|
|
95
|
+
Glyph 3 (gradient_icon): 2.1 KB
|
|
96
|
+
----
|
|
97
|
+
====
|
|
98
|
+
|
|
99
|
+
=== Ruby API for color fonts
|
|
100
|
+
|
|
101
|
+
Access color font data through the Ruby API.
|
|
102
|
+
|
|
103
|
+
[source,ruby]
|
|
104
|
+
----
|
|
105
|
+
require 'fontisan'
|
|
106
|
+
|
|
107
|
+
font = Fontisan::FontLoader.load('color_font.ttf')
|
|
108
|
+
|
|
109
|
+
# Access COLR/CPAL data
|
|
110
|
+
colr = font.table('COLR')
|
|
111
|
+
cpal = font.table('CPAL')
|
|
112
|
+
|
|
113
|
+
puts "Base glyphs: #{colr.num_base_glyph_records}"
|
|
114
|
+
puts "Palettes: #{cpal.num_palettes}"
|
|
115
|
+
|
|
116
|
+
# Access sbix strikes
|
|
117
|
+
sbix = font.table('sbix')
|
|
118
|
+
sbix.strikes.each do |strike|
|
|
119
|
+
puts "Strike: #{strike[:ppi]} PPI, #{strike[:num_glyphs]} glyphs"
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# Access SVG data
|
|
123
|
+
svg = font.table('SVG')
|
|
124
|
+
svg.document_records.each do |record|
|
|
125
|
+
puts "Glyphs #{record.start_glyph_id}-#{record.end_glyph_id}: #{record.svg_doc_length} bytes"
|
|
126
|
+
end
|
|
127
|
+
----
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# Fontisan Documentation Summary
|
|
2
|
+
|
|
3
|
+
This document provides an overview of all Fontisan documentation files and their purpose.
|
|
4
|
+
|
|
5
|
+
## Main Documentation
|
|
6
|
+
|
|
7
|
+
### README.adoc
|
|
8
|
+
Primary user guide and reference documentation for Fontisan.
|
|
9
|
+
|
|
10
|
+
## Feature Guides
|
|
11
|
+
|
|
12
|
+
### Font Hinting
|
|
13
|
+
- **File**: `docs/FONT_HINTING.adoc`
|
|
14
|
+
- **Purpose**: Documentation for font hinting features in Fontisan
|
|
15
|
+
- **Topics**: TrueType and PostScript hinting, hint extraction and application
|
|
16
|
+
|
|
17
|
+
### Variable Font Operations
|
|
18
|
+
- **File**: `docs/VARIABLE_FONT_OPERATIONS.adoc`
|
|
19
|
+
- **Purpose**: Guide for working with variable fonts
|
|
20
|
+
- **Topics**: Instance generation, axis manipulation, variation preservation
|
|
21
|
+
|
|
22
|
+
### TTC Migration Guide
|
|
23
|
+
- **File**: `docs/EXTRACT_TTC_MIGRATION.md`
|
|
24
|
+
- **Purpose**: Migration guide for users of the `extract-ttc` gem
|
|
25
|
+
- **Topics**: Moving from extract-ttc to Fontisan pack/unpack commands
|
|
26
|
+
|
|
27
|
+
### Web Font Formats
|
|
28
|
+
- **File**: `docs/WOFF_WOFF2_FORMATS.adoc`
|
|
29
|
+
- **Purpose**: Documentation for WOFF and WOFF2 web font formats
|
|
30
|
+
- **Topics**: Conversion to/from WOFF/WOFF2, web optimization
|
|
31
|
+
|
|
32
|
+
### Color Fonts
|
|
33
|
+
- **File**: `docs/COLOR_FONTS.adoc`
|
|
34
|
+
- **Purpose**: Guide for color font formats
|
|
35
|
+
- **Topics**: COLR/CPAL, SVG-in-OpenType, sbix color fonts
|
|
36
|
+
|
|
37
|
+
### Validation
|
|
38
|
+
- **File**: `docs/VALIDATION.adoc`
|
|
39
|
+
- **Purpose**: Font validation framework documentation
|
|
40
|
+
- **Topics**: Validation profiles, quality checks, OpenType spec compliance
|
|
41
|
+
|
|
42
|
+
### Apple Legacy Fonts
|
|
43
|
+
- **File**: `docs/APPLE_LEGACY_FONTS.adoc`
|
|
44
|
+
- **Purpose**: Documentation for Apple legacy font formats
|
|
45
|
+
- **Topics**: dfont format, Mac suitcase fonts
|
|
46
|
+
|
|
47
|
+
### Collection Validation
|
|
48
|
+
- **File**: `docs/COLLECTION_VALIDATION.adoc`
|
|
49
|
+
- **Purpose**: Guide for validating font collections (TTC/OTC/dfont)
|
|
50
|
+
- **Topics**: Collection-specific validation, profile selection
|
|
51
|
+
|
|
52
|
+
## CLI Commands Reference
|
|
53
|
+
|
|
54
|
+
Fontisan provides the following CLI commands:
|
|
55
|
+
|
|
56
|
+
| Command | Purpose |
|
|
57
|
+
|---------|---------|
|
|
58
|
+
| `info` | Display font information |
|
|
59
|
+
| `ls` | List contents (fonts in collection or font summary) |
|
|
60
|
+
| `tables` | List OpenType tables |
|
|
61
|
+
| `glyphs` | List glyph names |
|
|
62
|
+
| `unicode` | List Unicode to glyph mappings |
|
|
63
|
+
| `variable` | Display variable font information |
|
|
64
|
+
| `optical-size` | Display optical size information |
|
|
65
|
+
| `scripts` | List supported scripts from GSUB/GPOS tables |
|
|
66
|
+
| `features` | List GSUB/GPOS features |
|
|
67
|
+
| `subset` | Subset a font to specific glyphs |
|
|
68
|
+
| `convert` | Convert font to different format |
|
|
69
|
+
| `instance` | Generate static font instance from variable font |
|
|
70
|
+
| `pack` | Pack multiple fonts into TTC/OTC collection |
|
|
71
|
+
| `unpack` | Unpack fonts from TTC/OTC collection |
|
|
72
|
+
| `validate` | Validate font file |
|
|
73
|
+
| `export` | Export font to TTX/YAML/JSON format |
|
|
74
|
+
| `dump-table` | Dump raw table data to stdout |
|
|
75
|
+
| `version` | Display version information |
|
|
76
|
+
|
|
77
|
+
## Ruby API Reference
|
|
78
|
+
|
|
79
|
+
### Fontisan Module Methods
|
|
80
|
+
|
|
81
|
+
#### `Fontisan.info(path, brief: false, font_index: 0)`
|
|
82
|
+
Get font information. Supports both full and brief modes.
|
|
83
|
+
|
|
84
|
+
- **Parameters**:
|
|
85
|
+
- `path` (String): Path to font file
|
|
86
|
+
- `brief` (Boolean): Use brief mode for fast identification (default: false)
|
|
87
|
+
- `font_index` (Integer): Index for TTC/OTC files (default: 0)
|
|
88
|
+
- **Returns**: `Models::FontInfo`, `Models::CollectionInfo`, or `Models::CollectionBriefInfo`
|
|
89
|
+
- **Example**:
|
|
90
|
+
```ruby
|
|
91
|
+
info = Fontisan.info("font.ttf", brief: true)
|
|
92
|
+
puts info.family_name
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
#### `Fontisan.validate(path, profile: :default, options: {})`
|
|
96
|
+
Validate a font file using specified profile.
|
|
97
|
+
|
|
98
|
+
- **Parameters**:
|
|
99
|
+
- `path` (String): Path to font file
|
|
100
|
+
- `profile` (Symbol/String): Validation profile (default: :default)
|
|
101
|
+
- `options` (Hash): Additional validation options
|
|
102
|
+
- **Available Profiles**:
|
|
103
|
+
- `:indexability` - Fast validation for font discovery
|
|
104
|
+
- `:usability` - Basic usability for installation
|
|
105
|
+
- `:production` - Comprehensive quality checks (default)
|
|
106
|
+
- `:web` - Web embedding and optimization
|
|
107
|
+
- `:spec_compliance` - Full OpenType spec compliance
|
|
108
|
+
- `:default` - Alias for production profile
|
|
109
|
+
- **Returns**: `Models::ValidationReport`
|
|
110
|
+
- **Example**:
|
|
111
|
+
```ruby
|
|
112
|
+
report = Fontisan.validate("font.ttf", profile: :web)
|
|
113
|
+
puts "Errors: #{report.summary.errors}"
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Fontisan::FontLoader
|
|
117
|
+
|
|
118
|
+
Module for loading fonts in different modes.
|
|
119
|
+
|
|
120
|
+
- **Methods**:
|
|
121
|
+
- `load(path, mode: :full)` - Load a font file
|
|
122
|
+
- **Loading Modes**:
|
|
123
|
+
- `:full` - Load all tables
|
|
124
|
+
- `:metadata` - Load only metadata tables (name, head, hhea, maxp, OS/2, post)
|
|
125
|
+
- `:tables` - Load specific tables only
|
|
126
|
+
- `:structure` - Load structure tables only
|
|
127
|
+
|
|
128
|
+
## Verification
|
|
129
|
+
|
|
130
|
+
Documentation examples are verified by `spec/documentation_examples_spec.rb`.
|
|
131
|
+
|
|
132
|
+
This spec ensures that:
|
|
133
|
+
1. All CLI commands referenced in documentation exist
|
|
134
|
+
2. All Ruby API methods are available
|
|
135
|
+
3. All documentation files are present
|
|
136
|
+
4. Command examples reference valid commands
|
|
137
|
+
|
|
138
|
+
Run verification with:
|
|
139
|
+
```bash
|
|
140
|
+
bundle exec rspec spec/documentation_examples_spec.rb -v
|
|
141
|
+
```
|
data/docs/FONT_HINTING.adoc
CHANGED
|
@@ -541,9 +541,12 @@ The hint system has comprehensive test coverage:
|
|
|
541
541
|
* **Total Tests**: 306 (100% passing)
|
|
542
542
|
* **Generator Tests**: 45
|
|
543
543
|
* **Validator Tests**: 48
|
|
544
|
+
* **Applier Tests**: 87 (PostScript: 63, TrueType: 24)
|
|
545
|
+
* **Extractor Tests**: 23 (PostScript: 11, TrueType: 12)
|
|
546
|
+
* **Converter Tests**: 29
|
|
544
547
|
* **Round-Trip Tests**: 16
|
|
548
|
+
* **Integration Tests**: 28 (Conversion: 11, Application: 17)
|
|
545
549
|
* **Analyzer Tests**: 30
|
|
546
|
-
* **Integration Tests**: 167
|
|
547
550
|
|
|
548
551
|
Test files:
|
|
549
552
|
|
|
@@ -552,7 +555,12 @@ Test files:
|
|
|
552
555
|
* link:../spec/fontisan/hints/hint_validator_spec.rb[hint_validator_spec.rb]
|
|
553
556
|
* link:../spec/fontisan/hints/hint_round_trip_spec.rb[hint_round_trip_spec.rb]
|
|
554
557
|
* link:../spec/fontisan/hints/hint_converter_spec.rb[hint_converter_spec.rb]
|
|
558
|
+
* link:../spec/fontisan/hints/postscript_hint_applier_spec.rb[postscript_hint_applier_spec.rb]
|
|
559
|
+
* link:../spec/fontisan/hints/postscript_hint_extractor_spec.rb[postscript_hint_extractor_spec.rb]
|
|
560
|
+
* link:../spec/fontisan/hints/truetype_hint_applier_spec.rb[truetype_hint_applier_spec.rb]
|
|
561
|
+
* link:../spec/fontisan/hints/truetype_hint_extractor_spec.rb[truetype_hint_extractor_spec.rb]
|
|
555
562
|
* link:../spec/fontisan/hints/hint_conversion_integration_spec.rb[hint_conversion_integration_spec.rb]
|
|
563
|
+
* link:../spec/fontisan/hints/hint_application_integration_spec.rb[hint_application_integration_spec.rb]
|
|
556
564
|
|
|
557
565
|
== References
|
|
558
566
|
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
= Font Validation Framework
|
|
2
|
+
|
|
3
|
+
== General
|
|
4
|
+
|
|
5
|
+
Fontisan provides a comprehensive validation framework for ensuring font quality,
|
|
6
|
+
structural integrity, and compliance with OpenType specifications.
|
|
7
|
+
|
|
8
|
+
The framework uses a declarative DSL for defining validation checks and supports
|
|
9
|
+
multiple validation profiles for different use cases.
|
|
10
|
+
|
|
11
|
+
== Validation profiles
|
|
12
|
+
|
|
13
|
+
Fontisan includes predefined validation profiles:
|
|
14
|
+
|
|
15
|
+
`indexability`:: Fast font discovery and indexing (8 checks, metadata-only, ~5x faster)
|
|
16
|
+
|
|
17
|
+
`usability`:: Font installation compatibility (26 checks, macOS Font Book focused)
|
|
18
|
+
|
|
19
|
+
`production`:: Comprehensive production quality (37 checks, OpenType spec compliance - default)
|
|
20
|
+
|
|
21
|
+
`web`:: Web font embedding readiness (18 checks for web deployment)
|
|
22
|
+
|
|
23
|
+
`spec_compliance`:: Full OpenType specification compliance (detailed analysis mode)
|
|
24
|
+
|
|
25
|
+
[source,shell]
|
|
26
|
+
----
|
|
27
|
+
$ fontisan validate --list
|
|
28
|
+
Available validation profiles:
|
|
29
|
+
indexability - Fast validation for font discovery and indexing
|
|
30
|
+
usability - Basic usability for installation
|
|
31
|
+
production - Comprehensive quality checks
|
|
32
|
+
web - Web embedding and optimization
|
|
33
|
+
spec_compliance - Full OpenType spec compliance
|
|
34
|
+
default - Default validation profile (alias for production)
|
|
35
|
+
----
|
|
36
|
+
|
|
37
|
+
== Command-line validation
|
|
38
|
+
|
|
39
|
+
.Validate with default profile
|
|
40
|
+
[example]
|
|
41
|
+
====
|
|
42
|
+
[source,shell]
|
|
43
|
+
----
|
|
44
|
+
$ fontisan validate font.ttf
|
|
45
|
+
|
|
46
|
+
Font: font.ttf
|
|
47
|
+
Status: VALID
|
|
48
|
+
|
|
49
|
+
Summary:
|
|
50
|
+
Checks performed: 37
|
|
51
|
+
Passed: 37
|
|
52
|
+
Failed: 0
|
|
53
|
+
|
|
54
|
+
Errors: 0
|
|
55
|
+
Warnings: 0
|
|
56
|
+
Info: 0
|
|
57
|
+
----
|
|
58
|
+
====
|
|
59
|
+
|
|
60
|
+
.Validate for web use with summary
|
|
61
|
+
[example]
|
|
62
|
+
====
|
|
63
|
+
[source,shell]
|
|
64
|
+
----
|
|
65
|
+
$ fontisan validate font.ttf -t web -S
|
|
66
|
+
|
|
67
|
+
Font: font.ttf
|
|
68
|
+
Status: VALID
|
|
69
|
+
|
|
70
|
+
Summary:
|
|
71
|
+
Checks performed: 18
|
|
72
|
+
Passed: 17
|
|
73
|
+
Failed: 1
|
|
74
|
+
|
|
75
|
+
Errors: 1
|
|
76
|
+
Warnings: 0
|
|
77
|
+
|
|
78
|
+
Failed checks:
|
|
79
|
+
web_font_tables - Missing required GSUB table
|
|
80
|
+
----
|
|
81
|
+
====
|
|
82
|
+
|
|
83
|
+
.Validation with table format output
|
|
84
|
+
[example]
|
|
85
|
+
====
|
|
86
|
+
[source,shell]
|
|
87
|
+
----
|
|
88
|
+
$ fontisan validate font.ttf -T
|
|
89
|
+
|
|
90
|
+
CHECK_ID | STATUS | SEVERITY | TABLE
|
|
91
|
+
------------------------------------------------------------
|
|
92
|
+
required_tables | PASS | error | N/A
|
|
93
|
+
name_version | PASS | error | name
|
|
94
|
+
family_name | PASS | error | name
|
|
95
|
+
----
|
|
96
|
+
====
|
|
97
|
+
====
|
|
98
|
+
|
|
99
|
+
== Ruby API usage
|
|
100
|
+
|
|
101
|
+
=== Using predefined profiles
|
|
102
|
+
|
|
103
|
+
[source,ruby]
|
|
104
|
+
----
|
|
105
|
+
require 'fontisan'
|
|
106
|
+
|
|
107
|
+
# Validate with default profile (production)
|
|
108
|
+
report = Fontisan.validate('font.ttf')
|
|
109
|
+
puts report.valid? # => true or false
|
|
110
|
+
|
|
111
|
+
# Validate with specific profile
|
|
112
|
+
report = Fontisan.validate('font.ttf', profile: :web)
|
|
113
|
+
puts "Errors: #{report.summary.errors}"
|
|
114
|
+
puts "Warnings: #{report.summary.warnings}"
|
|
115
|
+
|
|
116
|
+
# Check validation status
|
|
117
|
+
if report.valid?
|
|
118
|
+
puts "Font is valid for web use!"
|
|
119
|
+
else
|
|
120
|
+
puts "Font has #{report.summary.errors} errors"
|
|
121
|
+
end
|
|
122
|
+
----
|
|
123
|
+
|
|
124
|
+
=== Query validation results
|
|
125
|
+
|
|
126
|
+
[source,ruby]
|
|
127
|
+
----
|
|
128
|
+
report = Fontisan.validate('font.ttf', profile: :production)
|
|
129
|
+
|
|
130
|
+
# Get issues by severity
|
|
131
|
+
fatal_issues = report.fatal_errors
|
|
132
|
+
error_issues = report.errors_only
|
|
133
|
+
warning_issues = report.warnings_only
|
|
134
|
+
info_issues = report.info_only
|
|
135
|
+
|
|
136
|
+
# Get issues by category
|
|
137
|
+
table_issues = report.issues_by_category('table_validation')
|
|
138
|
+
|
|
139
|
+
# Get check results
|
|
140
|
+
failed_ids = report.failed_check_ids
|
|
141
|
+
pass_rate = report.pass_rate
|
|
142
|
+
|
|
143
|
+
# Export to different formats
|
|
144
|
+
yaml_output = report.to_yaml
|
|
145
|
+
json_output = report.to_json
|
|
146
|
+
summary = report.to_summary # "2 errors, 3 warnings, 0 info"
|
|
147
|
+
----
|
|
148
|
+
|
|
149
|
+
== Creating custom validators
|
|
150
|
+
|
|
151
|
+
=== General
|
|
152
|
+
|
|
153
|
+
Custom validators inherit from `Fontisan::Validators::Validator` and define
|
|
154
|
+
validation logic using the DSL.
|
|
155
|
+
|
|
156
|
+
The DSL provides 6 check methods:
|
|
157
|
+
|
|
158
|
+
* `check_table` - Validate table-level properties
|
|
159
|
+
* `check_field` - Validate specific field values
|
|
160
|
+
* `check_structure` - Validate font structure and relationships
|
|
161
|
+
* `check_usability` - Validate usability and best practices
|
|
162
|
+
* `check_instructions` - Validate TrueType instructions/hinting
|
|
163
|
+
* `check_glyphs` - Validate individual glyphs
|
|
164
|
+
|
|
165
|
+
.Creating a custom validator
|
|
166
|
+
[example]
|
|
167
|
+
====
|
|
168
|
+
[source,ruby]
|
|
169
|
+
----
|
|
170
|
+
require 'fontisan/validators/validator'
|
|
171
|
+
|
|
172
|
+
class MyFontValidator < Fontisan::Validators::Validator
|
|
173
|
+
private
|
|
174
|
+
|
|
175
|
+
def define_checks
|
|
176
|
+
# Check name table
|
|
177
|
+
check_table :name_validation, 'name', severity: :error do |table|
|
|
178
|
+
table.valid_version? &&
|
|
179
|
+
table.valid_encoding_heuristics? &&
|
|
180
|
+
table.family_name_present? &&
|
|
181
|
+
table.postscript_name_valid?
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# Check head table
|
|
185
|
+
check_table :head_validation, 'head', severity: :error do |table|
|
|
186
|
+
table.valid_magic? &&
|
|
187
|
+
table.valid_version? &&
|
|
188
|
+
table.valid_units_per_em?
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
# Check structure
|
|
192
|
+
check_structure :required_tables, severity: :error do |font|
|
|
193
|
+
%w[name head maxp hhea].all? { |tag| !font.table(tag).nil? }
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
# Use the validator
|
|
199
|
+
font = Fontisan::FontLoader.load('font.ttf')
|
|
200
|
+
validator = MyFontValidator.new
|
|
201
|
+
report = validator.validate(font)
|
|
202
|
+
|
|
203
|
+
puts report.valid? # => true/false
|
|
204
|
+
puts report.summary.errors # => number of errors
|
|
205
|
+
puts report.summary.warnings # => number of warnings
|
|
206
|
+
----
|
|
207
|
+
====
|
|
208
|
+
|
|
209
|
+
== Validation helpers
|
|
210
|
+
|
|
211
|
+
The validation framework provides 56 helper methods across 8 core OpenType
|
|
212
|
+
tables. Each helper returns a boolean indicating whether the validation passed.
|
|
213
|
+
|
|
214
|
+
.Name table helpers:
|
|
215
|
+
[example]
|
|
216
|
+
====
|
|
217
|
+
[source,ruby]
|
|
218
|
+
----
|
|
219
|
+
class MyValidator < Fontisan::Validators::Validator
|
|
220
|
+
private
|
|
221
|
+
|
|
222
|
+
def define_checks
|
|
223
|
+
check_table :name_validation, 'name', severity: :error do |table|
|
|
224
|
+
table.valid_version? &&
|
|
225
|
+
table.valid_encoding_heuristics? &&
|
|
226
|
+
table.family_name_present? &&
|
|
227
|
+
table.postscript_name_valid?
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
----
|
|
232
|
+
====
|
|
233
|
+
|
|
234
|
+
.Head table helpers:
|
|
235
|
+
[example]
|
|
236
|
+
====
|
|
237
|
+
[source,ruby]
|
|
238
|
+
----
|
|
239
|
+
class MyValidator < Fontisan::Validators::Validator
|
|
240
|
+
private
|
|
241
|
+
|
|
242
|
+
def define_checks
|
|
243
|
+
check_table :head_validation, 'head', severity: :error do |table|
|
|
244
|
+
table.valid_magic? &&
|
|
245
|
+
table.valid_version? &&
|
|
246
|
+
table.valid_units_per_em? &&
|
|
247
|
+
table.valid_bounding_box? &&
|
|
248
|
+
table.valid_index_to_loc_format? &&
|
|
249
|
+
table.valid_glyph_data_format?
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
----
|
|
254
|
+
====
|