Class: Fontisan::Converters::Woff2Encoder

Inherits:
Object
  • Object
show all
Includes:
ConversionStrategy, Woff2FontMemoryLoader
Defined in:
lib/fontisan/converters/woff2_encoder.rb

Overview

WOFF2 encoder conversion strategy

[‘Woff2Encoder`](lib/fontisan/converters/woff2_encoder.rb) implements the ConversionStrategy interface to convert TTF or OTF fonts to WOFF2 format with Brotli compression.

WOFF2 encoding process:

  1. Load configuration settings

  2. Determine font flavor (TTF or CFF)

  3. Collect and order tables

  4. Transform tables (placeholder for glyf/loca/hmtx optimization)

  5. Compress all tables with single Brotli stream

  6. Build WOFF2 header and table directory

  7. Assemble complete WOFF2 binary

  8. (Optional) Validate encoded WOFF2

For Phase 2 Milestone 2.1:

  • Basic WOFF2 structure generation

  • Brotli compression of table data

  • Valid WOFF2 files for web font delivery

  • Table transformations are architectural placeholders

Examples:

Convert TTF to WOFF2

encoder = Woff2Encoder.new
result = encoder.convert(font)
File.binwrite('font.woff2', result[:woff2_binary])

Convert with validation

encoder = Woff2Encoder.new
result = encoder.convert(font, validate: true)
puts result[:validation_report].text_summary if result[:validation_report]

Defined Under Namespace

Modules: Woff2FontMemoryLoader

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from ConversionStrategy

#supports?

Methods included from Woff2FontMemoryLoader

from_file_io

Constructor Details

#initialize(config_path: nil) ⇒ Woff2Encoder

Initialize encoder with configuration

Parameters:

  • config_path (String, nil) (defaults to: nil)

    Path to config file



56
57
58
# File 'lib/fontisan/converters/woff2_encoder.rb', line 56

def initialize(config_path: nil)
  @config = load_configuration(config_path)
end

Instance Attribute Details

#configHash (readonly)

Returns Configuration settings.

Returns:

  • (Hash)

    Configuration settings



51
52
53
# File 'lib/fontisan/converters/woff2_encoder.rb', line 51

def config
  @config
end

Instance Method Details

#convert(font, options = {}) ⇒ Hash

Convert font to WOFF2 format

Returns a hash with :woff2_binary key containing complete WOFF2 file. This is different from other converters that return table data.

Parameters:

Options Hash (options):

  • :quality (Integer)

    Brotli quality (0-11)

  • :transform_tables (Boolean)

    Apply table transformations

  • :validate (Boolean)

    Run validation after encoding

  • :validation_level (Symbol)

    Validation level (:strict, :standard, :lenient)

Returns:

  • (Hash)

    Hash with :woff2_binary and optional :validation_report keys

Raises:

  • (Error)

    If encoding fails



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
114
115
116
117
118
119
120
# File 'lib/fontisan/converters/woff2_encoder.rb', line 73

def convert(font, options = {})
  validate(font, :woff2)

  # Get Brotli quality from options or config
  quality = options[:quality] || config["brotli"]["quality"]

  # Detect font flavor
  flavor = detect_flavor(font)

  # Collect all tables
  table_data = collect_tables(font, options)

  # Transform tables (if enabled)
  transformer = Woff2::TableTransformer.new(font)
  transform_enabled = options.fetch(:transform_tables, false)

  # Build table directory entries
  entries = build_table_entries(table_data, transformer,
                                transform_enabled)

  # Compress all table data into single stream
  compressed_data = compress_tables(entries, table_data, quality)

  # Calculate sizes
  total_sfnt_size = calculate_sfnt_size(table_data)
  total_compressed_size = compressed_data.bytesize

  # Build WOFF2 header
  header = build_header(
    flavor: flavor,
    num_tables: entries.size,
    total_sfnt_size: total_sfnt_size,
    total_compressed_size: total_compressed_size,
  )

  # Assemble WOFF2 binary
  woff2_binary = assemble_woff2(header, entries, compressed_data)

  # Prepare result
  { woff2_binary: woff2_binary }

  # Optional validation
  # Temporarily disabled - will be reimplemented with new DSL framework
  # if options[:validate]
  #   validation_report = validate_encoding(woff2_binary, options)
  #   result[:validation_report] = validation_report
  # end
end

#supported_conversionsArray<Array<Symbol>>

Get list of supported conversions

Returns:

  • (Array<Array<Symbol>>)

    Supported conversion pairs



125
126
127
128
129
130
# File 'lib/fontisan/converters/woff2_encoder.rb', line 125

def supported_conversions
  [
    %i[ttf woff2],
    %i[otf woff2],
  ]
end

#validate(font, target_format) ⇒ Boolean

Validate that conversion is possible

Parameters:

Returns:

  • (Boolean)

    True if valid

Raises:

  • (Error)

    If conversion is not possible



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

def validate(font, target_format)
  unless target_format == :woff2
    raise Fontisan::Error,
          "Woff2Encoder only supports conversion to woff2, " \
          "got: #{target_format}"
  end

  # Verify font has required tables
  required_tables = %w[head hhea maxp]
  required_tables.each do |tag|
    unless font.table(tag)
      raise Fontisan::Error,
            "Font is missing required table: #{tag}"
    end
  end

  # Verify font has either glyf or CFF table
  unless font.has_table?("glyf") || font.has_table?("CFF ") || font.has_table?("CFF2")
    raise Fontisan::Error,
          "Font must have either glyf or CFF/CFF2 table"
  end

  true
end