Class: Fontisan::Type1::Generator

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

Overview

Unified Type 1 font generator

[‘Generator`](lib/fontisan/type1/generator.rb) 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:



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/fontisan/type1/generator.rb', line 127

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



209
210
211
212
213
214
215
216
217
# File 'lib/fontisan/type1/generator.rb', line 209

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



64
65
66
67
# File 'lib/fontisan/type1/generator.rb', line 64

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



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
114
115
116
117
118
119
120
121
# File 'lib/fontisan/type1/generator.rb', line 75

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:



191
192
193
194
195
# File 'lib/fontisan/type1/generator.rb', line 191

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



147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/fontisan/type1/generator.rb', line 147

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