fontisan 0.2.11 → 0.2.12
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 +214 -51
- data/README.adoc +160 -0
- data/lib/fontisan/cli.rb +177 -6
- data/lib/fontisan/commands/convert_command.rb +32 -1
- data/lib/fontisan/config/conversion_matrix.yml +132 -4
- data/lib/fontisan/constants.rb +12 -0
- data/lib/fontisan/conversion_options.rb +378 -0
- data/lib/fontisan/converters/collection_converter.rb +45 -10
- data/lib/fontisan/converters/format_converter.rb +2 -0
- data/lib/fontisan/converters/outline_converter.rb +78 -4
- data/lib/fontisan/converters/type1_converter.rb +559 -0
- data/lib/fontisan/font_loader.rb +46 -3
- data/lib/fontisan/type1/afm_generator.rb +436 -0
- data/lib/fontisan/type1/afm_parser.rb +298 -0
- data/lib/fontisan/type1/agl.rb +456 -0
- data/lib/fontisan/type1/charstring_converter.rb +240 -0
- data/lib/fontisan/type1/charstrings.rb +408 -0
- data/lib/fontisan/type1/conversion_options.rb +243 -0
- data/lib/fontisan/type1/decryptor.rb +183 -0
- data/lib/fontisan/type1/encodings.rb +697 -0
- data/lib/fontisan/type1/font_dictionary.rb +514 -0
- data/lib/fontisan/type1/generator.rb +220 -0
- data/lib/fontisan/type1/inf_generator.rb +332 -0
- data/lib/fontisan/type1/pfa_generator.rb +343 -0
- data/lib/fontisan/type1/pfa_parser.rb +158 -0
- data/lib/fontisan/type1/pfb_generator.rb +291 -0
- data/lib/fontisan/type1/pfb_parser.rb +166 -0
- data/lib/fontisan/type1/pfm_generator.rb +610 -0
- data/lib/fontisan/type1/pfm_parser.rb +433 -0
- data/lib/fontisan/type1/private_dict.rb +285 -0
- data/lib/fontisan/type1/ttf_to_type1_converter.rb +327 -0
- data/lib/fontisan/type1/upm_scaler.rb +118 -0
- data/lib/fontisan/type1.rb +73 -0
- data/lib/fontisan/type1_font.rb +331 -0
- data/lib/fontisan/version.rb +1 -1
- data/lib/fontisan.rb +2 -0
- metadata +26 -2
data/lib/fontisan/cli.rb
CHANGED
|
@@ -203,10 +203,10 @@ module Fontisan
|
|
|
203
203
|
|
|
204
204
|
desc "convert FONT_FILE", "Convert font to different format"
|
|
205
205
|
option :to, type: :string, required: true,
|
|
206
|
-
desc: "Target format (ttf, otf, woff, woff2)",
|
|
206
|
+
desc: "Target format (ttf, otf, type1, t1, woff, woff2)",
|
|
207
207
|
aliases: "-t"
|
|
208
|
-
option :output, type: :string,
|
|
209
|
-
desc: "Output file path",
|
|
208
|
+
option :output, type: :string,
|
|
209
|
+
desc: "Output file path (required unless --show-options)",
|
|
210
210
|
aliases: "-o"
|
|
211
211
|
option :coordinates, type: :string,
|
|
212
212
|
desc: "Instance coordinates (e.g., wght=700,wdth=100)",
|
|
@@ -232,10 +232,34 @@ module Fontisan
|
|
|
232
232
|
desc: "Italic axis value (alternative to --coordinates)"
|
|
233
233
|
option :opsz, type: :numeric,
|
|
234
234
|
desc: "Optical size axis value (alternative to --coordinates)"
|
|
235
|
+
# Conversion options
|
|
236
|
+
option :preset, type: :string,
|
|
237
|
+
desc: "Use named preset (type1_to_modern, modern_to_type1, web_optimized, archive_to_modern)"
|
|
238
|
+
option :show_options, type: :boolean, default: false,
|
|
239
|
+
desc: "Show recommended options for the conversion and exit"
|
|
240
|
+
option :decompose, type: :boolean,
|
|
241
|
+
desc: "Decompose composite glyphs (opening option)"
|
|
242
|
+
option :convert_curves, type: :boolean,
|
|
243
|
+
desc: "Convert curves during conversion (opening option)"
|
|
244
|
+
option :scale_to_1000, type: :boolean,
|
|
245
|
+
desc: "Scale to 1000 units per em (opening option)"
|
|
246
|
+
option :autohint, type: :boolean,
|
|
247
|
+
desc: "Auto-hint the font (opening option)"
|
|
248
|
+
option :generate_unicode, type: :boolean,
|
|
249
|
+
desc: "Generate Unicode mappings (Type 1 opening option)"
|
|
250
|
+
option :hinting_mode, type: :string,
|
|
251
|
+
desc: "Hinting mode: preserve, auto, none, or full"
|
|
252
|
+
option :optimize_cff, type: :boolean,
|
|
253
|
+
desc: "Enable CFF subroutine optimization"
|
|
254
|
+
option :optimize_tables, type: :boolean,
|
|
255
|
+
desc: "Enable table optimization"
|
|
256
|
+
option :decompose_on_output, type: :boolean,
|
|
257
|
+
desc: "Decompose on output (generating option)"
|
|
235
258
|
# Convert a font to a different format using the universal transformation pipeline.
|
|
236
259
|
#
|
|
237
260
|
# Supported conversions:
|
|
238
261
|
# - TTF ↔ OTF: Outline format conversion
|
|
262
|
+
# - Type 1 ↔ TTF/OTF: Adobe Type 1 font conversion
|
|
239
263
|
# - WOFF/WOFF2: Web font packaging
|
|
240
264
|
# - Variable fonts: Automatic variation preservation or instance generation
|
|
241
265
|
# - Collections (TTC/OTC/dfont): Preserve mixed TTF+OTF by default, or standardize with --target-format
|
|
@@ -261,6 +285,12 @@ module Fontisan
|
|
|
261
285
|
# @example Convert TTF to OTF
|
|
262
286
|
# fontisan convert font.ttf --to otf --output font.otf
|
|
263
287
|
#
|
|
288
|
+
# @example Convert Type 1 to OTF
|
|
289
|
+
# fontisan convert font.pfb --to otf --output font.otf
|
|
290
|
+
#
|
|
291
|
+
# @example Convert OTF to Type 1
|
|
292
|
+
# fontisan convert font.otf --to type1 --output font.pfb
|
|
293
|
+
#
|
|
264
294
|
# @example Convert TTC to OTC (preserves mixed formats by default)
|
|
265
295
|
# fontisan convert family.ttc --to otc --output family.otc
|
|
266
296
|
#
|
|
@@ -284,17 +314,46 @@ module Fontisan
|
|
|
284
314
|
#
|
|
285
315
|
# @example Convert without validation
|
|
286
316
|
# fontisan convert font.ttf --to otf --output font.otf --no-validate
|
|
317
|
+
#
|
|
318
|
+
# @example Use named preset
|
|
319
|
+
# fontisan convert font.pfb --to otf --output font.otf --preset type1_to_modern
|
|
320
|
+
#
|
|
321
|
+
# @example Show recommended options for conversion
|
|
322
|
+
# fontisan convert font.ttf --to otf --show-options
|
|
323
|
+
#
|
|
324
|
+
# @example Convert with custom options
|
|
325
|
+
# fontisan convert font.ttf --to otf --output font.otf --autohint --hinting-mode auto
|
|
287
326
|
def convert(font_file)
|
|
327
|
+
# Detect source format from file
|
|
328
|
+
source_format = detect_source_format(font_file)
|
|
329
|
+
|
|
330
|
+
# Handle --show-options
|
|
331
|
+
if options[:show_options]
|
|
332
|
+
show_recommended_options(source_format, options[:to])
|
|
333
|
+
return
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
# Validate output is provided when not using --show-options
|
|
337
|
+
unless options[:output]
|
|
338
|
+
raise Thor::Error, "Output path is required. Use --output option."
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
# Build ConversionOptions
|
|
342
|
+
conv_options = build_conversion_options(source_format, options[:to],
|
|
343
|
+
options)
|
|
344
|
+
|
|
288
345
|
# Build instance coordinates from axis options
|
|
289
346
|
instance_coords = build_instance_coordinates(options)
|
|
290
347
|
|
|
291
|
-
# Merge coordinates into
|
|
348
|
+
# Merge coordinates and ConversionOptions into convert_options
|
|
292
349
|
convert_options = options.to_h.dup
|
|
293
350
|
if instance_coords.any?
|
|
294
|
-
convert_options[:instance_coordinates] =
|
|
295
|
-
instance_coords
|
|
351
|
+
convert_options[:instance_coordinates] = instance_coords
|
|
296
352
|
end
|
|
297
353
|
|
|
354
|
+
# Add ConversionOptions if built
|
|
355
|
+
convert_options[:options] = conv_options if conv_options
|
|
356
|
+
|
|
298
357
|
command = Commands::ConvertCommand.new(font_file, convert_options)
|
|
299
358
|
command.run
|
|
300
359
|
rescue Errno::ENOENT, Error => e
|
|
@@ -668,5 +727,117 @@ module Fontisan
|
|
|
668
727
|
puts " #{profile_name.to_s.ljust(20)} - #{config[:description]}"
|
|
669
728
|
end
|
|
670
729
|
end
|
|
730
|
+
|
|
731
|
+
# Detect source format from file extension
|
|
732
|
+
#
|
|
733
|
+
# @param font_file [String] Path to the font file
|
|
734
|
+
# @return [Symbol] Detected format symbol
|
|
735
|
+
def detect_source_format(font_file)
|
|
736
|
+
ext = File.extname(font_file).downcase
|
|
737
|
+
case ext
|
|
738
|
+
when ".ttf"
|
|
739
|
+
:ttf
|
|
740
|
+
when ".otf"
|
|
741
|
+
:otf
|
|
742
|
+
when ".pfb", ".pfa"
|
|
743
|
+
:type1
|
|
744
|
+
when ".ttc"
|
|
745
|
+
:ttc
|
|
746
|
+
when ".otc"
|
|
747
|
+
:otc
|
|
748
|
+
when ".dfont"
|
|
749
|
+
:dfont
|
|
750
|
+
when ".woff"
|
|
751
|
+
:woff
|
|
752
|
+
when ".woff2"
|
|
753
|
+
:woff2
|
|
754
|
+
when ".svg"
|
|
755
|
+
:svg
|
|
756
|
+
else
|
|
757
|
+
# Default to TTF for unknown extensions
|
|
758
|
+
:ttf
|
|
759
|
+
end
|
|
760
|
+
end
|
|
761
|
+
|
|
762
|
+
# Show recommended options for a conversion
|
|
763
|
+
#
|
|
764
|
+
# @param source_format [Symbol] Source format
|
|
765
|
+
# @param target_format_str [String] Target format string
|
|
766
|
+
# @return [void]
|
|
767
|
+
def show_recommended_options(source_format, target_format_str)
|
|
768
|
+
target_format = Fontisan::ConversionOptions.normalize_format(target_format_str)
|
|
769
|
+
|
|
770
|
+
puts "\nRecommended options for #{source_format.to_s.upcase} → #{target_format.to_s.upcase} conversion:"
|
|
771
|
+
puts "=" * 70
|
|
772
|
+
|
|
773
|
+
# Show recommended options
|
|
774
|
+
recommended = Fontisan::ConversionOptions.recommended(from: source_format,
|
|
775
|
+
to: target_format)
|
|
776
|
+
puts "\nOpening options:"
|
|
777
|
+
if recommended.opening.any?
|
|
778
|
+
recommended.opening.each do |key, value|
|
|
779
|
+
puts " --#{key.to_s.gsub('_', '-')}: #{value}"
|
|
780
|
+
end
|
|
781
|
+
else
|
|
782
|
+
puts " (none)"
|
|
783
|
+
end
|
|
784
|
+
|
|
785
|
+
puts "\nGenerating options:"
|
|
786
|
+
if recommended.generating.any?
|
|
787
|
+
recommended.generating.each do |key, value|
|
|
788
|
+
puts " --#{key.to_s.gsub('_', '-')}: #{value}"
|
|
789
|
+
end
|
|
790
|
+
else
|
|
791
|
+
puts " (none)"
|
|
792
|
+
end
|
|
793
|
+
|
|
794
|
+
puts "\nAvailable presets:"
|
|
795
|
+
Fontisan::ConversionOptions.available_presets.each do |preset|
|
|
796
|
+
puts " #{preset}"
|
|
797
|
+
end
|
|
798
|
+
|
|
799
|
+
puts "\nTo use preset:"
|
|
800
|
+
puts " fontisan convert #{source_format} --to #{target_format} --preset <name> --output output.ext"
|
|
801
|
+
puts "\n"
|
|
802
|
+
end
|
|
803
|
+
|
|
804
|
+
# Build ConversionOptions from CLI options
|
|
805
|
+
#
|
|
806
|
+
# @param source_format [Symbol] Source format
|
|
807
|
+
# @param target_format_str [String] Target format string
|
|
808
|
+
# @param opts [Hash] CLI options
|
|
809
|
+
# @return [ConversionOptions, nil] Built ConversionOptions or nil
|
|
810
|
+
def build_conversion_options(source_format, target_format_str, opts)
|
|
811
|
+
target_format = Fontisan::ConversionOptions.normalize_format(target_format_str)
|
|
812
|
+
|
|
813
|
+
# Use preset if specified
|
|
814
|
+
if opts[:preset]
|
|
815
|
+
return Fontisan::ConversionOptions.from_preset(opts[:preset])
|
|
816
|
+
end
|
|
817
|
+
|
|
818
|
+
# Build opening options from CLI flags
|
|
819
|
+
opening = {}
|
|
820
|
+
opening[:decompose_composites] = true if opts[:decompose]
|
|
821
|
+
opening[:convert_curves] = true if opts[:convert_curves]
|
|
822
|
+
opening[:scale_to_1000] = true if opts[:scale_to_1000]
|
|
823
|
+
opening[:autohint] = true if opts[:autohint]
|
|
824
|
+
opening[:generate_unicode] = true if opts[:generate_unicode]
|
|
825
|
+
|
|
826
|
+
# Build generating options from CLI flags
|
|
827
|
+
generating = {}
|
|
828
|
+
generating[:hinting_mode] = opts[:hinting_mode] if opts[:hinting_mode]
|
|
829
|
+
generating[:decompose_on_output] = true if opts[:decompose_on_output]
|
|
830
|
+
generating[:optimize_tables] = true if opts[:optimize_tables]
|
|
831
|
+
|
|
832
|
+
# Only create ConversionOptions if any options were set
|
|
833
|
+
return nil if opening.empty? && generating.empty?
|
|
834
|
+
|
|
835
|
+
Fontisan::ConversionOptions.new(
|
|
836
|
+
from: source_format,
|
|
837
|
+
to: target_format,
|
|
838
|
+
opening: opening,
|
|
839
|
+
generating: generating,
|
|
840
|
+
)
|
|
841
|
+
end
|
|
671
842
|
end
|
|
672
843
|
end
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require_relative "base_command"
|
|
4
4
|
require_relative "../pipeline/transformation_pipeline"
|
|
5
5
|
require_relative "../converters/collection_converter"
|
|
6
|
+
require_relative "../conversion_options"
|
|
6
7
|
require_relative "../font_loader"
|
|
7
8
|
|
|
8
9
|
module Fontisan
|
|
@@ -36,6 +37,16 @@ module Fontisan
|
|
|
36
37
|
# coordinates: 'wght=700,wdth=100'
|
|
37
38
|
# )
|
|
38
39
|
# command.run
|
|
40
|
+
#
|
|
41
|
+
# @example Convert with ConversionOptions
|
|
42
|
+
# options = ConversionOptions.recommended(from: :ttf, to: :otf)
|
|
43
|
+
# command = ConvertCommand.new(
|
|
44
|
+
# 'input.ttf',
|
|
45
|
+
# to: 'otf',
|
|
46
|
+
# output: 'output.otf',
|
|
47
|
+
# options: options
|
|
48
|
+
# )
|
|
49
|
+
# command.run
|
|
39
50
|
class ConvertCommand < BaseCommand
|
|
40
51
|
# Initialize convert command
|
|
41
52
|
#
|
|
@@ -52,6 +63,7 @@ module Fontisan
|
|
|
52
63
|
# @option options [String] :target_format Target outline format for collections: 'preserve' (default), 'ttf', or 'otf'
|
|
53
64
|
# @option options [Boolean] :no_validate Skip output validation
|
|
54
65
|
# @option options [Boolean] :verbose Verbose output
|
|
66
|
+
# @option options [ConversionOptions] :options ConversionOptions object
|
|
55
67
|
def initialize(font_path, options = {})
|
|
56
68
|
super(font_path, options)
|
|
57
69
|
|
|
@@ -63,6 +75,9 @@ module Fontisan
|
|
|
63
75
|
# Parse target format
|
|
64
76
|
@target_format = parse_target_format(opts[:to])
|
|
65
77
|
|
|
78
|
+
# Extract ConversionOptions if provided
|
|
79
|
+
@conv_options = extract_conversion_options(opts)
|
|
80
|
+
|
|
66
81
|
# Parse coordinates if string provided
|
|
67
82
|
@coordinates = if opts[:coordinates]
|
|
68
83
|
parse_coordinates(opts[:coordinates])
|
|
@@ -123,6 +138,9 @@ module Fontisan
|
|
|
123
138
|
verbose: @options[:verbose],
|
|
124
139
|
}
|
|
125
140
|
|
|
141
|
+
# Add ConversionOptions if available
|
|
142
|
+
pipeline_options[:conversion_options] = @conv_options if @conv_options
|
|
143
|
+
|
|
126
144
|
# Add variation options if specified
|
|
127
145
|
pipeline_options[:coordinates] = @coordinates if @coordinates
|
|
128
146
|
pipeline_options[:instance_index] = @instance_index if @instance_index
|
|
@@ -196,6 +214,7 @@ module Fontisan
|
|
|
196
214
|
output: @output_path,
|
|
197
215
|
target_format: @collection_target_format,
|
|
198
216
|
verbose: @options[:verbose],
|
|
217
|
+
options: @conv_options, # Pass ConversionOptions
|
|
199
218
|
},
|
|
200
219
|
)
|
|
201
220
|
|
|
@@ -309,10 +328,12 @@ module Fontisan
|
|
|
309
328
|
:woff
|
|
310
329
|
when "woff2"
|
|
311
330
|
:woff2
|
|
331
|
+
when "type1", "type-1", "t1", "pfb", "pfa"
|
|
332
|
+
:type1
|
|
312
333
|
else
|
|
313
334
|
raise ArgumentError,
|
|
314
335
|
"Unknown target format: #{format}. " \
|
|
315
|
-
"Supported: ttf, otf, ttc, otc, dfont, svg, woff, woff2"
|
|
336
|
+
"Supported: ttf, otf, type1, t1, ttc, otc, dfont, svg, woff, woff2"
|
|
316
337
|
end
|
|
317
338
|
end
|
|
318
339
|
|
|
@@ -329,6 +350,16 @@ module Fontisan
|
|
|
329
350
|
"#{(bytes / (1024.0 * 1024)).round(1)} MB"
|
|
330
351
|
end
|
|
331
352
|
end
|
|
353
|
+
|
|
354
|
+
# Extract ConversionOptions from options hash
|
|
355
|
+
#
|
|
356
|
+
# @param options [Hash, ConversionOptions] Options or hash containing :options key
|
|
357
|
+
# @return [ConversionOptions, nil] Extracted ConversionOptions or nil
|
|
358
|
+
def extract_conversion_options(options)
|
|
359
|
+
return options if options.is_a?(ConversionOptions)
|
|
360
|
+
|
|
361
|
+
options[:options] if options.is_a?(Hash)
|
|
362
|
+
end
|
|
332
363
|
end
|
|
333
364
|
end
|
|
334
365
|
end
|
|
@@ -6,9 +6,13 @@
|
|
|
6
6
|
# Format identifiers:
|
|
7
7
|
# - ttf: TrueType Font (with glyf/loca tables)
|
|
8
8
|
# - otf: OpenType Font with CFF outlines (with CFF table)
|
|
9
|
-
# -
|
|
10
|
-
# -
|
|
11
|
-
# -
|
|
9
|
+
# - type1: Adobe Type 1 Font (PFB/PFA format)
|
|
10
|
+
# - woff: Web Open Font Format (zlib compression)
|
|
11
|
+
# - woff2: Web Open Font Format 2 (Brotli compression)
|
|
12
|
+
# - svg: SVG Font (deprecated, for conversion/inspection)
|
|
13
|
+
# - ttc: TrueType Collection
|
|
14
|
+
# - otc: OpenType Collection
|
|
15
|
+
# - dfont: Apple dfont suitcase
|
|
12
16
|
#
|
|
13
17
|
# Phase 1 (Milestone 1.3): Basic conversions
|
|
14
18
|
# - Same format (copy/optimize): ttf→ttf, otf→otf
|
|
@@ -20,8 +24,11 @@
|
|
|
20
24
|
# Phase 2 (Milestone 2.2): SVG font generation
|
|
21
25
|
# - SVG export: ttf to svg, otf to svg
|
|
22
26
|
#
|
|
27
|
+
# Phase 3: Type 1 font support
|
|
28
|
+
# - Type 1 conversions: type1↔otf, type1↔ttf
|
|
29
|
+
#
|
|
23
30
|
# Future phases:
|
|
24
|
-
# - Phase
|
|
31
|
+
# - Phase 4: Variable font conversions
|
|
25
32
|
|
|
26
33
|
conversions:
|
|
27
34
|
# Same-format conversions (copy/optimize)
|
|
@@ -58,6 +65,47 @@ conversions:
|
|
|
58
65
|
table generation including cubic-to-quadratic curve conversion and
|
|
59
66
|
proper TrueType glyph structure encoding.
|
|
60
67
|
|
|
68
|
+
# Phase 3 conversions - Type 1 fonts
|
|
69
|
+
- from: type1
|
|
70
|
+
to: otf
|
|
71
|
+
strategy: type1_converter
|
|
72
|
+
description: "Convert Type 1 to OpenType/CFF format"
|
|
73
|
+
status: foundation
|
|
74
|
+
notes: >
|
|
75
|
+
Type 1 to OpenType conversion using CharStringConverter. Converts Type 1
|
|
76
|
+
CharStrings to CFF format and builds CFF table with proper DICT structures.
|
|
77
|
+
seac composites are expanded. Some hinting may not be preserved.
|
|
78
|
+
|
|
79
|
+
- from: otf
|
|
80
|
+
to: type1
|
|
81
|
+
strategy: type1_converter
|
|
82
|
+
description: "Convert OpenType/CFF to Type 1 format"
|
|
83
|
+
status: foundation
|
|
84
|
+
notes: >
|
|
85
|
+
OpenType to Type 1 conversion. Reverse conversion from CFF CharStrings to
|
|
86
|
+
Type 1 format. Builds PFB output with eexec encryption. Some modern
|
|
87
|
+
OpenType features may be lost in conversion.
|
|
88
|
+
|
|
89
|
+
- from: type1
|
|
90
|
+
to: ttf
|
|
91
|
+
strategy: type1_converter
|
|
92
|
+
description: "Convert Type 1 to TrueType format"
|
|
93
|
+
status: foundation
|
|
94
|
+
notes: >
|
|
95
|
+
Two-step conversion: Type 1 → OTF → TTF. First converts to OpenType/CFF,
|
|
96
|
+
then to TrueType with cubic-to-quadratic curve approximation. Hinting may
|
|
97
|
+
not be preserved in either step.
|
|
98
|
+
|
|
99
|
+
- from: ttf
|
|
100
|
+
to: type1
|
|
101
|
+
strategy: type1_converter
|
|
102
|
+
description: "Convert TrueType to Type 1 format"
|
|
103
|
+
status: foundation
|
|
104
|
+
notes: >
|
|
105
|
+
Two-step conversion: TTF → OTF → Type 1. First converts to OpenType/CFF
|
|
106
|
+
with quadratic-to-cubic curve conversion, then to Type 1. Significant
|
|
107
|
+
approximation artifacts may occur due to curve conversions.
|
|
108
|
+
|
|
61
109
|
# Phase 2 conversions (Milestone 2.1) - WOFF2
|
|
62
110
|
- from: ttf
|
|
63
111
|
to: woff2
|
|
@@ -147,6 +195,35 @@ conversions:
|
|
|
147
195
|
transformation. Note: SVG fonts are deprecated in favor of WOFF2, but
|
|
148
196
|
useful for fallback, conversion, and inspection purposes.
|
|
149
197
|
|
|
198
|
+
# Type 1 to web formats (via OTF intermediate)
|
|
199
|
+
- from: type1
|
|
200
|
+
to: woff
|
|
201
|
+
strategy: type1_converter
|
|
202
|
+
description: "Convert Type 1 to WOFF format"
|
|
203
|
+
status: foundation
|
|
204
|
+
notes: >
|
|
205
|
+
Two-step conversion: Type 1 → OTF → WOFF. Converts Type 1 to OpenType/CFF,
|
|
206
|
+
then compresses with zlib. Useful for web delivery of legacy Type 1 fonts.
|
|
207
|
+
|
|
208
|
+
- from: type1
|
|
209
|
+
to: woff2
|
|
210
|
+
strategy: type1_converter
|
|
211
|
+
description: "Convert Type 1 to WOFF2 format"
|
|
212
|
+
status: foundation
|
|
213
|
+
notes: >
|
|
214
|
+
Two-step conversion: Type 1 → OTF → WOFF2. Converts Type 1 to OpenType/CFF,
|
|
215
|
+
then compresses with Brotli. Best for web delivery of legacy Type 1 fonts.
|
|
216
|
+
|
|
217
|
+
- from: type1
|
|
218
|
+
to: svg
|
|
219
|
+
strategy: type1_converter
|
|
220
|
+
description: "Generate SVG font from Type 1"
|
|
221
|
+
status: foundation
|
|
222
|
+
notes: >
|
|
223
|
+
Type 1 to SVG conversion. Extracts outlines from Type 1 CharStrings and
|
|
224
|
+
generates SVG font format. Note: SVG fonts are deprecated but useful for
|
|
225
|
+
inspection and conversion workflows.
|
|
226
|
+
|
|
150
227
|
# WOFF2 decompression (reverse conversions)
|
|
151
228
|
- from: woff2
|
|
152
229
|
to: ttf
|
|
@@ -296,6 +373,57 @@ compatibility:
|
|
|
296
373
|
- hinting_loss: >
|
|
297
374
|
CFF hints are not converted to TrueType hinting instructions.
|
|
298
375
|
|
|
376
|
+
type1_to_otf:
|
|
377
|
+
preserves:
|
|
378
|
+
- glyph_outlines: Type 1 CharStrings are similar to CFF
|
|
379
|
+
- font_metrics: FontBBox, metrics preserved
|
|
380
|
+
- name_table: FontInfo converted to name table
|
|
381
|
+
- hints: Some hints preserved (BlueValues, OtherBlues)
|
|
382
|
+
limitations:
|
|
383
|
+
- seac_expansion: >
|
|
384
|
+
seac composite glyphs are expanded to base glyphs.
|
|
385
|
+
- hinting_approximation: >
|
|
386
|
+
Some Type 1 hints may not translate exactly to CFF hints.
|
|
387
|
+
- lost_features: >
|
|
388
|
+
Type 1-specific features (Flex, multiple master) not preserved.
|
|
389
|
+
|
|
390
|
+
otf_to_type1:
|
|
391
|
+
preserves:
|
|
392
|
+
- glyph_outlines: CFF outlines converted to Type 1
|
|
393
|
+
- font_metrics: Basic metrics preserved
|
|
394
|
+
- name_table: name table converted to FontInfo
|
|
395
|
+
limitations:
|
|
396
|
+
- reverse_conversion: >
|
|
397
|
+
CFF to Type 1 is reverse conversion with potential data loss.
|
|
398
|
+
- modern_features_lost: >
|
|
399
|
+
Modern OpenType features (GPOS, GSUB variations) lost in Type 1.
|
|
400
|
+
- hinting_approximation: >
|
|
401
|
+
CFF hints may not translate exactly to Type 1 hints.
|
|
402
|
+
|
|
403
|
+
type1_to_ttf:
|
|
404
|
+
preserves:
|
|
405
|
+
- glyph_outlines: Via OTF intermediate
|
|
406
|
+
- font_metrics: Basic metrics preserved
|
|
407
|
+
limitations:
|
|
408
|
+
- multi_step_conversion: >
|
|
409
|
+
Type 1 → OTF → TTF, compounding approximation errors.
|
|
410
|
+
- curve_approximation: >
|
|
411
|
+
CFF cubic to TrueType quadratic approximation.
|
|
412
|
+
- significant_data_loss: >
|
|
413
|
+
Most Type 1 and OpenType features lost.
|
|
414
|
+
|
|
415
|
+
ttf_to_type1:
|
|
416
|
+
preserves:
|
|
417
|
+
- glyph_outlines: Via OTF intermediate
|
|
418
|
+
- font_metrics: Basic metrics preserved
|
|
419
|
+
limitations:
|
|
420
|
+
- multi_step_conversion: >
|
|
421
|
+
TTF → OTF → Type 1, compounding approximation errors.
|
|
422
|
+
- curve_approximation: >
|
|
423
|
+
Quadratic to cubic, then back to Type 1 curves.
|
|
424
|
+
- extreme_data_loss: >
|
|
425
|
+
Nearly all TrueType and Type 1 features lost.
|
|
426
|
+
|
|
299
427
|
same_format:
|
|
300
428
|
preserves:
|
|
301
429
|
- all_tables
|
data/lib/fontisan/constants.rb
CHANGED
|
@@ -95,6 +95,18 @@ module Fontisan
|
|
|
95
95
|
# CFF2 table tag identifier (CFF version 2 with variations)
|
|
96
96
|
CFF2_TAG = "CFF2"
|
|
97
97
|
|
|
98
|
+
# Adobe Type 1 font format constants
|
|
99
|
+
# PFB (Printer Font Binary) chunk markers
|
|
100
|
+
PFB_ASCII_CHUNK = 0x8001
|
|
101
|
+
PFB_BINARY_CHUNK = 0x8002
|
|
102
|
+
|
|
103
|
+
# PFA (Printer Font ASCII) file signatures
|
|
104
|
+
PFA_SIGNATURE_ADOBE_1_0 = "%!PS-AdobeFont-1.0"
|
|
105
|
+
PFA_SIGNATURE_ADOBE_3_0 = "%!PS-Adobe-3.0 Resource-Font"
|
|
106
|
+
|
|
107
|
+
# Type 1 CharString operators
|
|
108
|
+
TYPE1_SEAC_ESCAPE = 6 # seac operator is escape byte 12 + 6
|
|
109
|
+
|
|
98
110
|
# TrueType hinting tables
|
|
99
111
|
# Font Program table (TrueType bytecode executed once at font load)
|
|
100
112
|
FPGM_TAG = "fpgm"
|