Class: Fontisan::Converters::Woff2Encoder

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

Overview

WOFF2 encoder conversion strategy

Woff2Encoder 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. Apply WOFF2 spec encoder rules (drop DSIG, mark head.flags)
  5. Transform tables (placeholder for glyf/loca/hmtx optimization)
  6. Compress all tables with single Brotli stream
  7. Build WOFF2 header and table directory
  8. Assemble complete WOFF2 binary

Examples:

Convert TTF to WOFF2

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

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from ConversionStrategy

included, #supports?

Constructor Details

#initialize(config_path: nil) ⇒ Woff2Encoder

Initialize encoder with configuration.

The encoder is stateless per call; all conversion knobs come through the per-convert options hash. The config file supplies default values only for fields not expressed via the DSL.

Parameters:

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

    Path to config file



41
42
43
# File 'lib/fontisan/converters/woff2_encoder.rb', line 41

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

Instance Attribute Details

#configHash (readonly)

Returns Configuration settings.

Returns:

  • (Hash)

    Configuration settings



32
33
34
# File 'lib/fontisan/converters/woff2_encoder.rb', line 32

def config
  @config
end

Instance Method Details

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

Convert font to WOFF2 format.

Parameters:

  • font (TrueTypeFont, OpenTypeFont)

    Source font

  • options (Hash{Symbol => Object}) (defaults to: {})

    Per-call options:

    • :brotli_quality (0–11, default from config or 11)
    • :transform_tables (bool, default false; glyf/loca are always transformed per WOFF2 spec section 5.3 regardless of this flag)
    • :quality — legacy alias for :brotli_quality (backward compat)

Returns:

  • (Hash{Symbol => String})

    { woff2_binary: <bytes> }

Raises:

  • (ArgumentError)

    if any option fails validation

  • (Fontisan::Error)

    if encoding fails



63
64
65
66
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
# File 'lib/fontisan/converters/woff2_encoder.rb', line 63

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

  resolved = normalize_legacy_quality(options)
  self.class.validate_options!(strategy_options(resolved))

  quality = resolved.fetch(:brotli_quality) do
    config["brotli"]["quality"]
  end

  flavor = detect_flavor(font)
  table_data = collect_tables(font, options)
  Woff2::EncoderRules.apply!(table_data)

  glyf_transform = apply_glyf_loca_transform!(table_data, font)

  transformer = Woff2::TableTransformer.new(font)
  transform_enabled = resolved.fetch(:transform_tables, false)
  entries, transformed_data = build_table_entries(table_data,
                                                  transformer,
                                                  transform_enabled,
                                                  glyf_transform:)

  compressed_data = compress_tables(entries, table_data,
                                    transformed_data, quality)

  total_sfnt_size = calculate_sfnt_size(table_data,
                                        glyf_transform:)
  header = build_header(
    flavor: flavor,
    num_tables: entries.size,
    total_sfnt_size: total_sfnt_size,
    total_compressed_size: compressed_data.bytesize,
  )

  { woff2_binary: assemble_woff2(header, entries, compressed_data) }
end

#supported_conversionsArray<Array<Symbol>>

Get list of supported conversions

Returns:

  • (Array<Array<Symbol>>)

    Supported conversion pairs



104
105
106
107
108
109
# File 'lib/fontisan/converters/woff2_encoder.rb', line 104

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



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/fontisan/converters/woff2_encoder.rb', line 117

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

  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

  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