Class: Fontisan::Type1::Generator

Inherits:
Object
  • Object
show all
Defined in:
lib/fontisan/type1/generator.rb

Overview

Unified Type 1 font generator

Generator provides a unified interface for generating all Type 1 font formats from TrueType/OpenType fonts.

This generator creates:

  • AFM (Adobe Font Metrics) - Text-based font metrics
  • PFM (Printer Font Metrics) - Windows font metrics
  • PFA (Printer Font ASCII) - Unix Type 1 font (ASCII-hex encoded)
  • PFB (Printer Font Binary) - Windows Type 1 font (binary)
  • INF (Font Information) - Windows installation metadata

Examples:

Generate all Type 1 formats with default options (1000 UPM)

font = Fontisan::FontLoader.load("font.ttf")
result = Fontisan::Type1::Generator.generate(font)
result[:afm]   # => AFM file content
result[:pfm]   # => PFM file content
result[:pfb]   # => PFB file content
result[:inf]   # => INF file content

Generate Unix Type 1 (PFA) with custom options

result = Fontisan::Type1::Generator.generate(font,
  format: :pfa,
  upm_scale: 1000,
  encoding: Fontisan::Type1::Encodings::AdobeStandard
)

Generate with ConversionOptions preset

options = Fontisan::Type1::ConversionOptions.windows_type1
result = Fontisan::Type1::Generator.generate(font, options)

See Also:

Constant Summary collapse

DEFAULT_OPTIONS =

Default generation options

{
  upm_scale: 1000,
  encoding: Encodings::AdobeStandard,
  decompose_composites: false,
  convert_curves: true,
  autohint: false,
  preserve_hinting: false,
  format: :pfb,
}.freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(font, options = {}) ⇒ Generator

Initialize a new Generator

Parameters:



119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/fontisan/type1/generator.rb', line 119

def initialize(font, options = {})
  @font = font
  @options = normalize_options_value(options)
  @metrics = MetricsCalculator.new(font)

  # Set up scaler
  upm_scale = @options.upm_scale || 1000
  @scaler = if upm_scale == :native
              UPMScaler.native(font)
            else
              UPMScaler.new(font, target_upm: upm_scale)
            end

  # Set up encoding
  @encoding = @options.encoding || Encodings::AdobeStandard
end

Class Method Details

.extract_base_name(font) ⇒ String

Extract base filename from font

Parameters:

Returns:

  • (String)

    Base filename



201
202
203
204
205
206
207
208
209
# File 'lib/fontisan/type1/generator.rb', line 201

def self.extract_base_name(font)
  name_table = font.table(Constants::NAME_TAG)
  if name_table.respond_to?(:postscript_name)
    name = name_table.postscript_name(1) || name_table.postscript_name(3)
    return name if name
  end

  font.post_script_name || "font"
end

.generate(font, options = {}) ⇒ Hash

Generate all Type 1 formats from a font

Parameters:

Returns:

  • (Hash)

    Generated file contents



56
57
58
59
# File 'lib/fontisan/type1/generator.rb', line 56

def self.generate(font, options = {})
  options = normalize_options(options)
  new(font, options).generate
end

.generate_to_files(font, output_dir, options = {}) ⇒ Array<String>

Generate Type 1 files and write to disk

Parameters:

Returns:

  • (Array<String>)

    Paths to generated files



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/fontisan/type1/generator.rb', line 67

def self.generate_to_files(font, output_dir, options = {})
  options = normalize_options(options)
  result = generate(font, options)

  # Ensure output directory exists
  FileUtils.mkdir_p(output_dir)

  # Get base filename from font
  base_name = extract_base_name(font)

  # Write files
  written_files = []

  # Write AFM
  if result[:afm]
    afm_path = File.join(output_dir, "#{base_name}.afm")
    File.write(afm_path, result[:afm], encoding: "ISO-8859-1")
    written_files << afm_path
  end

  # Write PFM
  if result[:pfm]
    pfm_path = File.join(output_dir, "#{base_name}.pfm")
    File.binwrite(pfm_path, result[:pfm])
    written_files << pfm_path
  end

  # Write PFB or PFA
  if result[:pfb]
    pfb_path = File.join(output_dir, "#{base_name}.pfb")
    File.binwrite(pfb_path, result[:pfb])
    written_files << pfb_path
  elsif result[:pfa]
    pfa_path = File.join(output_dir, "#{base_name}.pfa")
    File.write(pfa_path, result[:pfa])
    written_files << pfa_path
  end

  # Write INF
  if result[:inf]
    inf_path = File.join(output_dir, "#{base_name}.inf")
    File.write(inf_path, result[:inf], encoding: "ISO-8859-1")
    written_files << inf_path
  end

  written_files
end

.normalize_options(options) ⇒ ConversionOptions

Normalize options to ConversionOptions

Parameters:

Returns:



183
184
185
186
187
# File 'lib/fontisan/type1/generator.rb', line 183

def self.normalize_options(options)
  return options if options.is_a?(ConversionOptions)

  ConversionOptions.new(options)
end

Instance Method Details

#generateHash

Generate all Type 1 formats

Returns:

  • (Hash)

    Generated file contents



139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/fontisan/type1/generator.rb', line 139

def generate
  result = {}

  # Always generate AFM
  result[:afm] = AFMGenerator.generate(@font, to_hash)

  # Always generate PFM (for Windows compatibility)
  result[:pfm] = PFMGenerator.generate(@font, to_hash)

  # Generate PFB or PFA based on format option
  format = @options.format || :pfb
  if format == :pfa
    result[:pfa] = PFAGenerator.generate(@font, to_hash)
  else
    result[:pfb] = PFBGenerator.generate(@font, to_hash)
  end

  # Generate INF for Windows installation
  result[:inf] = INFGenerator.generate(@font, to_hash)

  result
end