fontisan 0.2.4 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +150 -30
  3. data/README.adoc +497 -242
  4. data/lib/fontisan/cli.rb +67 -6
  5. data/lib/fontisan/commands/validate_command.rb +107 -151
  6. data/lib/fontisan/converters/woff2_encoder.rb +7 -29
  7. data/lib/fontisan/models/validation_report.rb +227 -0
  8. data/lib/fontisan/pipeline/transformation_pipeline.rb +4 -8
  9. data/lib/fontisan/tables/cmap.rb +82 -2
  10. data/lib/fontisan/tables/glyf.rb +118 -0
  11. data/lib/fontisan/tables/head.rb +60 -0
  12. data/lib/fontisan/tables/hhea.rb +74 -0
  13. data/lib/fontisan/tables/maxp.rb +60 -0
  14. data/lib/fontisan/tables/name.rb +76 -0
  15. data/lib/fontisan/tables/os2.rb +113 -0
  16. data/lib/fontisan/tables/post.rb +57 -0
  17. data/lib/fontisan/validators/basic_validator.rb +85 -0
  18. data/lib/fontisan/validators/font_book_validator.rb +130 -0
  19. data/lib/fontisan/validators/opentype_validator.rb +112 -0
  20. data/lib/fontisan/validators/profile_loader.rb +139 -0
  21. data/lib/fontisan/validators/validator.rb +484 -0
  22. data/lib/fontisan/validators/web_font_validator.rb +102 -0
  23. data/lib/fontisan/version.rb +1 -1
  24. data/lib/fontisan.rb +78 -6
  25. metadata +7 -11
  26. data/lib/fontisan/config/validation_rules.yml +0 -149
  27. data/lib/fontisan/validation/checksum_validator.rb +0 -170
  28. data/lib/fontisan/validation/consistency_validator.rb +0 -197
  29. data/lib/fontisan/validation/structure_validator.rb +0 -198
  30. data/lib/fontisan/validation/table_validator.rb +0 -158
  31. data/lib/fontisan/validation/validator.rb +0 -152
  32. data/lib/fontisan/validation/variable_font_validator.rb +0 -218
  33. data/lib/fontisan/validation/woff2_header_validator.rb +0 -278
  34. data/lib/fontisan/validation/woff2_table_validator.rb +0 -270
  35. data/lib/fontisan/validation/woff2_validator.rb +0 -248
data/README.adoc CHANGED
@@ -424,6 +424,11 @@ tables:
424
424
  length: 17870
425
425
  offset: 542992
426
426
  checksum: 701383168
427
+ - tag: OS/2
428
+ length: 96
429
+ offset: 392
430
+ checksum: 1193824355
431
+ ...
427
432
  ----
428
433
  ====
429
434
 
@@ -505,7 +510,7 @@ Syntax:
505
510
  $ fontisan unicode FONT_FILE [--format FORMAT]
506
511
  ----
507
512
 
508
- Where,
513
+ Where:
509
514
 
510
515
  `FONT_FILE`:: Path to the font file (OTF, TTF, or TTC)
511
516
  `FORMAT`:: Output format: `text` (default), `json`, or `yaml`
@@ -734,10 +739,8 @@ Dry-run mode: Preview of instance generation
734
739
  Coordinates:
735
740
  wght: 700.0
736
741
 
737
- Output would be written to: variable-instance.ttf
738
- Output
739
-
740
- format: same as input
742
+ Output file: variable-instance.ttf
743
+ Format: same as input
741
744
 
742
745
  Use without --dry-run to actually generate the instance.
743
746
  ----
@@ -1020,6 +1023,492 @@ Uses base64 encoding for binary data instead of hexadecimal, useful for
1020
1023
  JSON-based workflows.
1021
1024
  ====
1022
1025
 
1026
+ == Font validation
1027
+
1028
+ === General
1029
+
1030
+ Fontisan provides validation functionality to ensure font quality, structural
1031
+ integrity, and compliance with various standards.
1032
+
1033
+ The validation framework allows developers to create custom validators using a
1034
+ declarative DSL. Validators can perform checks on font tables, fields,
1035
+ structures, usability, instructions, and glyphs.
1036
+
1037
+ === Predefined profiles
1038
+
1039
+ Fontisan includes several predefined validation profiles for common use cases:
1040
+
1041
+ `indexability`:: Fast validation for font discovery and indexing (< 50ms). Uses
1042
+ BasicValidator with 8 essential checks. Loading mode: metadata.
1043
+
1044
+ `usability`:: Basic usability for font installation. Uses FontBookValidator with
1045
+ 26 checks including macOS Font Book compatibility. Loading mode: full.
1046
+
1047
+ `production`:: Comprehensive quality checks for production fonts (default
1048
+ profile). Uses OpenTypeValidator with 36 checks for OpenType spec compliance.
1049
+ Loading mode: full.
1050
+
1051
+ `web`:: Web font embedding and optimization validation. Uses WebFontValidator
1052
+ with 18 checks for web deployment. Loading mode: full.
1053
+
1054
+ `spec_compliance`:: Full OpenType specification compliance with detailed checks.
1055
+ Uses OpenTypeValidator with info-level severity for comprehensive analysis.
1056
+ Loading mode: full.
1057
+
1058
+ `default`:: Alias for the production profile.
1059
+
1060
+
1061
+ === Command-line usage
1062
+
1063
+ ==== Validate a font file against a predefined profile
1064
+
1065
+ .Validate with default profile
1066
+ [example]
1067
+ ====
1068
+ [source,shell]
1069
+ ----
1070
+ $ fontisan validate font.ttf
1071
+ ----
1072
+ ====
1073
+
1074
+ .Validate for web use
1075
+ [example]
1076
+ ====
1077
+ [source,shell]
1078
+ ----
1079
+ $ fontisan validate font.ttf -t web
1080
+ ----
1081
+ ====
1082
+
1083
+ .List available profiles
1084
+ [example]
1085
+ ====
1086
+ [source,shell]
1087
+ ----
1088
+ $ fontisan validate --list
1089
+ Available validation profiles:
1090
+ indexability - Fast validation for font discovery and indexing
1091
+ usability - Basic usability for installation
1092
+ production - Comprehensive quality checks
1093
+ web - Web embedding and optimization
1094
+ spec_compliance - Full OpenType spec compliance
1095
+ default - Default validation profile (alias for production)
1096
+ ----
1097
+ ====
1098
+
1099
+ .Full report to file
1100
+ [example]
1101
+ ====
1102
+ [source,shell]
1103
+ ----
1104
+ $ fontisan validate font.ttf -t production -r -o report.txt
1105
+ ----
1106
+ ====
1107
+
1108
+ .Summary with return value
1109
+ [example]
1110
+ ====
1111
+ [source,shell]
1112
+ ----
1113
+ $ fontisan validate font.ttf -S -R
1114
+ 0 errors, 2 warnings, 0 info
1115
+ $ echo $?
1116
+ 4 # Exit code 4 indicates warnings found
1117
+ ----
1118
+ ====
1119
+
1120
+ .Table format output
1121
+ [example]
1122
+ ====
1123
+ [source,shell]
1124
+ ----
1125
+ $ fontisan validate font.ttf -T
1126
+ CHECK_ID | STATUS | SEVERITY | TABLE
1127
+ ------------------------------------------------------------
1128
+ required_tables | PASS | error | N/A
1129
+ name_version | PASS | error | name
1130
+ family_name | PASS | error | name
1131
+ ...
1132
+ ----
1133
+ ====
1134
+
1135
+ ==== CLI options
1136
+
1137
+ -t, --test-list PROFILE:: Select validation profile (indexability, usability,
1138
+ production, web, spec_compliance, default)
1139
+
1140
+ -l, --list:: List available validation profiles
1141
+
1142
+ -o, --output FILE:: Write report to file instead of stdout
1143
+
1144
+ -r, --full-report:: Generate full detailed report
1145
+
1146
+ -R, --return-value-results:: Use return value to indicate results (0=none,
1147
+ 1=error, 2=fatal, 3=major, 4=minor, 5=info)
1148
+
1149
+ -S, --summary-report:: Generate brief summary report
1150
+
1151
+ -T, --table-report:: Generate tabular format report
1152
+
1153
+ -v, --verbose:: Enable verbose output
1154
+
1155
+ -w, --suppress-warnings:: Suppress warning output
1156
+
1157
+ -e, --exclude CHECKS:: Exclude specific checks (comma-separated list)
1158
+
1159
+
1160
+ === Ruby API usage
1161
+
1162
+ ==== Architecture
1163
+
1164
+ The validation framework in Ruby consists of:
1165
+
1166
+ DSL base class:: `Fontisan::Validators::Validator` provides a declarative syntax
1167
+ for defining validation checks
1168
+
1169
+ Table validation helpers::
1170
+ 56 helper methods across 8 core OpenType tables (name, head, maxp, hhea, glyf,
1171
+ cmap, post, OS/2) that perform specific validation checks
1172
+
1173
+ ValidationReport::
1174
+ Structured reports with individual check results, severity levels, and
1175
+ comprehensive issue tracking
1176
+
1177
+ ==== Using predefined profiles
1178
+
1179
+ .Validate with Ruby API
1180
+ [example]
1181
+ ====
1182
+ [source,ruby]
1183
+ ----
1184
+ require 'fontisan'
1185
+
1186
+ # Validate with default profile (production)
1187
+ report = Fontisan.validate('font.ttf')
1188
+ puts report.valid? # => true or false
1189
+
1190
+ # Validate with specific profile
1191
+ report = Fontisan.validate('font.ttf', profile: :web)
1192
+ puts "Errors: #{report.summary.errors}"
1193
+ puts "Warnings: #{report.summary.warnings}"
1194
+
1195
+ # Check validation status
1196
+ if report.valid?
1197
+ puts "Font is valid for web use!"
1198
+ else
1199
+ puts "Font has #{report.summary.errors} errors"
1200
+ end
1201
+ ----
1202
+ ====
1203
+
1204
+ .Query validation results
1205
+ [example]
1206
+ ====
1207
+ [source,ruby]
1208
+ ----
1209
+ report = Fontisan.validate('font.ttf', profile: :production)
1210
+
1211
+ # Get issues by severity
1212
+ fatal_issues = report.fatal_errors
1213
+ error_issues = report.errors_only
1214
+ warning_issues = report.warnings_only
1215
+ info_issues = report.info_only
1216
+
1217
+ # Get issues by category
1218
+ table_issues = report.issues_by_category('table_validation')
1219
+
1220
+ # Get check results
1221
+ failed_ids = report.failed_check_ids
1222
+ pass_rate = report.pass_rate
1223
+
1224
+ # Export to different formats
1225
+ yaml_output = report.to_yaml
1226
+ json_output = report.to_json
1227
+ summary = report.to_summary # "2 errors, 3 warnings, 0 info"
1228
+ ----
1229
+ ====
1230
+
1231
+ .Use validators directly
1232
+ [example]
1233
+ ====
1234
+ [source,ruby]
1235
+ ----
1236
+ require 'fontisan'
1237
+
1238
+ # Load font
1239
+ font = Fontisan::FontLoader.load('font.ttf')
1240
+
1241
+ # Use specific validator
1242
+ validator = Fontisan::Validators::OpenTypeValidator.new
1243
+ report = validator.validate(font)
1244
+
1245
+ # Check individual results
1246
+ name_check = report.result_of(:name_version)
1247
+ puts name_check.passed?
1248
+ puts name_check.severity
1249
+ ----
1250
+ ====
1251
+
1252
+ ==== Using custom validators
1253
+
1254
+ ===== General
1255
+
1256
+ Custom validators inherit from `Fontisan::Validators::Validator` and define
1257
+ validation logic using the DSL.
1258
+
1259
+ The DSL provides 6 check methods for different validation types:
1260
+
1261
+ * `check_table` - Validate table-level properties
1262
+ * `check_field` - Validate specific field values
1263
+ * `check_structure` - Validate font structure and relationships
1264
+ * `check_usability` - Validate usability and best practices
1265
+ * `check_instructions` - Validate TrueType instructions/hinting
1266
+ * `check_glyphs` - Validate individual glyphs
1267
+
1268
+ Each check receives a unique ID, severity level (:info, :warning, :error,
1269
+ :fatal), and a validation block.
1270
+
1271
+ .Creating a custom validator
1272
+ [example]
1273
+ ====
1274
+ [source,ruby]
1275
+ ----
1276
+ require 'fontisan/validators/validator'
1277
+
1278
+ # Define a custom validator
1279
+ class MyFontValidator < Fontisan::Validators::Validator
1280
+ private
1281
+
1282
+ def define_checks
1283
+ # Check name table
1284
+ check_table :name_version, 'name', severity: :error do |table|
1285
+ table.valid_version?
1286
+ end
1287
+
1288
+ check_table :family_name, 'name', severity: :error do |table|
1289
+ table.family_name_present?
1290
+ end
1291
+
1292
+ # Check head table
1293
+ check_table :head_magic, 'head', severity: :error do |table|
1294
+ table.valid_magic?
1295
+ end
1296
+
1297
+ check_table :units_per_em, 'head', severity: :error do |table|
1298
+ table.valid_units_per_em?
1299
+ end
1300
+
1301
+ # Check structure
1302
+ check_structure :required_tables, severity: :error do |font|
1303
+ %w[name head maxp hhea].all? { |tag| !font.table(tag).nil? }
1304
+ end
1305
+ end
1306
+ end
1307
+
1308
+ # Use the validator
1309
+ font = Fontisan::FontLoader.load('font.ttf')
1310
+ validator = MyFontValidator.new
1311
+ report = validator.validate(font)
1312
+
1313
+ # Check results
1314
+ puts report.valid? # => true/false
1315
+ puts report.status # => "valid", "valid_with_warnings", "invalid"
1316
+ puts report.summary.errors # => number of errors
1317
+ puts report.summary.warnings # => number of warnings
1318
+
1319
+ # Query specific checks
1320
+ result = report.result_of(:name_version)
1321
+ puts result.passed? # => true/false
1322
+ puts result.severity # => "error"
1323
+ puts result.messages # => array of messages
1324
+
1325
+ # Get all failed checks
1326
+ report.failed_checks.each do |check|
1327
+ puts "#{check.check_id}: #{check.messages.join(', ')}"
1328
+ end
1329
+
1330
+ # Serialize report
1331
+ puts report.to_yaml
1332
+ puts report.to_json
1333
+ ----
1334
+ ====
1335
+
1336
+
1337
+ .Using table validation helpers
1338
+ [example]
1339
+ ====
1340
+ The validation framework integrates with 56 built-in validation helpers across
1341
+ core OpenType tables. These helpers perform specific validation checks and
1342
+ return boolean values.
1343
+
1344
+ [source,ruby]
1345
+ ----
1346
+ class ComprehensiveValidator < Fontisan::Validators::Validator
1347
+ private
1348
+
1349
+ def define_checks
1350
+ # Name table validation helpers
1351
+ check_table :name_validation, 'name' do |table|
1352
+ table.valid_version? &&
1353
+ table.valid_encoding_heuristics? &&
1354
+ table.family_name_present? &&
1355
+ table.postscript_name_valid?
1356
+ end
1357
+
1358
+ # Head table validation helpers
1359
+ check_table :head_validation, 'head' do |table|
1360
+ table.valid_magic? &&
1361
+ table.valid_version? &&
1362
+ table.valid_units_per_em? &&
1363
+ table.valid_bounding_box? &&
1364
+ table.valid_index_to_loc_format? &&
1365
+ table.valid_glyph_data_format?
1366
+ end
1367
+
1368
+ # Maxp table validation helpers
1369
+ check_table :maxp_validation, 'maxp' do |table|
1370
+ table.valid_version? &&
1371
+ table.valid_num_glyphs? &&
1372
+ table.valid_max_zones? &&
1373
+ table.has_truetype_metrics? &&
1374
+ table.reasonable_metrics?
1375
+ end
1376
+ end
1377
+ end
1378
+ ----
1379
+ ====
1380
+
1381
+ .Handling validation results
1382
+ [example]
1383
+ ====
1384
+ [source,ruby]
1385
+ ----
1386
+ validator = MyFontValidator.new
1387
+ report = validator.validate(font)
1388
+
1389
+ # Overall validation status
1390
+ if report.valid?
1391
+ puts "Font is valid!"
1392
+ else
1393
+ puts "Font has issues:"
1394
+
1395
+ # Show errors
1396
+ report.errors.each do |error|
1397
+ puts " [ERROR] #{error.category}: #{error.message}"
1398
+ puts " Location: #{error.location}" if error.location
1399
+ end
1400
+
1401
+ # Show warnings
1402
+ report.warnings.each do |warning|
1403
+ puts " [WARN] #{warning.category}: #{warning.message}"
1404
+ end
1405
+ end
1406
+
1407
+ # Check specific validation results
1408
+ if report.result_of(:name_version)&.passed?
1409
+ puts "Name table version is valid"
1410
+ else
1411
+ puts "Name table version check failed"
1412
+ end
1413
+
1414
+ # Get summary statistics
1415
+ puts "\nValidation Summary:"
1416
+ puts " Total checks: #{report.check_results.count}"
1417
+ puts " Passed: #{report.passed_checks.count}"
1418
+ puts " Failed: #{report.failed_checks.count}"
1419
+ puts " Errors: #{report.summary.errors}"
1420
+ puts " Warnings: #{report.summary.warnings}"
1421
+ puts " Info: #{report.summary.info}"
1422
+ ----
1423
+ ====
1424
+
1425
+ ==== Validation helpers
1426
+
1427
+ ===== General
1428
+
1429
+ The validation framework provides 56 helper methods across 8 core OpenType
1430
+ tables. Each helper returns a boolean indicating whether the validation passed.
1431
+
1432
+ Name table:
1433
+
1434
+ * `valid_version?` - Check if version is 0 or 1
1435
+ * `valid_encoding_heuristics?` - Check platform/encoding combinations
1436
+ * `has_valid_platform_combos?` - Check for required platform combinations
1437
+ * `family_name_present?` - Check if family name exists and is non-empty
1438
+ * `postscript_name_present?` - Check if PostScript name exists and is non-empty
1439
+ * `postscript_name_valid?` - Check if PostScript name matches required pattern
1440
+
1441
+ Head table:
1442
+
1443
+ * `valid_magic?` - Check magic number (0x5F0F3CF5)
1444
+ * `valid_version?` - Check version is 1.0
1445
+ * `valid_units_per_em?` - Check units per em is valid (16-16384)
1446
+ * `valid_bounding_box?` - Check bounding box coordinates
1447
+ * `valid_index_to_loc_format?` - Check format is 0 or 1
1448
+ * `valid_glyph_data_format?` - Check format is 0
1449
+
1450
+ Maxp Table:
1451
+
1452
+ * `valid_version?` - Check version is 0.5 or 1.0
1453
+ * `valid_num_glyphs?` - Check num glyphs >= 1
1454
+ * `valid_max_zones?` - Check maxZones is 1 or 2
1455
+ * `has_truetype_metrics?` - Check TrueType metrics are present
1456
+ * `reasonable_metrics?` - Check metrics are within reasonable bounds
1457
+
1458
+ Hhea Table:
1459
+
1460
+ * `valid_version?` - Check version is 1.0
1461
+ * `valid_metric_data_format?` - Check format is 0
1462
+ * `valid_number_of_h_metrics?` - Check count >= 1
1463
+ * `valid_ascent_descent?` - Check signs are correct
1464
+ * `valid_line_gap?` - Check line gap >= 0
1465
+ * `valid_advance_width_max?` - Check max width > 0
1466
+ * `valid_caret_slope?` - Check caret slope values
1467
+ * `valid_x_max_extent?` - Check extent > 0
1468
+
1469
+ Glyf Table:
1470
+
1471
+ * `has_empty_glyphs?` - Check for empty glyphs
1472
+ * `has_clipped_glyphs?` - Check for clipped glyphs
1473
+ * `has_instructions?` - Check for TrueType instructions
1474
+ * `contours_valid?` - Check contour counts
1475
+ * `glyphs_accessible?` - Check glyph accessibility
1476
+
1477
+ Cmap Table:
1478
+
1479
+ * `valid_version?` - Check version is 0
1480
+ * `has_valid_subtables?` - Check subtable validity
1481
+ * `has_unicode_mapping?` - Check for Unicode support
1482
+ * `has_valid_bmp_coverage?` - Check BMP coverage
1483
+ * `has_valid_format4?` - Check format 4 subtable
1484
+ * `glyph_indices_valid?` - Check glyph index validity
1485
+ * `supports_platform?` - Check platform support
1486
+
1487
+ Post Table:
1488
+
1489
+ * `valid_version?` - Check version (1.0, 2.0, 2.5, 3.0, 4.0)
1490
+ * `valid_italic_angle?` - Check italic angle range
1491
+ * `valid_underline_position?` - Check underline metrics
1492
+ * `valid_underline_thickness?` - Check underline thickness
1493
+ * `valid_is_fixed_pitch?` - Check fixed pitch flag
1494
+ * `has_glyph_names?` - Check for glyph names
1495
+
1496
+ OS/2 Table:
1497
+
1498
+ * `valid_version?` - Check version (0-5)
1499
+ * `valid_weight_class?` - Check weight class (100-900)
1500
+ * `valid_width_class?` - Check width class (1-9)
1501
+ * `valid_vendor_id?` - Check vendor ID format
1502
+ * `valid_typo_metrics?` - Check typographic metrics
1503
+ * `valid_win_metrics?` - Check Windows metrics
1504
+ * `valid_unicode_ranges?` - Check Unicode range bits
1505
+ * `has_valid_panose?` - Check PANOSE classification
1506
+ * `valid_selection_flags?` - Check style selection flags
1507
+ * `valid_first_char_index?` - Check first character index
1508
+ * `valid_last_char_index?` - Check last character index
1509
+ * `valid_typo_ascender?` - Check typographic ascender
1510
+ * `valid_typo_descender?` - Check typographic descender
1511
+
1023
1512
 
1024
1513
  == Version information
1025
1514
 
@@ -1300,173 +1789,6 @@ $ fontisan validate FONT.{ttc,otc}
1300
1789
  NOTE: In `extract_ttc`, this was done with `extract_ttc --validate FONT.ttc`.
1301
1790
 
1302
1791
 
1303
-
1304
-
1305
- == Color font support
1306
-
1307
- === General
1308
-
1309
- Fontisan provides comprehensive analysis of all color font formats defined in the OpenType specification.
1310
-
1311
- === Supported color font formats
1312
-
1313
- Fontisan supports all four color font table formats:
1314
-
1315
- COLR/CPAL:: Layered color glyphs with custom color palettes (Microsoft/Google standard)
1316
-
1317
- SVG:: Embedded SVG graphics with gzip compression support (W3C standard)
1318
-
1319
- CBDT/CBLC:: Bitmap glyphs at multiple ppem sizes (Google format)
1320
-
1321
- sbix:: Bitmap graphics with PNG/JPEG/TIFF support (Apple format)
1322
-
1323
- === Analyzing color fonts
1324
-
1325
- [source,ruby]
1326
- ----
1327
- require 'fontisan'
1328
-
1329
- # Load and analyze a color font
1330
- info = Fontisan.info('emoji-font.ttf')
1331
-
1332
- # Color glyph detection
1333
- puts info.is_color_font # true if COLR/CPAL present
1334
- puts info.has_svg_table # true if SVG table present
1335
- puts info.has_bitmap_glyphs # true if CBDT/CBLC or sbix present
1336
-
1337
- # Get color palette information (COLR/CPAL)
1338
- if info.is_color_font
1339
- puts "Color glyphs: #{info.color_glyphs}"
1340
- puts "Color palettes: #{info.color_palettes}"
1341
- puts "Colors per palette: #{info.colors_per_palette}"
1342
- end
1343
-
1344
- # Get SVG glyph information
1345
- if info.has_svg_table
1346
- puts "SVG glyphs: #{info.svg_glyph_count}"
1347
- end
1348
-
1349
- # Get bitmap information
1350
- if info.has_bitmap_glyphs
1351
- puts "Bitmap formats: #{info.bitmap_formats.join(', ')}"
1352
- puts "Available sizes (ppem): #{info.bitmap_ppem_sizes.join(', ')}"
1353
-
1354
- info.bitmap_strikes.each do |strike|
1355
- puts "Strike at #{strike.ppem}ppem:"
1356
- puts " - Glyphs: #{strike.num_glyphs}"
1357
- puts " - Color depth: #{strike.color_depth}"
1358
- end
1359
- end
1360
- ----
1361
-
1362
- === Color font table access
1363
-
1364
- Access color font tables directly:
1365
-
1366
- [source,ruby]
1367
- ----
1368
- font = Fontisan::FontLoader.load('emoji-font.ttf')
1369
-
1370
- # Access COLR table (layered color)
1371
- if font.has_table?('COLR')
1372
- colr = font.table('COLR')
1373
- puts "Color glyphs: #{colr.num_color_glyphs}"
1374
-
1375
- # Get color layers for a glyph
1376
- layers = colr.layers_for_glyph(42)
1377
- layers.each do |layer|
1378
- puts "Layer glyph: #{layer.glyph_id}, Palette index: #{layer.palette_index}"
1379
- end
1380
- end
1381
-
1382
- # Access CPAL table (color palettes)
1383
- if font.has_table?('CPAL')
1384
- cpal = font.table('CPAL')
1385
-
1386
- # Get colors from first palette
1387
- palette = cpal.palette(0)
1388
- palette.each_with_index do |color, i|
1389
- puts "Color #{i}: R=#{color.red} G=#{color.green} B=#{color.blue} A=#{color.alpha}"
1390
- end
1391
- end
1392
-
1393
- # Access SVG table
1394
- if font.has_table?('SVG ')
1395
- svg = font.table('SVG ')
1396
-
1397
- # Get SVG document for glyph 100
1398
- svg_doc = svg.svg_document_for_glyph(100)
1399
- puts "Compressed: #{svg_doc.compressed?}"
1400
- puts "SVG data: #{svg_doc.svg_data}"
1401
- end
1402
-
1403
- # Access bitmap tables
1404
- if font.has_table?('CBLC')
1405
- cblc = font.table('CBLC')
1406
- puts "Available ppem sizes: #{cblc.ppem_sizes.join(', ')}"
1407
-
1408
- # Check if glyph 50 has bitmap at 64ppem
1409
- if cblc.has_bitmap_for_glyph?(50, 64)
1410
- puts "Glyph 50 has bitmap at 64ppem"
1411
- end
1412
- end
1413
-
1414
- if font.has_table?('sbix')
1415
- sbix = font.table('sbix')
1416
-
1417
- # Get bitmap data for glyph 42 at 128ppem
1418
- glyph_data = sbix.glyph_data(42, 128)
1419
- if glyph_data
1420
- puts "Format: #{glyph_data[:graphic_type_name]}"
1421
- puts "Origin: (#{glyph_data[:origin_x]}, #{glyph_data[:origin_y]})"
1422
- puts "Data size: #{glyph_data[:data].length} bytes"
1423
- end
1424
- end
1425
- ----
1426
-
1427
- === Output formats
1428
-
1429
- Color font information can be serialized to multiple formats:
1430
-
1431
- [source,ruby]
1432
- ----
1433
- info = Fontisan.info('emoji-font.ttf')
1434
-
1435
- # YAML output
1436
- puts info.to_yaml
1437
-
1438
- # JSON output
1439
- puts info.to_json
1440
-
1441
- # XML output
1442
- puts info.to_xml
1443
- ----
1444
-
1445
- Example YAML output:
1446
-
1447
- [source,yaml]
1448
- ----
1449
- font_format: truetype
1450
- family_name: "Emoji Font"
1451
- is_color_font: true
1452
- color_glyphs: 872
1453
- color_palettes: 1
1454
- colors_per_palette: 256
1455
- has_svg_table: true
1456
- svg_glyph_count: 872
1457
- has_bitmap_glyphs: true
1458
- bitmap_ppem_sizes: [16, 32, 64, 128, 256]
1459
- bitmap_formats: ["PNG"]
1460
- bitmap_strikes:
1461
- - ppem: 128
1462
- start_glyph_id: 1
1463
- end_glyph_id: 872
1464
- bit_depth: 32
1465
- num_glyphs: 872
1466
- color_depth: "32-bit (full color with alpha)"
1467
- ----
1468
-
1469
-
1470
1792
  == Advanced features
1471
1793
 
1472
1794
  Fontisan provides capabilities:
@@ -1556,9 +1878,6 @@ The loading mode can be queried at any time.
1556
1878
 
1557
1879
  [source,ruby]
1558
1880
  ----
1559
- # Check laziness
1560
- font.lazy? # => true
1561
-
1562
1881
  # Mode stored as font property
1563
1882
  font.loading_mode # => :metadata or :full
1564
1883
 
@@ -1567,12 +1886,6 @@ font.table_available?(tag) # => boolean
1567
1886
 
1568
1887
  # Access restricted based on mode
1569
1888
  font.table(tag) # => Returns table or raises error
1570
-
1571
- # Test lazy loading with an expensive operation
1572
- glyphs = [] if font.subset_glyphs(lazy: true) { glyphs = font.subset_glyphs }
1573
- glyphs.count # => Tests whether glyphs were already loaded
1574
- font.table_available?("head") # => true (lazy loading enabled)
1575
- font.table_available?("GSUB") # => false (lazy loading enabled)
1576
1889
  ----
1577
1890
 
1578
1891
 
@@ -1606,7 +1919,7 @@ fields:
1606
1919
  `family_name`:: Font family name (nameID 1)
1607
1920
  `subfamily_name`:: Font subfamily/style name (nameID 2)
1608
1921
  `full_name`:: Full font name (nameID 4)
1609
- `postscript_name`:: PostScript name (nameID 6)
1922
+ `post_script_name`:: PostScript name (nameID 6)
1610
1923
  `preferred_family_name`:: Preferred family name (nameID 16, may be nil)
1611
1924
  `preferred_subfamily_name`:: Preferred subfamily name (nameID 17, may be nil)
1612
1925
  `units_per_em`:: Units per em from head table
@@ -1660,64 +1973,6 @@ font = Fontisan::FontLoader.load('font.ttf', mode: :full, lazy: false)
1660
1973
  ----
1661
1974
 
1662
1975
 
1663
- === Table preparedness
1664
-
1665
- Every table uses preparedness to avoid lazy initialization overhead. Function
1666
- `table_available?` was added to check if table prepared for access.
1667
-
1668
- [source,ruby]
1669
- ----
1670
- font = Fontisan::FontLoader.load('font.ttf')
1671
-
1672
- # Check preparedness
1673
- font.table_available?("head") # => true
1674
- font.table_available?("GSUB") # => true
1675
- font.table_available?("GPOS") # => true
1676
-
1677
- # Force loading of a table
1678
- head = font.table("head")
1679
- puts head.metrics.units_per_em # => Asks explicitly for metric value
1680
- puts head.metrics.weight_class # => Asks explicitly for metric value
1681
- print head.ty # => Prints force loaded table
1682
-
1683
- # Check preparedness after loading
1684
- font.table_available?("head") # => true in cache
1685
- font.table_available?("GSUB") # => true in cache
1686
- font.table_available?("GPOS") # => true in cache
1687
- ----
1688
-
1689
- A table not present in a font file is loaded lazily and `table_available?`
1690
- returns `false` after loading this table or after calling directly `table` for
1691
- the given tag:
1692
-
1693
- [source,ruby]
1694
- ----
1695
- font = Fontisan::FontLoader.load('font.ttf')
1696
-
1697
- # Check preparedness
1698
- font.standard_glyphs # => instantly loading glyphs (CFF and GDEF)
1699
- font.candlestick_and_widget_chart # => instantly loading glyphs (Colr)
1700
- font.txt_encoder # => instantly loading glyphs (OutlinedFont)
1701
- font.table_available?("post") # => true (cached)
1702
-
1703
- font.table_available?("OS/2") # => false (not loaded)
1704
- font.table("OS/2") # => instant loading tables (lazy loading)
1705
- font.table_available?("OS/2") # => true (cached)
1706
-
1707
- font.table_available?("VORG") # => false (not loaded)
1708
- font.table("VORG") # => instant loading tables (lazy loading)
1709
- # Raises Fontisan::Tables::VorgTableNotInFont: Not a valid sfnt font or sfnt table VORG not included in input font
1710
- font.table_available?("VORG") # => true (cached)
1711
-
1712
- font.table_available?("GLYC") # => nil
1713
- font.table("GLYC") # => instant loading tables (lazy loading)
1714
- # Raises Fontisan::TableNotFound: Table GLYC not found in font
1715
- font.table_available?("GLYC") # => nil (not cached)
1716
- ----
1717
-
1718
- NOTE: If you do not need to check whether the table is present before access
1719
- it is faster to access directly `table` method and catch error with validation
1720
- than first call table_available? for the table not present in the font file.
1721
1976
 
1722
1977
 
1723
1978
  == Outline format conversion
@@ -2376,7 +2631,7 @@ end
2376
2631
  ====
2377
2632
 
2378
2633
 
2379
- == Round-trip validation
2634
+ == Round-Trip validation
2380
2635
 
2381
2636
  === General
2382
2637
 
@@ -2449,7 +2704,7 @@ Loron.
2449
2704
 
2450
2705
  Support for layered import CFF color glyphs rasterizing on demand, with
2451
2706
  composite font support, a multi-layer color font represented by many
2452
- CFF fonts stacked on top of each other. ColorGlyph support contains
2707
+ CFF fonts stacked on top of each other. ColorGlyph support contains
2453
2708
  color glyphs, advanced color fonts glyphs and raster images (PNG or JPG)
2454
2709
  combined with TrueType outlines.
2455
2710