fontisan 0.1.0

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 (56) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.rubocop.yml +13 -0
  4. data/.rubocop_todo.yml +217 -0
  5. data/Gemfile +15 -0
  6. data/LICENSE +24 -0
  7. data/README.adoc +984 -0
  8. data/Rakefile +95 -0
  9. data/exe/fontisan +7 -0
  10. data/fontisan.gemspec +44 -0
  11. data/lib/fontisan/binary/base_record.rb +57 -0
  12. data/lib/fontisan/binary/structures.rb +84 -0
  13. data/lib/fontisan/cli.rb +192 -0
  14. data/lib/fontisan/commands/base_command.rb +82 -0
  15. data/lib/fontisan/commands/dump_table_command.rb +71 -0
  16. data/lib/fontisan/commands/features_command.rb +94 -0
  17. data/lib/fontisan/commands/glyphs_command.rb +50 -0
  18. data/lib/fontisan/commands/info_command.rb +120 -0
  19. data/lib/fontisan/commands/optical_size_command.rb +41 -0
  20. data/lib/fontisan/commands/scripts_command.rb +59 -0
  21. data/lib/fontisan/commands/tables_command.rb +52 -0
  22. data/lib/fontisan/commands/unicode_command.rb +76 -0
  23. data/lib/fontisan/commands/variable_command.rb +61 -0
  24. data/lib/fontisan/config/features.yml +143 -0
  25. data/lib/fontisan/config/scripts.yml +42 -0
  26. data/lib/fontisan/constants.rb +78 -0
  27. data/lib/fontisan/error.rb +15 -0
  28. data/lib/fontisan/font_loader.rb +109 -0
  29. data/lib/fontisan/formatters/text_formatter.rb +314 -0
  30. data/lib/fontisan/models/all_scripts_features_info.rb +21 -0
  31. data/lib/fontisan/models/features_info.rb +42 -0
  32. data/lib/fontisan/models/font_info.rb +99 -0
  33. data/lib/fontisan/models/glyph_info.rb +26 -0
  34. data/lib/fontisan/models/optical_size_info.rb +33 -0
  35. data/lib/fontisan/models/scripts_info.rb +39 -0
  36. data/lib/fontisan/models/table_info.rb +55 -0
  37. data/lib/fontisan/models/unicode_mappings.rb +42 -0
  38. data/lib/fontisan/models/variable_font_info.rb +82 -0
  39. data/lib/fontisan/open_type_collection.rb +97 -0
  40. data/lib/fontisan/open_type_font.rb +292 -0
  41. data/lib/fontisan/parsers/tag.rb +77 -0
  42. data/lib/fontisan/tables/cmap.rb +284 -0
  43. data/lib/fontisan/tables/fvar.rb +157 -0
  44. data/lib/fontisan/tables/gpos.rb +111 -0
  45. data/lib/fontisan/tables/gsub.rb +111 -0
  46. data/lib/fontisan/tables/head.rb +114 -0
  47. data/lib/fontisan/tables/layout_common.rb +73 -0
  48. data/lib/fontisan/tables/name.rb +188 -0
  49. data/lib/fontisan/tables/os2.rb +175 -0
  50. data/lib/fontisan/tables/post.rb +148 -0
  51. data/lib/fontisan/true_type_collection.rb +98 -0
  52. data/lib/fontisan/true_type_font.rb +313 -0
  53. data/lib/fontisan/utilities/checksum_calculator.rb +89 -0
  54. data/lib/fontisan/version.rb +5 -0
  55. data/lib/fontisan.rb +80 -0
  56. metadata +150 -0
data/README.adoc ADDED
@@ -0,0 +1,984 @@
1
+ = Fontisan
2
+
3
+ image:https://img.shields.io/gem/v/fontisan.svg[RubyGems Version, link=https://rubygems.org/gems/fontisan]
4
+ image:https://img.shields.io/github/license/fontist/fontisan.svg[License]
5
+ image:https://github.com/fontist/fontisan/actions/workflows/test.yml/badge.svg[Build Status, link=https://github.com/fontist/fontisan/actions/workflows/test.yml]
6
+
7
+ == Purpose
8
+
9
+ Fontisan is a Ruby gem providing font analysis tools and utilities for OpenType fonts. It is designed as a pure Ruby implementation with full object-oriented architecture, supporting extraction of information from OpenType fonts (OTF, TTF, TTC).
10
+
11
+ The gem provides both a Ruby library API and a command-line interface, with structured output formats (YAML, JSON, text) via lutaml-model. It achieves complete otfinfo parity, supporting all font analysis features needed for font inspection and validation.
12
+
13
+ == Installation
14
+
15
+ Add this line to your application's Gemfile:
16
+
17
+ [source,ruby]
18
+ ----
19
+ gem "fontisan"
20
+ ----
21
+
22
+ And then execute:
23
+
24
+ [source,shell]
25
+ ----
26
+ bundle install
27
+ ----
28
+
29
+ Or install it yourself as:
30
+
31
+ [source,shell]
32
+ ----
33
+ gem install fontisan
34
+ ----
35
+
36
+ == Features
37
+
38
+ * Extract comprehensive font metadata (name, version, designer, license, etc.)
39
+ * List OpenType tables with checksums and offsets
40
+ * Extract glyph names from post table
41
+ * Display Unicode codepoint to glyph index mappings
42
+ * Analyze variable font axes and named instances
43
+ * Display optical size information
44
+ * List supported scripts from GSUB/GPOS tables
45
+ * List OpenType features (ligatures, kerning, etc.) by script
46
+ * Dump raw binary table data for analysis
47
+ * Support for OTF, TTF, and TTC font formats
48
+ * Command-line interface with full otfinfo parity
49
+ * Ruby library API for programmatic access
50
+ * Structured output in YAML, JSON, and text formats
51
+
52
+ == Usage
53
+
54
+ === Command-line interface
55
+
56
+ ==== Font information
57
+
58
+ Extract comprehensive metadata from font files. This includes font names,
59
+ version information, designer credits, vendor details, licensing information,
60
+ and font metrics.
61
+
62
+ Syntax:
63
+
64
+ [source,shell]
65
+ ----
66
+ $ fontisan info FONT_FILE [--format FORMAT]
67
+ ----
68
+
69
+ Where,
70
+
71
+ `FONT_FILE`:: Path to the font file (OTF, TTF, or TTC)
72
+ `FORMAT`:: Output format: `text` (default), `json`, or `yaml`
73
+
74
+
75
+ .Font information for Libertinus Serif Regular
76
+ [example]
77
+ ====
78
+ [source,shell]
79
+ ----
80
+ $ fontisan info spec/fixtures/fonts/libertinus/ttf/LibertinusSerif-Regular.ttf
81
+
82
+ Font type: TrueType
83
+ Family: Libertinus Serif
84
+ Subfamily: Regular
85
+ Full name: Libertinus Serif Regular
86
+ PostScript name: LibertinusSerif-Regular
87
+ Version: Version 7.051;RELEASE
88
+ Unique ID: 5.000;QUE ;LibertinusSerif-Regular
89
+ Designer: Philipp H. Poll, Khaled Hosny
90
+ Manufacturer: Caleb Maclennan
91
+ Vendor URL: https://github.com/alerque/libertinus
92
+ Vendor ID: QUE
93
+ License Description: This Font Software is licensed under the SIL Open Font License, Version 1.1. This license is available with a FAQ at: https://openfontlicense.org
94
+ License URL: https://openfontlicense.org
95
+ Font revision: 7.05099
96
+ Permissions: Installable
97
+ Units per em: 1000
98
+ ----
99
+ ====
100
+
101
+
102
+ .Output in structured YAML format
103
+ [example]
104
+ ====
105
+ [source,shell]
106
+ ----
107
+ $ fontisan info spec/fixtures/fonts/libertinus/ttf/LibertinusSerif-Regular.ttf --format yaml
108
+ ----
109
+
110
+ [source,yaml]
111
+ ----
112
+ font_format: truetype
113
+ is_variable: false
114
+ family_name: Libertinus Serif
115
+ subfamily_name: Regular
116
+ full_name: Libertinus Serif Regular
117
+ postscript_name: LibertinusSerif-Regular
118
+ version: Version 7.051;RELEASE
119
+ unique_id: 5.000;QUE ;LibertinusSerif-Regular
120
+ designer: Philipp H. Poll, Khaled Hosny
121
+ manufacturer: Caleb Maclennan
122
+ vendor_url: https://github.com/alerque/libertinus
123
+ vendor_id: QUE
124
+ license_description: 'This Font Software is licensed under the SIL Open Font License,
125
+ Version 1.1. This license is available with a FAQ at: https://openfontlicense.org'
126
+ license_url: https://openfontlicense.org
127
+ font_revision: 7.050994873046875
128
+ permissions: Installable
129
+ units_per_em: 1000
130
+ ----
131
+ ====
132
+
133
+
134
+ ==== List OpenType tables
135
+
136
+ Display the font's table directory, showing all OpenType tables with their
137
+ sizes, offsets, and checksums. Useful for understanding font structure and
138
+ verifying table integrity.
139
+
140
+ Syntax:
141
+
142
+ [source,shell]
143
+ ----
144
+ $ fontisan tables FONT_FILE [--format FORMAT]
145
+ ----
146
+
147
+ Where,
148
+
149
+ `FONT_FILE`:: Path to the font file (OTF, TTF, or TTC)
150
+ `FORMAT`:: Output format: `text` (default), `json`, or `yaml`
151
+
152
+ .List of OpenType tables in Libertinus Serif Regular
153
+ [example]
154
+ ====
155
+ [source,shell]
156
+ ----
157
+ $ fontisan tables spec/fixtures/fonts/libertinus/ttf/LibertinusSerif-Regular.ttf
158
+ ----
159
+
160
+ [source,text]
161
+ ----
162
+ SFNT Version: TrueType (0x00010000)
163
+ Number of tables: 16
164
+
165
+ Tables:
166
+ GDEF 834 bytes (offset: 542156, checksum: 0x429C5C0C)
167
+ GPOS 17870 bytes (offset: 542992, checksum: 0x29CE4200)
168
+ OS/2 96 bytes (offset: 392, checksum: 0x4830F1C3)
169
+ cmap 3620 bytes (offset: 11412, checksum: 0x03AD3899)
170
+ cvt 248 bytes (offset: 18868, checksum: 0x3098127E)
171
+ fpgm 3596 bytes (offset: 15032, checksum: 0x622F0781)
172
+ gasp 8 bytes (offset: 542148, checksum: 0x00000010)
173
+ glyf 484900 bytes (offset: 30044, checksum: 0x0FF34594)
174
+ head 54 bytes (offset: 268, checksum: 0x18F5BDD0)
175
+ hhea 36 bytes (offset: 324, checksum: 0x191E2264)
176
+ hmtx 10924 bytes (offset: 488, checksum: 0x1F9D892B)
177
+ loca 10928 bytes (offset: 19116, checksum: 0x230B1A58)
178
+ maxp 32 bytes (offset: 360, checksum: 0x0EF919E7)
179
+ name 894 bytes (offset: 514944, checksum: 0x4E9173E6)
180
+ post 26308 bytes (offset: 515840, checksum: 0xE3D70231)
181
+ prep 239 bytes (offset: 18628, checksum: 0x8B4AB356)
182
+ ----
183
+ ====
184
+
185
+ .Output in structured YAML format
186
+ [example]
187
+ ====
188
+ [source,shell]
189
+ ----
190
+ $ fontisan tables spec/fixtures/fonts/libertinus/ttf/LibertinusSerif-Regular.ttf --format yaml
191
+ ----
192
+
193
+ [source,yaml]
194
+ ----
195
+ ---
196
+ sfnt_version: TrueType (0x00010000)
197
+ num_tables: 16
198
+ tables:
199
+ - tag: GDEF
200
+ length: 834
201
+ offset: 542156
202
+ checksum: 1117543436
203
+ - tag: GPOS
204
+ length: 17870
205
+ offset: 542992
206
+ checksum: 701383168
207
+ - tag: OS/2
208
+ length: 96
209
+ offset: 392
210
+ checksum: 1211167171
211
+ - tag: cmap
212
+ length: 3620
213
+ offset: 11412
214
+ checksum: 61683865
215
+ - tag: 'cvt '
216
+ length: 248
217
+ offset: 18868
218
+ checksum: 815272574
219
+ - tag: fpgm
220
+ length: 3596
221
+ offset: 15032
222
+ checksum: 1647249281
223
+ ----
224
+ ====
225
+
226
+ ==== List glyph names
227
+
228
+ Show all glyph names defined in the font's post table. Each glyph is listed with
229
+ its index and name, useful for understanding the font's character coverage.
230
+
231
+ Syntax:
232
+
233
+ [source,shell]
234
+ ----
235
+ $ fontisan glyphs FONT_FILE [--format FORMAT]
236
+ ----
237
+
238
+ Where,
239
+
240
+ `FONT_FILE`:: Path to the font file (OTF, TTF, or TTC)
241
+ `FORMAT`:: Output format: `text` (default), `json`, or `yaml`
242
+
243
+
244
+ .List of glyph names in Libertinus Serif Regular
245
+ [example]
246
+ ====
247
+ [source,shell]
248
+ ----
249
+ $ fontisan glyphs spec/fixtures/fonts/libertinus/ttf/LibertinusSerif-Regular.ttf
250
+ ----
251
+
252
+ [source,text]
253
+ ----
254
+ Glyph count: 2731
255
+ Source: post_2.0
256
+
257
+ Glyph names:
258
+ 0 .notdef
259
+ 1 space
260
+ 2 exclam
261
+ 3 quotedbl
262
+ 4 numbersign
263
+ 5 dollar
264
+ 6 percent
265
+ 7 ampersand
266
+ 8 quotesingle
267
+ 9 parenleft
268
+ 10 parenright
269
+ 11 asterisk
270
+ 12 plus
271
+ 13 comma
272
+ 14 hyphen
273
+ 15 period
274
+ 16 slash
275
+ 17 zero
276
+ 18 one
277
+ 19 two
278
+ 20 three
279
+ ...
280
+ ----
281
+ ====
282
+
283
+ ==== Show Unicode mappings
284
+
285
+ Display Unicode codepoint to glyph index mappings from the cmap table. Shows
286
+ which glyphs are assigned to which Unicode characters.
287
+
288
+ Syntax:
289
+
290
+ [source,shell]
291
+ ----
292
+ $ fontisan unicode FONT_FILE [--format FORMAT]
293
+ ----
294
+
295
+ Where,
296
+
297
+ `FONT_FILE`:: Path to the font file (OTF, TTF, or TTC)
298
+ `FORMAT`:: Output format: `text` (default), `json`, or `yaml`
299
+
300
+
301
+ .Unicode to glyph mappings in Libertinus Serif Regular
302
+ [example]
303
+ ====
304
+ [source,shell]
305
+ ----
306
+ $ fontisan unicode spec/fixtures/fonts/libertinus/ttf/LibertinusSerif-Regular.ttf
307
+ ----
308
+
309
+ [source,text]
310
+ ----
311
+ Unicode mappings: 2382
312
+
313
+ U+0020 glyph 1 space
314
+ U+0021 glyph 2 exclam
315
+ U+0022 glyph 3 quotedbl
316
+ U+0023 glyph 4 numbersign
317
+ U+0024 glyph 5 dollar
318
+ U+0025 glyph 6 percent
319
+ U+0026 glyph 7 ampersand
320
+ U+0027 glyph 8 quotesingle
321
+ U+0028 glyph 9 parenleft
322
+ U+0029 glyph 10 parenright
323
+ U+002A glyph 11 asterisk
324
+ U+002B glyph 12 plus
325
+ U+002C glyph 13 comma
326
+ U+002D glyph 14 hyphen
327
+ U+002E glyph 15 period
328
+ U+002F glyph 16 slash
329
+ U+0030 glyph 17 zero
330
+ U+0031 glyph 18 one
331
+ ...
332
+ ----
333
+ ====
334
+
335
+ ==== Variable font information
336
+
337
+ Display variation axes and named instances for variable fonts. Shows the design
338
+ space and predefined styles available in the font.
339
+
340
+ Syntax:
341
+
342
+ [source,shell]
343
+ ----
344
+ $ fontisan variable FONT_FILE [--format FORMAT]
345
+ ----
346
+
347
+ Where,
348
+
349
+ `FONT_FILE`:: Path to the variable font file
350
+ `FORMAT`:: Output format: `text` (default), `json`, or `yaml`
351
+
352
+
353
+ .Variable font axes and instances in Mona Sans
354
+ [example]
355
+ ====
356
+ [source,shell]
357
+ ----
358
+ $ fontisan variable spec/fixtures/fonts/MonaSans/variable/MonaSans[wdth,wght].ttf
359
+ ----
360
+
361
+ [source,text]
362
+ ----
363
+ Axis 0: wdth
364
+ Axis 0 name: Width
365
+ Axis 0 range: 75 125
366
+ Axis 0 default: 100
367
+ Axis 1: wght
368
+ Axis 1 name: Weight
369
+ Axis 1 range: 200 900
370
+ Axis 1 default: 400
371
+ Instance 0 name: Mona Sans Narrow Thin
372
+ Instance 0 position: 75 200
373
+ Instance 1 name: Mona Sans Narrow ExtraLight
374
+ Instance 1 position: 75 250
375
+ Instance 2 name: Mona Sans Narrow Light
376
+ Instance 2 position: 75 300
377
+ ...
378
+ ----
379
+ ====
380
+
381
+ ==== Optical size information
382
+
383
+ Display optical size range from the OS/2 table for fonts designed for specific
384
+ point sizes.
385
+
386
+ Syntax:
387
+
388
+ [source,shell]
389
+ ----
390
+ $ fontisan optical-size FONT_FILE [--format FORMAT]
391
+ ----
392
+
393
+ Where,
394
+
395
+ `FONT_FILE`:: Path to the font file with optical sizing
396
+ `FORMAT`:: Output format: `text` (default), `json`, or `yaml`
397
+
398
+
399
+ .Optical size information in Libertinus Serif Display
400
+ [example]
401
+ ====
402
+ [source,shell]
403
+ ----
404
+ $ fontisan optical-size spec/fixtures/fonts/libertinus/ttf/LibertinusSerifDisplay-Regular.ttf
405
+ ----
406
+
407
+ [source,text]
408
+ ----
409
+ Size range: [18, 72) pt (source: OS/2_usLowerOpticalPointSize)
410
+ ----
411
+ ====
412
+
413
+ ==== List supported scripts
414
+
415
+ Show all scripts (writing systems) supported by the font, extracted from GSUB
416
+ and GPOS tables. Useful for understanding language coverage.
417
+
418
+ Syntax:
419
+
420
+ [source,shell]
421
+ ----
422
+ $ fontisan scripts FONT_FILE [--format FORMAT]
423
+ ----
424
+
425
+ Where,
426
+
427
+ `FONT_FILE`:: Path to the font file (OTF, TTF, or TTC)
428
+ `FORMAT`:: Output format: `text` (default), `json`, or `yaml`
429
+
430
+
431
+ .Supported scripts in Libertinus Serif Regular
432
+ [example]
433
+ ====
434
+ [source,shell]
435
+ ----
436
+ $ fontisan scripts spec/fixtures/fonts/libertinus/ttf/LibertinusSerif-Regular.ttf
437
+ ----
438
+
439
+ [source,text]
440
+ ----
441
+ Script count: 5
442
+
443
+ DFLT Default
444
+ cyrl Cyrillic
445
+ grek Greek
446
+ hebr Hebrew
447
+ latn Latin
448
+ ----
449
+ ====
450
+
451
+ ==== List OpenType features
452
+
453
+ Show OpenType layout features (typography features like ligatures, kerning,
454
+ small capitals) available for specific scripts or all scripts.
455
+
456
+ Syntax:
457
+
458
+ [source,shell]
459
+ ----
460
+ $ fontisan features FONT_FILE [--script SCRIPT] [--format FORMAT]
461
+ ----
462
+
463
+ Where,
464
+
465
+ `FONT_FILE`:: Path to the font file (OTF, TTF, or TTC)
466
+ `SCRIPT`:: Optional 4-character script tag (e.g., `latn`, `cyrl`, `arab`). If not specified, shows features for all scripts
467
+ `FORMAT`:: Output format: `text` (default), `json`, or `yaml`
468
+
469
+
470
+ .OpenType features for Latin script
471
+ [example]
472
+ ====
473
+ [source,shell]
474
+ ----
475
+ $ fontisan features spec/fixtures/fonts/libertinus/ttf/LibertinusSerif-Regular.ttf --script latn
476
+ ----
477
+
478
+ [source,text]
479
+ ----
480
+ Script: latn
481
+ Feature count: 4
482
+
483
+ cpsp Capital Spacing
484
+ kern Kerning
485
+ mark Mark Positioning
486
+ mkmk Mark to Mark Positioning
487
+ ----
488
+ ====
489
+
490
+
491
+ .OpenType features for all scripts
492
+ [example]
493
+ ====
494
+ [source,shell]
495
+ ----
496
+ $ fontisan features spec/fixtures/fonts/libertinus/ttf/LibertinusSerif-Regular.ttf
497
+ ----
498
+
499
+ [source,text]
500
+ ----
501
+ Script: DFLT
502
+ Feature count: 4
503
+
504
+ cpsp Capital Spacing
505
+ kern Kerning
506
+ mark Mark Positioning
507
+ mkmk Mark to Mark Positioning
508
+
509
+ Script: cyrl
510
+ Feature count: 4
511
+
512
+ cpsp Capital Spacing
513
+ kern Kerning
514
+ mark Mark Positioning
515
+ mkmk Mark to Mark Positioning
516
+
517
+ Script: grek
518
+ Feature count: 4
519
+
520
+ cpsp Capital Spacing
521
+ kern Kerning
522
+ mark Mark Positioning
523
+ mkmk Mark to Mark Positioning
524
+
525
+ Script: hebr
526
+ Feature count: 2
527
+
528
+ mark Mark Positioning
529
+ mkmk Mark to Mark Positioning
530
+
531
+ Script: latn
532
+ Feature count: 4
533
+
534
+ cpsp Capital Spacing
535
+ kern Kerning
536
+ mark Mark Positioning
537
+ mkmk Mark to Mark Positioning
538
+ ----
539
+ ====
540
+
541
+ ==== Dump raw table data
542
+
543
+ Extract raw binary data from a specific OpenType table. Useful for detailed
544
+ analysis or debugging font issues.
545
+
546
+ Syntax:
547
+
548
+ [source,shell]
549
+ ----
550
+ $ fontisan dump-table FONT_FILE TABLE_TAG
551
+ ----
552
+
553
+ Where,
554
+
555
+ `FONT_FILE`:: Path to the font file (OTF, TTF, or TTC)
556
+ `TABLE_TAG`:: Four-character table tag (e.g., `name`, `head`, `GSUB`, `GPOS`)
557
+
558
+
559
+ .Dump raw table data to files
560
+ [example]
561
+ ====
562
+ [source,shell]
563
+ ----
564
+ $ fontisan dump-table spec/fixtures/fonts/libertinus/ttf/LibertinusSerif-Regular.ttf name > name_table.bin
565
+ $ fontisan dump-table spec/fixtures/fonts/libertinus/ttf/LibertinusSerif-Regular.ttf GPOS > gpos_table.bin
566
+ $ fontisan dump-table spec/fixtures/fonts/libertinus/ttf/LibertinusSerif-Regular.ttf head > head_table.bin
567
+ ----
568
+
569
+ The output is binary data written directly to stdout, which can be redirected to a file for further analysis.
570
+ ====
571
+
572
+ ==== General options
573
+
574
+ All commands support these options:
575
+
576
+ `--format FORMAT`:: Output format: `text` (default), `json`, or `yaml`
577
+
578
+ `--font-index INDEX`:: Font index for TTC files (default: 0)
579
+
580
+ `--verbose`:: Enable verbose output
581
+
582
+ `--quiet`:: Suppress non-error output
583
+
584
+ ==== Version information
585
+
586
+ Display the Fontisan version:
587
+
588
+ [source,shell]
589
+ ----
590
+ fontisan version
591
+ ----
592
+
593
+ === Ruby API
594
+
595
+ ==== General
596
+
597
+ Fontisan provides a comprehensive Ruby API for programmatic font analysis.
598
+
599
+ All functionality available via the CLI is accessible through the library.
600
+
601
+ ==== Loading fonts
602
+
603
+ Load TrueType and OpenType fonts:
604
+
605
+ .Loading a TrueType font
606
+ [example]
607
+ ====
608
+ [source,ruby]
609
+ ----
610
+ require "fontisan"
611
+
612
+ # Load a TrueType font (.ttf)
613
+ font = Fontisan::TrueTypeFont.from_file("path/to/font.ttf")
614
+
615
+ # Load an OpenType font (.otf with CFF outlines)
616
+ font = Fontisan::OpenTypeFont.from_file("path/to/font.otf")
617
+ ----
618
+ ====
619
+
620
+ .Loading fonts from TrueType Collections
621
+ [example]
622
+ ====
623
+ [source,ruby]
624
+ ----
625
+ # Load a specific font from a TTC file
626
+ ttc = Fontisan::TrueTypeCollection.from_file("path/to/fonts.ttc")
627
+ font = ttc.font_at_index(0) # Get first font
628
+
629
+ # Or use FontLoader to auto-detect format
630
+ font = Fontisan::FontLoader.load_file("path/to/any-font-file.ttf", font_index: 0)
631
+ ----
632
+ ====
633
+
634
+ ==== Accessing font tables
635
+
636
+ Access and parse OpenType tables:
637
+
638
+ .Working with the name table
639
+ [example]
640
+ ====
641
+ [source,ruby]
642
+ ----
643
+ name_table = font.table("name")
644
+
645
+ # Get standard name entries
646
+ family = name_table.english_name(Fontisan::Tables::Name::FAMILY)
647
+ subfamily = name_table.english_name(Fontisan::Tables::Name::SUBFAMILY)
648
+ full_name = name_table.english_name(Fontisan::Tables::Name::FULL_NAME)
649
+ postscript_name = name_table.english_name(Fontisan::Tables::Name::POSTSCRIPT)
650
+
651
+ # Get all available names
652
+ name_table.name_records.each do |record|
653
+ puts "#{record.name_id}: #{record.string}"
654
+ end
655
+ ----
656
+ ====
657
+
658
+ .Working with the head table
659
+ [example]
660
+ ====
661
+ [source,ruby]
662
+ ----
663
+ head_table = font.table("head")
664
+
665
+ # Get font revision
666
+ revision = head_table.font_revision # => 7.050994873046875
667
+
668
+ # Get units per em
669
+ units_per_em = head_table.units_per_em # => 1000
670
+
671
+ # Get created/modified timestamps
672
+ created = head_table.created
673
+ modified = head_table.modified
674
+ ----
675
+ ====
676
+
677
+ .Working with the OS/2 table
678
+ [example]
679
+ ====
680
+ [source,ruby]
681
+ ----
682
+ os2_table = font.table("OS/2")
683
+
684
+ # Get vendor ID
685
+ vendor_id = os2_table.ach_vend_id # => "QUE "
686
+
687
+ # Check optical size
688
+ if os2_table.version >= 5
689
+ lower_size = os2_table.us_lower_optical_point_size # => 18
690
+ upper_size = os2_table.us_upper_optical_point_size # => 72
691
+ end
692
+
693
+ # Get weight class
694
+ weight = os2_table.us_weight_class # => 400 (Regular)
695
+ ----
696
+ ====
697
+
698
+ .Working with the post table
699
+ [example]
700
+ ====
701
+ [source,ruby]
702
+ ----
703
+ post_table = font.table("post")
704
+
705
+ # Get all glyph names
706
+ glyph_names = post_table.glyph_names # => [".notdef", "space", "exclam", ...]
707
+
708
+ # Check post table version
709
+ version = post_table.version # => 2.0
710
+ ----
711
+ ====
712
+
713
+ ==== Working with cmap (Unicode mappings)
714
+
715
+ Access Unicode to glyph mappings:
716
+
717
+ .Getting Unicode mappings
718
+ [example]
719
+ ====
720
+ [source,ruby]
721
+ ----
722
+ cmap_table = font.table("cmap")
723
+
724
+ # Get all Unicode to glyph index mappings
725
+ mappings = cmap_table.unicode_mappings
726
+ # => { 0x0020 => 1, 0x0021 => 2, 0x0022 => 3, ... }
727
+
728
+ # Look up specific Unicode codepoint
729
+ glyph_index = mappings[0x0041] # => glyph index for 'A'
730
+
731
+ # Get subtables
732
+ subtables = cmap_table.subtables
733
+ subtables.each do |subtable|
734
+ puts "Platform #{subtable.platform_id}, Encoding #{subtable.encoding_id}"
735
+ end
736
+ ----
737
+ ====
738
+
739
+ ==== Working with GSUB/GPOS (scripts and features)
740
+
741
+ Extract OpenType layout information:
742
+
743
+ .Getting supported scripts
744
+ [example]
745
+ ====
746
+ [source,ruby]
747
+ ----
748
+ # Get scripts from GSUB table
749
+ gsub = font.table("GSUB")
750
+ scripts = gsub.scripts # => ["DFLT", "latn", "cyrl", "grek", "hebr"]
751
+
752
+ # Get scripts from GPOS table
753
+ gpos = font.table("GPOS")
754
+ scripts = gpos.scripts # => ["DFLT", "latn", "cyrl", "grek", "hebr"]
755
+
756
+ # Combine scripts from both tables
757
+ all_scripts = (gsub.scripts + gpos.scripts).uniq.sort
758
+ ----
759
+ ====
760
+
761
+ .Getting OpenType features
762
+ [example]
763
+ ====
764
+ [source,ruby]
765
+ ----
766
+ gsub = font.table("GSUB")
767
+
768
+ # Get features for a specific script
769
+ latin_features = gsub.features(script_tag: "latn")
770
+ # => ["cpsp", "kern", "mark", "mkmk"]
771
+
772
+ # Get features for all scripts
773
+ scripts = gsub.scripts
774
+ features_by_script = scripts.each_with_object({}) do |script, hash|
775
+ hash[script] = gsub.features(script_tag: script)
776
+ end
777
+ # => {"DFLT"=>["cpsp", "kern", ...], "latn"=>["cpsp", "kern", ...], ...}
778
+
779
+ # Combine GSUB and GPOS features
780
+ gpos = font.table("GPOS")
781
+ all_features = (gsub.features(script_tag: "latn") + gpos.features(script_tag: "latn")).uniq
782
+ ----
783
+ ====
784
+
785
+ ==== Working with variable fonts
786
+
787
+ Access variation axes and instances:
788
+
789
+ .Analyzing variable fonts
790
+ [example]
791
+ ====
792
+ [source,ruby]
793
+ ----
794
+ fvar_table = font.table("fvar")
795
+
796
+ # Check if font is variable
797
+ is_variable = !fvar_table.nil?
798
+
799
+ # Get variation axes
800
+ axes = fvar_table.axes
801
+ axes.each do |axis|
802
+ puts "Axis: #{axis.axis_tag}"
803
+ puts " Name: #{axis.axis_name_id}"
804
+ puts " Range: #{axis.min_value} to #{axis.max_value}"
805
+ puts " Default: #{axis.default_value}"
806
+ end
807
+
808
+ # Get named instances
809
+ instances = fvar_table.instances
810
+ instances.each do |instance|
811
+ puts "Instance: #{instance.subfamily_name_id}"
812
+ puts " Coordinates: #{instance.coordinates.inspect}"
813
+ end
814
+ ----
815
+ ====
816
+
817
+ ==== Font inspection utilities
818
+
819
+ Check table presence and extract basic info:
820
+
821
+ .Font inspection
822
+ [example]
823
+ ====
824
+ [source,ruby]
825
+ ----
826
+ # Ch eck if font has specific tables
827
+ has_gsub = font.has_table?("GSUB") # => true
828
+ has_gpos = font.has_table?("GPOS") # => true
829
+ has_fvar = font.has_table?("fvar") # => false (not a variable font)
830
+
831
+ # Get list of all table tags
832
+ table_names = font.table_names
833
+ # => ["GDEF", "GPOS", "OS/2", "cmap", "cvt ", ...]
834
+
835
+ # Get font format
836
+ font_format = font.header.sfnt_version == 0x00010000 ? "TrueType" : "OpenType"
837
+
838
+ # Get number of glyphs
839
+ post = font.table("post")
840
+ glyph_count = post.glyph_names.length # => 2731
841
+ ----
842
+ ====
843
+
844
+ ==== Using commands programmatically
845
+
846
+ Use command classes for structured output:
847
+
848
+ .Getting structured font information
849
+ [example]
850
+ ====
851
+ [source,ruby]
852
+ ----
853
+ # Use InfoCommand to get structured info
854
+ cmd = Fontisan::Commands::InfoCommand.new("font.ttf", {})
855
+ info = cmd.run # Returns Fontisan::Models::FontInfo
856
+
857
+ # Access structured data
858
+ puts info.family_name # => "Libertinus Serif"
859
+ puts info.designer # => "Philipp H. Poll, Khaled Hosny"
860
+ puts info.font_format # => "truetype"
861
+
862
+ # Serialize to formats
863
+ json_output = info.to_json
864
+ yaml_output = info.to_yaml
865
+ ----
866
+ ====
867
+
868
+ .Getting scripts and features programmatically
869
+ [example]
870
+ ====
871
+ [source,ruby]
872
+ ----
873
+ # Get scripts
874
+ scripts_cmd = Fontisan::Commands::ScriptsCommand.new("font.ttf", {})
875
+ scripts_info = scripts_cmd.run # Returns Fontisan::Models::ScriptsInfo
876
+
877
+ scripts_info.scripts.each do |script|
878
+ puts "#{script.tag}: #{script.description}"
879
+ end
880
+
881
+ # Get features for a script
882
+ features_cmd = Fontisan::Commands::FeaturesCommand.new(
883
+ "font.ttf",
884
+ { script: "latn" }
885
+ )
886
+ features_info = features_cmd.run # Returns Fontisan::Models::FeaturesInfo
887
+
888
+ features_info.features.each do |feature|
889
+ puts "#{feature.tag}: #{feature.description}"
890
+ end
891
+ ----
892
+ ====
893
+
894
+ == Development
895
+
896
+ After checking out the repo, run `bundle install` to install dependencies.
897
+
898
+ === Running tests
899
+
900
+ [source,shell]
901
+ ----
902
+ bundle exec rake spec
903
+ ----
904
+
905
+ === Code style
906
+
907
+ Check code style with RuboCop:
908
+
909
+ [source,shell]
910
+ ----
911
+ bundle exec rake rubocop
912
+ ----
913
+
914
+ === Test fixtures
915
+
916
+ The test suite uses real font files for testing.
917
+
918
+ Rake tasks are provided to download fonts from GitHub releases for testing.
919
+
920
+ ==== Download test fixtures
921
+
922
+ Download font fixtures automatically (only downloads if files don't already
923
+ exist):
924
+
925
+ [source,shell]
926
+ ----
927
+ bundle exec rake fixtures:download
928
+ ----
929
+
930
+ This downloads four font collections:
931
+
932
+ * **Libertinus 7.051** - Serif, Sans, and Mono families with extensive OpenType
933
+ features (included in repository)
934
+
935
+ * **Mona Sans v2.0** - Variable TTF with width and weight axes for testing
936
+ variable fonts (downloaded via Rake, not in repository)
937
+
938
+ * **Noto Serif CJK 2.003 (Static)** - Large CJK TTC for testing static font
939
+ collections (downloaded via Rake, not in repository)
940
+
941
+ * **Noto Serif CJK 2.003 (Variable)** - Variable OTF/OTC for testing variable
942
+ OpenType collections (downloaded via Rake, not in repository)
943
+
944
+ The Rake task uses file dependencies, so running it multiple times won't
945
+ re-download existing files. This makes it safe and efficient to run repeatedly
946
+ during development.
947
+
948
+ NOTE: Noto CJK and Mona Sans fonts are excluded from the repository (see
949
+ `.gitignore`) due to their size. They are automatically downloaded when running
950
+ `rake fixtures:download`.
951
+
952
+ ==== Clean test fixtures
953
+
954
+ Remove all downloaded fixture files:
955
+
956
+ [source,shell]
957
+ ----
958
+ bundle exec rake fixtures:clean
959
+ ----
960
+
961
+ ==== Built-in fixtures
962
+
963
+ The repository includes pre-installed Libertinus fixtures in
964
+ `spec/fixtures/fonts/libertinus/` which are sufficient for basic testing.
965
+
966
+ Large font collections (Noto CJK, Mona Sans) are **not committed** to the
967
+ repository due to their size. Use `rake fixtures:download` to obtain them for
968
+ comprehensive testing of:
969
+
970
+ * Variable fonts (MonaSans variable TTF)
971
+ * Large static font collections (NotoSerifCJK TTC)
972
+ * Variable OpenType collections (NotoSerifCJK-VF OTC)
973
+
974
+ == Contributing
975
+
976
+ Bug reports and pull requests are welcome on GitHub at https://github.com/fontist/fontisan.
977
+
978
+ == License
979
+
980
+ The gem is available as open source under the terms of the BSD-2-Clause license.
981
+
982
+ == Copyright
983
+
984
+ Copyright https://www.ribose.com[Ribose].