Class: Fontisan::Commands::ConvertCommand

Inherits:
BaseCommand
  • Object
show all
Defined in:
lib/fontisan/commands/convert_command.rb

Overview

Command for converting fonts between formats

[‘ConvertCommand`](lib/fontisan/commands/convert_command.rb) provides CLI interface for font format conversion operations using the universal transformation pipeline. It supports:

  • Same-format operations (copy/optimize)

  • TTF ↔ OTF outline format conversion

  • Variable font operations (preserve/instance generation)

  • WOFF/WOFF2 compression

The command uses [‘TransformationPipeline`](lib/fontisan/pipeline/transformation_pipeline.rb) to orchestrate conversions with appropriate strategies.

Examples:

Convert TTF to OTF

command = ConvertCommand.new(
  'input.ttf',
  to: 'otf',
  output: 'output.otf'
)
command.run

Generate instance at coordinates

command = ConvertCommand.new(
  'variable.ttf',
  to: 'ttf',
  output: 'bold.ttf',
  coordinates: 'wght=700,wdth=100'
)
command.run

Instance Method Summary collapse

Constructor Details

#initialize(font_path, options = {}) ⇒ ConvertCommand

Initialize convert command

Parameters:

  • font_path (String)

    Path to input font file

  • options (Hash) (defaults to: {})

    Conversion options

Options Hash (options):

  • :to (String)

    Target format (ttf, otf, woff, woff2)

  • :output (String)

    Output file path (required)

  • :font_index (Integer)

    Index for TTC/OTC (default: 0)

  • :coordinates (String)

    Coordinate string (e.g., “wght=700,wdth=100”)

  • :instance_coordinates (Hash)

    Axis coordinates hash (e.g., => 700.0)

  • :instance_index (Integer)

    Named instance index

  • :preserve_variation (Boolean)

    Preserve variation data (default: auto)

  • :preserve_hints (Boolean)

    Preserve rendering hints (default: false)

  • :no_validate (Boolean)

    Skip output validation

  • :verbose (Boolean)

    Verbose output



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/fontisan/commands/convert_command.rb', line 52

def initialize(font_path, options = {})
  super(font_path, options)

  # Convert string keys to symbols for Thor compatibility
  opts = options.transform_keys(&:to_sym)

  @output_path = opts[:output]

  # Parse target format
  @target_format = parse_target_format(opts[:to])

  # Parse coordinates if string provided
  @coordinates = if opts[:coordinates]
                   parse_coordinates(opts[:coordinates])
                 elsif opts[:instance_coordinates]
                   opts[:instance_coordinates]
                 end

  @instance_index = opts[:instance_index]
  @preserve_variation = opts[:preserve_variation]
  @preserve_hints = opts.fetch(:preserve_hints, false)
  @validate = !opts[:no_validate]
end

Instance Method Details

#runHash

Execute the conversion

Returns:

  • (Hash)

    Result information

Raises:

  • (ArgumentError)

    If output path is not specified

  • (Error)

    If conversion fails



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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/fontisan/commands/convert_command.rb', line 81

def run
  validate_options!

  puts "Converting #{File.basename(font_path)} to #{@target_format}..." unless @options[:quiet]

  # Build pipeline options
  pipeline_options = {
    target_format: @target_format,
    validate: @validate,
    verbose: @options[:verbose],
  }

  # Add variation options if specified
  pipeline_options[:coordinates] = @coordinates if @coordinates
  pipeline_options[:instance_index] = @instance_index if @instance_index
  unless @preserve_variation.nil?
    pipeline_options[:preserve_variation] =
      @preserve_variation
  end

  # Add hint preservation option
  pipeline_options[:preserve_hints] = @preserve_hints if @preserve_hints

  # Use TransformationPipeline for universal conversion
  pipeline = Pipeline::TransformationPipeline.new(
    font_path,
    @output_path,
    pipeline_options,
  )

  result = pipeline.transform

  # Display results
  unless @options[:quiet]
    output_size = File.size(@output_path)
    input_size = File.size(font_path)

    puts "Conversion complete!"
    puts "  Input:  #{font_path} (#{format_size(input_size)})"
    puts "  Output: #{@output_path} (#{format_size(output_size)})"
    puts "  Format: #{result[:details][:source_format]}#{result[:details][:target_format]}"

    if result[:details][:variation_preserved]
      puts "  Variation: Preserved (#{result[:details][:variation_strategy]})"
    elsif result[:details][:variation_strategy] != :preserve
      puts "  Variation: Instance generated (#{result[:details][:variation_strategy]})"
    end
  end

  {
    success: true,
    input_path: font_path,
    output_path: @output_path,
    source_format: result[:details][:source_format],
    target_format: result[:details][:target_format],
    input_size: File.size(font_path),
    output_size: File.size(@output_path),
    variation_strategy: result[:details][:variation_strategy],
  }
rescue ArgumentError
  # Let ArgumentError propagate for validation errors
  raise
rescue StandardError => e
  raise Error, "Conversion failed: #{e.message}"
end