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
data/docs/package.json
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"scripts": {
|
|
3
|
+
"dev": "vitepress dev",
|
|
4
|
+
"build": "vitepress build",
|
|
5
|
+
"preview": "vitepress preview",
|
|
6
|
+
"format": "prettier -w ."
|
|
7
|
+
},
|
|
8
|
+
"type": "module",
|
|
9
|
+
"devDependencies": {
|
|
10
|
+
"@types/node": "^25.4.0",
|
|
11
|
+
"prettier": "^3.8.1",
|
|
12
|
+
"typescript": "^5.9.3",
|
|
13
|
+
"vitepress": "^1.6.4"
|
|
14
|
+
}
|
|
15
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" id="uuid-c6d7bb0b-ce20-4c4f-b0df-e25e79a561a7" viewBox="0 0 500 500" width="500" height="500"><path d="M64.43,140.29h67.44v13.2h-48.96v180h48.96v13.2h-67.44v-206.4Z" style="fill:#4d4b54;"></path><path d="M352.67,333.5h48.96v-180h-48.96v-13.2h67.44v206.4h-67.44v-13.2Z" style="fill:#4d4b54;"></path><path d="M237.77,169.8c4.32-20.16,8.64-39.6,16.92-54.36,9.36-16.92,24.12-33.48,55.08-33.48,21.96,0,34.2,10.8,34.2,26.28,0,10.44-6.84,15.84-14.4,15.84-9.72,0-13.32-6.48-14.4-14.04-1.44-9-2.16-17.64-10.8-17.64-18.36,0-27.36,21.24-32.76,51.84l-4.32,25.56h34.2l-2.16,14.76h-33.84l-20.52,122.76c-5.04,30.96-21.6,111.6-70.92,111.6-23.04,0-32.04-13.32-32.04-25.92,0-10.08,5.04-17.64,14.4-17.64,21.6,0,9.72,32.04,23.4,32.04,19.08,0,28.44-59.04,32.4-82.8l23.4-140.04h-30.24l1.44-14.76h30.96Z" style="fill:#bf4e6a;"></path></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?><svg id="uuid-5b0c2658-028c-4702-accc-5ed4e2e91676" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2100.48 500"><path d="M257.61,451.33c-14.44,6.96-31.78,5.55-41.96-7.84L67.48,248.75c-5.62-7.38-6.35-18.76-.56-25.73l75.41-90.8c3.17-3.82,7.58-5.34,12.06-7.47l160.97-76.62c14.33-6.82,30.68-3.53,42.04,7.07l105.12,142.11c2.69,5.58,5.13,10.27,8.53,15.28l55.82,82.24c5.37,7.91,6.05,23.69-4.06,28.56l-265.21,127.93ZM287.03,310.96l161.6-76.96c11.16-5.32,21.54-22.67,13.21-34.01l-105.49-143.66c-11.5-10.31-27.05-13.14-41.14-6.4l-166.89,79.87c-13.23,6.33-14.59,25.94-6.48,36.81l97.77,131.09c11.25,15.09,29.74,21.66,47.42,13.24ZM232.38,452.15c6.57,2.92,14.18,2.5,21.22-.89l267.88-128.95c8.75-4.21,9.43-18.42,4.56-25.6l-59.66-88.07c-1.3,13.05-7.4,22.31-18.52,27.6l-157.65,75.1c-9.63,4.59-18.53,5.83-29.47,4.16-6.26-3.25-13.52-5.43-18.2-11.67l-100.41-133.93c-6.12-8.16-7.99-15.97-6.35-27.06l-67.77,81.52c-5.01,6.03-4.38,16.57.54,23.04l148.59,195.3c3.88,5.09,9.36,7.96,15.25,9.45Z" style="fill:#676565;"/><path d="M287.03,310.96c-17.68,8.42-36.17,1.85-47.42-13.24l-97.77-131.09c-8.11-10.88-6.75-30.48,6.48-36.81l166.89-79.87c14.09-6.74,29.64-3.91,41.14,6.4l105.49,143.66c8.33,11.34-2.05,28.69-13.21,34.01l-161.6,76.96Z" style="fill:#e1dfd2;"/><path d="M232.38,452.15c1.96-4.82,3.23-9.57,4.66-15.14l27.96-108.44c1.32-5.12-3.24-8.92-4.26-13.08,10.94,1.67,19.84.42,29.47-4.16l157.65-75.1c11.12-5.3,17.22-14.55,18.52-27.6l59.66,88.07c4.87,7.19,4.2,21.39-4.56,25.6l-267.88,128.95c-7.05,3.39-14.65,3.81-21.22.89Z" style="fill:#bebbac;"/><path d="M260.74,315.5c1.02,4.16,5.58,7.95,4.26,13.08l-27.96,108.44c-1.44,5.57-2.71,10.31-4.66,15.14-5.89-1.49-11.37-4.36-15.25-9.45L68.54,247.4c-4.92-6.47-5.55-17.01-.54-23.04l67.77-81.52c-1.64,11.09.23,18.9,6.35,27.06l100.41,133.93c4.68,6.24,11.94,8.42,18.2,11.67Z" style="fill:#dddac8;"/><polygon points="282.54 238.11 289.49 249.09 263.7 260.65 194.99 159.94 222.35 148.43 228.68 158.31 214.22 164.38 269.97 243.75 282.54 238.11" style="fill:#4d4b54;"/><polygon points="369.09 198.8 383.44 192.08 329.33 114.13 315.75 120.26 309.88 111.47 336 98.94 403.17 194.97 375.96 207.94 369.09 198.8" style="fill:#4d4b54;"/><path d="M292.11,160.41c9.03,15.98,17.59,31.55,25.28,48.2,7.43,16.09,16.44,39,4.36,54.53-5.6,7.2-13.93,10.74-22.32,9.15-3.42-.65-5.8-2.78-5.93-5.92-.12-2.78,1.59-5.75,4.93-6.61,2.7-.69,6.2-.29,8.92.64,5.17,1.76,9.75-.71,11.18-6.18,1.14-4.4.26-9.46-1.57-13.97-4.76-11.73-10.73-22.33-17-33.4l-21.8-38.5c-.25-.44-6.36-11.42-6.36-11.42-2.87-6.21-16.16-25.52-5.57-44.8,5.23-9.53,15.89-15.13,26.35-12.59,3.15.76,5.82,3.09,6.27,5.63.57,3.22-1.12,6.43-4.3,7.81-8,3.48-12.19-4.65-17.66-2.08-7.12,3.35-3.91,13.49-1.03,19.02l10.48,20.15c2.29,4.41,1.97,3.58,5.79,10.33Z" style="fill:#bf4e6a;"/><polygon points="266.05 179.81 260.64 171.75 310.91 148.47 315.92 155.96 266.05 179.81" style="fill:#bf4e6a;"/><path d="M703.28,220.77v144.67h-27.95v-144.67h-31.82v-24.08h31.99v-20.92c0-38.32,24.43-61.35,63.11-61.35,15.12,0,24.79,4.22,27.77,5.45l-3.34,22.68c-4.75-2.11-13.54-4.22-23.2-4.22-21.45,0-36.91,10.55-36.91,39.38v18.98h52.38v24.08h-52.03Z" style="fill:#bf4e6a;"/><path d="M863.6,193.17c51.33,0,89.65,38.5,89.65,87.89s-38.32,87.89-89.65,87.89-89.65-38.5-89.65-87.89,38.32-87.89,89.65-87.89ZM863.6,342.94c35.51,0,61.7-27.07,61.7-61.88s-26.19-61.88-61.7-61.88-61.7,27.07-61.7,61.88,26.19,61.88,61.7,61.88Z" style="fill:#bf4e6a;"/><path d="M1154.16,262.78v102.66h-27.77v-95.8c0-32.87-17.23-50.1-47.81-50.1-28.83,0-52.21,19.86-52.21,50.62v95.27h-27.95v-168.75h28.12v25.31c9.49-15.64,29.53-28.83,56.43-28.83,44.47,0,71.19,26.19,71.19,69.61Z" style="fill:#bf4e6a;"/><path d="M1246.27,220.77v91.23c0,22.15,11.95,31.82,29.18,31.82,9.14,0,20.74-1.76,28.83-4.75l3.69,24.08c-7.21,3.16-21.8,5.8-35.51,5.8-32.52,0-54.14-17.93-54.14-52.38v-95.8h-31.11v-24.08h31.29v-54.14h27.6v54.14h53.96v24.08h-53.79Z" style="fill:#bf4e6a;"/><path d="M1339.26,140.09c0-10.2,7.03-17.23,17.23-17.23s17.58,7.03,17.58,17.23-7.38,17.4-17.58,17.4-17.23-7.21-17.23-17.4ZM1342.6,196.69h27.95v168.75h-27.95v-168.75Z" style="fill:#4d4b54;"/><path d="M1496.76,270.34c33.57,6.68,51.33,21.8,51.33,48.16,0,32.87-26.19,50.45-67.15,50.45-23.91,0-47.46-4.75-63.28-12.66l3.87-24.96c15.47,7.91,37.09,12.66,57.48,12.66,27.07,0,41.66-8.44,41.66-24.08s-13.01-21.45-36.74-26.02l-21.97-4.39c-27.95-5.45-45.88-20.21-45.88-46.23,0-30.06,26.54-50.1,68.55-50.1,20.39,0,40.96,3.87,54.14,9.32l-3.52,24.43c-13.71-5.45-32.34-8.96-48.87-8.96-27.42,0-42.54,9.14-42.54,24.61,0,14.59,11.6,19.69,35.33,24.26l17.58,3.52Z" style="fill:#4d4b54;"/><path d="M1757.09,365.44h-27.95v-27.77c-12.66,18.11-34.8,31.29-65.04,31.29-48.34,0-85.08-37.62-85.08-88.42s36.74-87.36,85.08-87.36c30.23,0,52.38,13.01,65.04,31.11v-27.6h27.95v168.75ZM1606.8,280.54c0,34.98,24.96,63.11,60.12,63.11s62.58-28.12,62.58-63.11-26.54-62.05-62.58-62.05-60.12,27.25-60.12,62.05Z" style="fill:#4d4b54;"/><path d="M1971.19,262.78v102.66h-27.77v-95.8c0-32.87-17.23-50.1-47.81-50.1-28.83,0-52.21,19.86-52.21,50.62v95.27h-27.95v-168.75h28.12v25.31c9.49-15.64,29.53-28.83,56.43-28.83,44.47,0,71.19,26.19,71.19,69.61Z" style="fill:#4d4b54;"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?><svg id="uuid-bbbd5b2f-b286-4c12-becd-414fca1ebde9" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500"><path d="M210.8,451.33c-14.44,6.96-31.78,5.55-41.96-7.84L20.67,248.75c-5.62-7.38-6.35-18.76-.56-25.73l75.41-90.8c3.17-3.82,7.58-5.34,12.06-7.47l160.97-76.62c14.33-6.82,30.68-3.53,42.04,7.07l105.12,142.11c2.69,5.58,5.13,10.27,8.53,15.28l55.82,82.24c5.37,7.91,6.05,23.69-4.06,28.56l-265.21,127.93ZM240.21,310.96l161.6-76.96c11.16-5.32,21.54-22.67,13.21-34.01l-105.49-143.66c-11.5-10.31-27.05-13.14-41.14-6.4l-166.89,79.87c-13.23,6.33-14.59,25.94-6.48,36.81l97.77,131.09c11.25,15.09,29.74,21.66,47.42,13.24ZM185.57,452.15c6.57,2.92,14.18,2.5,21.22-.89l267.88-128.95c8.75-4.21,9.43-18.42,4.56-25.6l-59.66-88.07c-1.3,13.05-7.4,22.31-18.52,27.6l-157.65,75.1c-9.63,4.59-18.53,5.83-29.47,4.16-6.26-3.25-13.52-5.43-18.2-11.67l-100.41-133.93c-6.12-8.16-7.99-15.97-6.35-27.06L21.19,224.36c-5.01,6.03-4.38,16.57.54,23.04l148.59,195.3c3.88,5.09,9.36,7.96,15.25,9.45Z" style="fill:#676565;"/><path d="M240.21,310.96c-17.68,8.42-36.17,1.85-47.42-13.24l-97.77-131.09c-8.11-10.88-6.75-30.48,6.48-36.81l166.89-79.87c14.09-6.74,29.64-3.91,41.14,6.4l105.49,143.66c8.33,11.34-2.05,28.69-13.21,34.01l-161.6,76.96Z" style="fill:#e1dfd2;"/><path d="M185.57,452.15c1.96-4.82,3.23-9.57,4.66-15.14l27.96-108.44c1.32-5.12-3.24-8.92-4.26-13.08,10.94,1.67,19.84.42,29.47-4.16l157.65-75.1c11.12-5.3,17.22-14.55,18.52-27.6l59.66,88.07c4.87,7.19,4.2,21.39-4.56,25.6l-267.88,128.95c-7.05,3.39-14.65,3.81-21.22.89Z" style="fill:#bebbac;"/><path d="M213.93,315.5c1.02,4.16,5.58,7.95,4.26,13.08l-27.96,108.44c-1.44,5.57-2.71,10.31-4.66,15.14-5.89-1.49-11.37-4.36-15.25-9.45L21.73,247.4c-4.92-6.47-5.55-17.01-.54-23.04l67.77-81.52c-1.64,11.09.23,18.9,6.35,27.06l100.41,133.93c4.68,6.24,11.94,8.42,18.2,11.67Z" style="fill:#dddac8;"/><polygon points="235.73 238.11 242.68 249.09 216.89 260.65 148.18 159.94 175.53 148.43 181.86 158.31 167.41 164.38 223.16 243.75 235.73 238.11" style="fill:#4d4b54;"/><polygon points="322.28 198.8 336.63 192.08 282.52 114.13 268.93 120.26 263.07 111.47 289.19 98.94 356.36 194.97 329.15 207.94 322.28 198.8" style="fill:#4d4b54;"/><path d="M245.3,160.41c9.03,15.98,17.59,31.55,25.28,48.2,7.43,16.09,16.44,39,4.36,54.53-5.6,7.2-13.93,10.74-22.32,9.15-3.42-.65-5.8-2.78-5.93-5.92-.12-2.78,1.59-5.75,4.93-6.61,2.7-.69,6.2-.29,8.92.64,5.17,1.76,9.75-.71,11.18-6.18,1.14-4.4.26-9.46-1.57-13.97-4.76-11.73-10.73-22.33-17-33.4l-21.8-38.5c-.25-.44-6.36-11.42-6.36-11.42-2.87-6.21-16.16-25.52-5.57-44.8,5.23-9.53,15.89-15.13,26.35-12.59,3.15.76,5.82,3.09,6.27,5.63.57,3.22-1.12,6.43-4.3,7.81-8,3.48-12.19-4.65-17.66-2.08-7.12,3.35-3.91,13.49-1.03,19.02l10.48,20.15c2.29,4.41,1.97,3.58,5.79,10.33Z" style="fill:#bf4e6a;"/><polygon points="219.23 179.81 213.82 171.75 264.09 148.47 269.11 155.96 219.23 179.81" style="fill:#bf4e6a;"/></svg>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "MyWebSite",
|
|
3
|
+
"short_name": "MySite",
|
|
4
|
+
"icons": [
|
|
5
|
+
{
|
|
6
|
+
"src": "/web-app-manifest-192x192.png",
|
|
7
|
+
"sizes": "192x192",
|
|
8
|
+
"type": "image/png",
|
|
9
|
+
"purpose": "maskable"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"src": "/web-app-manifest-512x512.png",
|
|
13
|
+
"sizes": "512x512",
|
|
14
|
+
"type": "image/png",
|
|
15
|
+
"purpose": "maskable"
|
|
16
|
+
}
|
|
17
|
+
],
|
|
18
|
+
"theme_color": "#ffffff",
|
|
19
|
+
"background_color": "#ffffff",
|
|
20
|
+
"display": "standalone"
|
|
21
|
+
}
|
|
Binary file
|
|
Binary file
|
data/fontisan.gemspec
CHANGED
|
@@ -41,7 +41,7 @@ Gem::Specification.new do |spec|
|
|
|
41
41
|
spec.add_dependency "base64"
|
|
42
42
|
spec.add_dependency "bindata", "~> 2.5"
|
|
43
43
|
spec.add_dependency "brotli", "~> 0.5"
|
|
44
|
-
spec.add_dependency "lutaml-model", "~> 0.
|
|
44
|
+
spec.add_dependency "lutaml-model", "~> 0.8"
|
|
45
45
|
spec.add_dependency "nokogiri", "~> 1.16"
|
|
46
46
|
spec.add_dependency "thor", "~> 1.3"
|
|
47
47
|
end
|
|
@@ -161,10 +161,10 @@ module Fontisan
|
|
|
161
161
|
|
|
162
162
|
# Check if variable font (Type1 fonts are never variable)
|
|
163
163
|
info.is_variable = if font.is_a?(Type1Font)
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
164
|
+
false
|
|
165
|
+
else
|
|
166
|
+
font.has_table?(Constants::FVAR_TAG)
|
|
167
|
+
end
|
|
168
168
|
end
|
|
169
169
|
|
|
170
170
|
# Populate essential fields for brief mode (metadata tables only).
|
|
@@ -273,7 +273,7 @@ module Fontisan
|
|
|
273
273
|
info.version = font_info.version
|
|
274
274
|
info.copyright = font_info.copyright
|
|
275
275
|
info.description = font_info.notice
|
|
276
|
-
info.designer = nil
|
|
276
|
+
info.designer = nil # Type 1 fonts may not have designer info
|
|
277
277
|
|
|
278
278
|
# Metrics
|
|
279
279
|
if font_dict&.font_b_box
|
|
@@ -351,7 +351,8 @@ _options)
|
|
|
351
351
|
is_type1 = font.is_a?(Type1Font)
|
|
352
352
|
|
|
353
353
|
unless is_type1 || font.respond_to?(:table)
|
|
354
|
-
raise ArgumentError,
|
|
354
|
+
raise ArgumentError,
|
|
355
|
+
"Font must respond to :table method or be a Type1Font"
|
|
355
356
|
end
|
|
356
357
|
|
|
357
358
|
unless target_format.is_a?(Symbol)
|
|
@@ -327,7 +327,10 @@ module Fontisan
|
|
|
327
327
|
|
|
328
328
|
# Get CharStrings INDEX from CFF
|
|
329
329
|
charstrings_index = cff_table.charstrings_index(0)
|
|
330
|
-
|
|
330
|
+
unless charstrings_index
|
|
331
|
+
raise Fontisan::Error,
|
|
332
|
+
"CharStrings INDEX not found"
|
|
333
|
+
end
|
|
331
334
|
|
|
332
335
|
# Get Private DICT for context
|
|
333
336
|
private_dict = cff_table.private_dict(0)
|
|
@@ -335,7 +338,7 @@ module Fontisan
|
|
|
335
338
|
# Create CFF to Type 1 converter
|
|
336
339
|
converter = Type1::CffToType1Converter.new(
|
|
337
340
|
nominal_width: private_dict&.nominal_width || 0,
|
|
338
|
-
default_width: private_dict&.default_width || 0
|
|
341
|
+
default_width: private_dict&.default_width || 0,
|
|
339
342
|
)
|
|
340
343
|
|
|
341
344
|
# Convert each CFF CharString to Type 1 format
|
|
@@ -354,7 +357,7 @@ module Fontisan
|
|
|
354
357
|
private_dict_hash = build_private_dict_hash(private_dict)
|
|
355
358
|
type1_charstrings[glyph_name] = converter.convert(
|
|
356
359
|
cff_charstring,
|
|
357
|
-
private_dict: private_dict_hash
|
|
360
|
+
private_dict: private_dict_hash,
|
|
358
361
|
)
|
|
359
362
|
end
|
|
360
363
|
|
|
@@ -551,7 +554,7 @@ module Fontisan
|
|
|
551
554
|
# Parse version (e.g., "001.000" => 1.0)
|
|
552
555
|
version_parts = version_str.split(".")
|
|
553
556
|
major = version_parts[0].to_i
|
|
554
|
-
minor = version_parts[1]
|
|
557
|
+
minor = version_parts[1].to_i
|
|
555
558
|
version = major + (minor / 1000.0)
|
|
556
559
|
|
|
557
560
|
# Version (Fixed 16.16) - stored as int32
|
|
@@ -626,24 +629,24 @@ module Fontisan
|
|
|
626
629
|
|
|
627
630
|
# Ascent (int16) - Distance from baseline to highest ascender
|
|
628
631
|
# Use BlueValues[2] or [3] if available, otherwise font_bbox[3]
|
|
629
|
-
if blue_values.length >= 4
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
632
|
+
ascent = if blue_values.length >= 4
|
|
633
|
+
blue_values[3] # Top zone top
|
|
634
|
+
elsif blue_values.length >= 3
|
|
635
|
+
blue_values[2] # Top zone bottom
|
|
636
|
+
else
|
|
637
|
+
font_bbox[3] # y_max
|
|
638
|
+
end
|
|
636
639
|
data << [ascent].pack("s>")
|
|
637
640
|
|
|
638
641
|
# Descent (int16) - Distance from baseline to lowest descender (negative)
|
|
639
642
|
# Use BlueValues[0] or [1] if available, otherwise font_bbox[1]
|
|
640
|
-
if blue_values.length >= 2
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
643
|
+
descent = if blue_values.length >= 2
|
|
644
|
+
blue_values[0] # Bottom zone bottom (negative)
|
|
645
|
+
elsif blue_values.length >= 1
|
|
646
|
+
blue_values[0]
|
|
647
|
+
else
|
|
648
|
+
font_bbox[1] # y_min (should be negative)
|
|
649
|
+
end
|
|
647
650
|
data << [descent].pack("s>")
|
|
648
651
|
|
|
649
652
|
# Line Gap (int16) - Additional space between lines
|
|
@@ -728,33 +731,33 @@ module Fontisan
|
|
|
728
731
|
|
|
729
732
|
# Extract font names with fallbacks
|
|
730
733
|
font_name = font.font_name || font_dict&.font_name || "Unnamed"
|
|
731
|
-
family_name = if font_info
|
|
734
|
+
family_name = if font_info.respond_to?(:family_name)
|
|
732
735
|
font_info.family_name || font_dict&.family_name || font_name
|
|
733
736
|
else
|
|
734
737
|
font_dict&.family_name || font_name
|
|
735
738
|
end
|
|
736
|
-
full_name = if font_info
|
|
739
|
+
full_name = if font_info.respond_to?(:full_name)
|
|
737
740
|
font_info.full_name || font_dict&.full_name || family_name
|
|
738
741
|
else
|
|
739
742
|
font_dict&.full_name || family_name
|
|
740
743
|
end
|
|
741
|
-
version = if font_info
|
|
744
|
+
version = if font_info.respond_to?(:version)
|
|
742
745
|
font_info.version || font.version || "001.000"
|
|
743
746
|
else
|
|
744
747
|
font.version || "001.000"
|
|
745
748
|
end
|
|
746
|
-
copyright = if font_info
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
749
|
+
copyright = if font_info.respond_to?(:copyright)
|
|
750
|
+
font_info.copyright || font_dict&.raw_data&.dig(:copyright) || ""
|
|
751
|
+
else
|
|
752
|
+
font_dict&.raw_data&.dig(:copyright) || ""
|
|
753
|
+
end
|
|
751
754
|
postscript_name = font_name
|
|
752
|
-
weight = if font_info
|
|
755
|
+
weight = if font_info.respond_to?(:weight)
|
|
753
756
|
font_info.weight
|
|
754
757
|
else
|
|
755
758
|
"Regular"
|
|
756
759
|
end
|
|
757
|
-
notice = if font_info
|
|
760
|
+
notice = if font_info.respond_to?(:notice)
|
|
758
761
|
font_info.notice
|
|
759
762
|
else
|
|
760
763
|
""
|
|
@@ -782,7 +785,9 @@ module Fontisan
|
|
|
782
785
|
]
|
|
783
786
|
|
|
784
787
|
# Filter out empty strings and build string storage
|
|
785
|
-
name_records = name_records.select
|
|
788
|
+
name_records = name_records.select do |r|
|
|
789
|
+
!r[:string].nil? && !r[:string].empty?
|
|
790
|
+
end
|
|
786
791
|
|
|
787
792
|
# Build string storage (UTF-16BE encoded for Windows platform)
|
|
788
793
|
string_storage = (+"").b
|
|
@@ -810,15 +815,15 @@ module Fontisan
|
|
|
810
815
|
# Write name records
|
|
811
816
|
platform_id = 3 # Windows
|
|
812
817
|
encoding_id = 1 # Unicode BMP
|
|
813
|
-
language_id = 0x0409
|
|
818
|
+
language_id = 0x0409 # US English
|
|
814
819
|
|
|
815
820
|
name_records.each do |record|
|
|
816
821
|
data << [platform_id].pack("n") # platform ID
|
|
817
822
|
data << [encoding_id].pack("n") # encoding ID
|
|
818
823
|
data << [language_id].pack("n") # language ID
|
|
819
824
|
data << [record[:name_id]].pack("n") # name ID
|
|
820
|
-
data << [record[:encoded].bytesize].pack("n")
|
|
821
|
-
data << [record[:offset]].pack("n")
|
|
825
|
+
data << [record[:encoded].bytesize].pack("n") # string length
|
|
826
|
+
data << [record[:offset]].pack("n") # string offset
|
|
822
827
|
end
|
|
823
828
|
|
|
824
829
|
# Write string storage
|
|
@@ -926,13 +931,13 @@ module Fontisan
|
|
|
926
931
|
|
|
927
932
|
# Unicode ranges (4 x uint32) - Basic Latin + Latin-1
|
|
928
933
|
# Bits 0-31: Basic Latin, Latin-1, Latin Extended-A/B, etc.
|
|
929
|
-
data << [0x00000001].pack("N")
|
|
934
|
+
data << [0x00000001].pack("N") # Basic Latin (0-7F)
|
|
930
935
|
data << [0x00000000].pack("N")
|
|
931
936
|
data << [0x00000000].pack("N")
|
|
932
937
|
data << [0x00000000].pack("N")
|
|
933
938
|
|
|
934
939
|
# achVendID (4 bytes) - Vendor ID
|
|
935
|
-
data << "UKWN"
|
|
940
|
+
data << "UKWN" # Unknown
|
|
936
941
|
|
|
937
942
|
# fsSelection (uint16) - Font selection flags
|
|
938
943
|
# Bit 6 (0x40) = Regular weight if 400-500
|
|
@@ -946,25 +951,25 @@ module Fontisan
|
|
|
946
951
|
data << [fs_selection].pack("n")
|
|
947
952
|
|
|
948
953
|
# usFirstCharIndex (uint16) - First Unicode character
|
|
949
|
-
data << [32].pack("n")
|
|
954
|
+
data << [32].pack("n") # Space
|
|
950
955
|
|
|
951
956
|
# usLastCharIndex (uint16) - Last Unicode character
|
|
952
|
-
data << [0xFFFD].pack("n")
|
|
957
|
+
data << [0xFFFD].pack("n") # Replacement character
|
|
953
958
|
|
|
954
959
|
# sTypoAscender (int16) - Use BlueValues or font bbox
|
|
955
|
-
if blue_values.length >= 4
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
+
typo_ascender = if blue_values.length >= 4
|
|
961
|
+
blue_values[3]
|
|
962
|
+
else
|
|
963
|
+
font_bbox[3]
|
|
964
|
+
end
|
|
960
965
|
data << [typo_ascender].pack("s>")
|
|
961
966
|
|
|
962
967
|
# sTypoDescender (int16) - Use BlueValues or font bbox (negative)
|
|
963
|
-
if blue_values.length >= 2
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
+
typo_descender = if blue_values.length >= 2
|
|
969
|
+
blue_values[0]
|
|
970
|
+
else
|
|
971
|
+
font_bbox[1]
|
|
972
|
+
end
|
|
968
973
|
data << [typo_descender].pack("s>")
|
|
969
974
|
|
|
970
975
|
# sTypoLineGap (int16)
|
|
@@ -1013,7 +1018,7 @@ module Fontisan
|
|
|
1013
1018
|
# Version (Fixed 16.16) - Use version 3.0 for CFF fonts (no glyph names)
|
|
1014
1019
|
# Version 2.0 would include glyph names, but for OTF output version 3.0 is fine
|
|
1015
1020
|
# since CFF table contains the glyph names
|
|
1016
|
-
data << [0x00030000].pack("N")
|
|
1021
|
+
data << [0x00030000].pack("N") # Version 3.0
|
|
1017
1022
|
|
|
1018
1023
|
# Italic Angle (Fixed 16.16)
|
|
1019
1024
|
# Get from FontInfo if available, otherwise default to 0
|
|
@@ -1030,7 +1035,7 @@ module Fontisan
|
|
|
1030
1035
|
data << [underline_thickness].pack("s>")
|
|
1031
1036
|
|
|
1032
1037
|
# Fixed Pitch (uint32) - Boolean for monospace
|
|
1033
|
-
is_fixed_pitch =
|
|
1038
|
+
is_fixed_pitch = font_info.is_fixed_pitch || false ? 1 : 0
|
|
1034
1039
|
data << [is_fixed_pitch].pack("N")
|
|
1035
1040
|
|
|
1036
1041
|
# Min/Max Memory for Type 42 (uint32 each) - Not used for CFF, set to 0
|
|
@@ -1066,10 +1071,10 @@ module Fontisan
|
|
|
1066
1071
|
unicode = Type1::AGL.unicode_for_glyph_name(glyph_name)
|
|
1067
1072
|
|
|
1068
1073
|
# If no Unicode mapping, try to derive from encoding position
|
|
1069
|
-
if unicode.nil?
|
|
1074
|
+
if unicode.nil? && (glyph_index < 128)
|
|
1070
1075
|
# For standard encoding, try to map from position
|
|
1071
1076
|
# This is a simplified approach - real implementation would be more robust
|
|
1072
|
-
unicode = glyph_index
|
|
1077
|
+
unicode = glyph_index
|
|
1073
1078
|
end
|
|
1074
1079
|
|
|
1075
1080
|
# Map Unicode to glyph index
|
|
@@ -1088,21 +1093,21 @@ module Fontisan
|
|
|
1088
1093
|
subtable_data = build_cmap_format_4(unicode_to_glyph)
|
|
1089
1094
|
|
|
1090
1095
|
# Calculate offsets
|
|
1091
|
-
encoding_records_offset = 4
|
|
1092
|
-
subtable_offset = encoding_records_offset + 8
|
|
1096
|
+
encoding_records_offset = 4 # After version (2) + num_tables (2)
|
|
1097
|
+
subtable_offset = encoding_records_offset + 8 # After one encoding record (8 bytes)
|
|
1093
1098
|
|
|
1094
1099
|
# Build cmap table header
|
|
1095
1100
|
# Version (uint16)
|
|
1096
1101
|
data << [0].pack("n")
|
|
1097
1102
|
|
|
1098
1103
|
# Number of encoding records (uint16)
|
|
1099
|
-
data << [1].pack("n")
|
|
1104
|
+
data << [1].pack("n") # One encoding record
|
|
1100
1105
|
|
|
1101
1106
|
# Encoding record: Platform ID (uint16), Encoding ID (uint16), Subtable offset (uint32)
|
|
1102
1107
|
# Platform 3 (Windows), Encoding 1 (Unicode BMP)
|
|
1103
1108
|
data << [3].pack("n") # Platform ID: Windows
|
|
1104
1109
|
data << [1].pack("n") # Encoding ID: Unicode BMP
|
|
1105
|
-
data << [subtable_offset].pack("N")
|
|
1110
|
+
data << [subtable_offset].pack("N") # Subtable offset
|
|
1106
1111
|
|
|
1107
1112
|
# Append subtable data
|
|
1108
1113
|
data << subtable_data
|
|
@@ -1160,13 +1165,13 @@ module Fontisan
|
|
|
1160
1165
|
# Calculate segment count and related values
|
|
1161
1166
|
seg_count = segments.length
|
|
1162
1167
|
seg_count_x2 = seg_count * 2
|
|
1163
|
-
search_range = 2
|
|
1168
|
+
search_range = 2**Math.log2(seg_count).to_i * 2
|
|
1164
1169
|
entry_selector = Math.log2(search_range / 2).to_i
|
|
1165
1170
|
range_shift = (seg_count - search_range / 2) * 2
|
|
1166
1171
|
|
|
1167
1172
|
# Build format 4 subtable header (14 bytes)
|
|
1168
|
-
data << [4].pack("n")
|
|
1169
|
-
data << [calculate_cmap4_length(segments)].pack("n")
|
|
1173
|
+
data << [4].pack("n") # Format
|
|
1174
|
+
data << [calculate_cmap4_length(segments)].pack("n") # Length (placeholder)
|
|
1170
1175
|
data << [0].pack("n") # Language (0 = independent)
|
|
1171
1176
|
data << [seg_count_x2].pack("n") # segCountX2
|
|
1172
1177
|
data << [search_range].pack("n") # searchRange
|
|
@@ -1203,9 +1208,9 @@ module Fontisan
|
|
|
1203
1208
|
|
|
1204
1209
|
# Write arrays (padded to even length)
|
|
1205
1210
|
end_codes.each { |code| data << [code].pack("n") }
|
|
1206
|
-
data << [0].pack("n")
|
|
1211
|
+
data << [0].pack("n") # Reserved padding
|
|
1207
1212
|
start_codes.each { |code| data << [code].pack("n") }
|
|
1208
|
-
id_deltas.each { |delta| data << [delta].pack("s>") }
|
|
1213
|
+
id_deltas.each { |delta| data << [delta].pack("s>") } # Signed
|
|
1209
1214
|
id_range_offsets.each { |offset| data << [offset].pack("n") }
|
|
1210
1215
|
glyph_id_array.each { |gid| data << [gid].pack("n") }
|
|
1211
1216
|
|
|
@@ -1227,7 +1232,7 @@ module Fontisan
|
|
|
1227
1232
|
seg_count = segments.length
|
|
1228
1233
|
|
|
1229
1234
|
# Rough estimate (actual calculation done during construction)
|
|
1230
|
-
14 + (seg_count * 8) + (seg_count * 2) + 100
|
|
1235
|
+
14 + (seg_count * 8) + (seg_count * 2) + 100 # 100 for glyph ID array estimate
|
|
1231
1236
|
end
|
|
1232
1237
|
end
|
|
1233
1238
|
end
|
|
@@ -276,7 +276,8 @@ module Fontisan
|
|
|
276
276
|
# Merge all extracted hints (prep_hints and fpgm_hints override stem widths if present)
|
|
277
277
|
# Note: fpgm_hints contains metadata (fpgm_size, has_functions, complexity)
|
|
278
278
|
# which we must filter out before merging into PostScript dict hints
|
|
279
|
-
fpgm_dict_hints = fpgm_hints.
|
|
279
|
+
fpgm_dict_hints = fpgm_hints.except(:fpgm_size, :has_functions,
|
|
280
|
+
:complexity)
|
|
280
281
|
hints.merge!(prep_hints).merge!(fpgm_dict_hints).merge!(blue_zones)
|
|
281
282
|
|
|
282
283
|
# Provide default blue_values if none were detected
|
|
@@ -32,46 +32,6 @@ module Fontisan
|
|
|
32
32
|
# Page size for lazy loading alignment (typical filesystem page size)
|
|
33
33
|
PAGE_SIZE = 4096
|
|
34
34
|
|
|
35
|
-
# Read OpenType Font from a file
|
|
36
|
-
#
|
|
37
|
-
# @param path [String] Path to the OTF file
|
|
38
|
-
# @param mode [Symbol] Loading mode (:metadata or :full, default: :full)
|
|
39
|
-
# @param lazy [Boolean] If true, load tables on demand (default: false)
|
|
40
|
-
# @return [OpenTypeFont] A new instance
|
|
41
|
-
# @raise [ArgumentError] if path is nil or empty, or if mode is invalid
|
|
42
|
-
# @raise [Errno::ENOENT] if file does not exist
|
|
43
|
-
# @raise [RuntimeError] if file format is invalid
|
|
44
|
-
def self.from_file(path, mode: LoadingModes::FULL, lazy: false)
|
|
45
|
-
if path.nil? || path.to_s.empty?
|
|
46
|
-
raise ArgumentError,
|
|
47
|
-
"path cannot be nil or empty"
|
|
48
|
-
end
|
|
49
|
-
raise Errno::ENOENT, "File not found: #{path}" unless File.exist?(path)
|
|
50
|
-
|
|
51
|
-
# Validate mode
|
|
52
|
-
LoadingModes.validate_mode!(mode)
|
|
53
|
-
|
|
54
|
-
File.open(path, "rb") do |io|
|
|
55
|
-
font = read(io)
|
|
56
|
-
font.initialize_storage
|
|
57
|
-
font.loading_mode = mode
|
|
58
|
-
font.lazy_load_enabled = lazy
|
|
59
|
-
|
|
60
|
-
if lazy
|
|
61
|
-
# Keep file handle open for lazy loading
|
|
62
|
-
font.io_source = File.open(path, "rb")
|
|
63
|
-
font.setup_finalizer
|
|
64
|
-
else
|
|
65
|
-
# Read tables upfront
|
|
66
|
-
font.read_table_data(io)
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
font
|
|
70
|
-
end
|
|
71
|
-
rescue BinData::ValidityError, EOFError => e
|
|
72
|
-
raise "Invalid OTF file: #{e.message}"
|
|
73
|
-
end
|
|
74
|
-
|
|
75
35
|
# Initialize storage hashes
|
|
76
36
|
#
|
|
77
37
|
# Extends base class to add page_cache for lazy loading.
|
data/lib/fontisan/sfnt_font.rb
CHANGED
|
@@ -149,34 +149,55 @@ module Fontisan
|
|
|
149
149
|
# @raise [RuntimeError] if file format is invalid
|
|
150
150
|
def self.from_file(path, mode: LoadingModes::FULL, lazy: false)
|
|
151
151
|
if path.nil? || path.to_s.empty?
|
|
152
|
-
raise ArgumentError,
|
|
153
|
-
"path cannot be nil or empty"
|
|
152
|
+
raise ArgumentError, "path cannot be nil or empty"
|
|
154
153
|
end
|
|
155
154
|
raise Errno::ENOENT, "File not found: #{path}" unless File.exist?(path)
|
|
156
155
|
|
|
157
|
-
# Validate mode
|
|
158
156
|
LoadingModes.validate_mode!(mode)
|
|
159
157
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
158
|
+
font = new
|
|
159
|
+
font.initialize_storage
|
|
160
|
+
font.loading_mode = mode
|
|
161
|
+
font.lazy_load_enabled = lazy
|
|
162
|
+
|
|
163
|
+
lazy ? load_lazy(path, font) : load_eager(path, font)
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# Load font with lazy loading (keeps file handle open)
|
|
167
|
+
#
|
|
168
|
+
# @param path [String] Path to the font file
|
|
169
|
+
# @param font [SfntFont] Font instance to populate
|
|
170
|
+
# @return [SfntFont] The populated font instance
|
|
171
|
+
def self.load_lazy(path, font)
|
|
172
|
+
# rubocop:disable Security/Open -- Intentionally kept open for lazy loading
|
|
173
|
+
# Finalizer handles cleanup when object is GC'd
|
|
174
|
+
font.io_source = File.open(path, "rb")
|
|
175
|
+
# rubocop:enable Security/Open
|
|
176
|
+
font.setup_finalizer
|
|
177
|
+
font.io_source.rewind
|
|
178
|
+
font.read(font.io_source)
|
|
179
|
+
font
|
|
180
|
+
rescue BinData::ValidityError, EOFError => e
|
|
181
|
+
font_type = name.split("::").last
|
|
182
|
+
raise "Invalid #{font_type} file: #{e.message}"
|
|
183
|
+
end
|
|
174
184
|
|
|
175
|
-
|
|
185
|
+
# Load font with eager loading (reads all data, closes file)
|
|
186
|
+
#
|
|
187
|
+
# @param path [String] Path to the font file
|
|
188
|
+
# @param font [SfntFont] Font instance to populate
|
|
189
|
+
# @return [SfntFont] The populated font instance
|
|
190
|
+
def self.load_eager(path, font)
|
|
191
|
+
File.open(path, "rb") do |io|
|
|
192
|
+
font.read(io)
|
|
193
|
+
font.read_table_data(io)
|
|
176
194
|
end
|
|
195
|
+
font
|
|
177
196
|
rescue BinData::ValidityError, EOFError => e
|
|
178
|
-
|
|
197
|
+
font_type = name.split("::").last
|
|
198
|
+
raise "Invalid #{font_type} file: #{e.message}"
|
|
179
199
|
end
|
|
200
|
+
private_class_method :load_lazy, :load_eager
|
|
180
201
|
|
|
181
202
|
# Read SFNT Font from collection at specific offset
|
|
182
203
|
#
|
|
@@ -422,9 +443,7 @@ module Fontisan
|
|
|
422
443
|
#
|
|
423
444
|
# @return [Hash<String, SfntTable>] Hash mapping tag => SfntTable instance
|
|
424
445
|
def all_sfnt_tables
|
|
425
|
-
table_names.
|
|
426
|
-
hash[tag] = sfnt_table(tag)
|
|
427
|
-
end
|
|
446
|
+
table_names.to_h { |tag| [tag, sfnt_table(tag)] }
|
|
428
447
|
end
|
|
429
448
|
|
|
430
449
|
# Get parsed table instance
|