Module: Fontisan::Ufo::Convert::FromBinData

Defined in:
lib/fontisan/ufo/convert/from_bin_data.rb

Overview

Converts a loaded TTF/OTF font (from Fontisan::FontLoader.load) into a typed Fontisan::Ufo::Font. This is the reverse of Compile::TtfCompiler / Compile::OtfCompiler.

Reads each BinData table, extracts per-glyph data, and builds Ufo::Glyph objects in the default layer.

Composite (compound) glyphs are decomposed into contours — each component's base glyph is resolved recursively, the 2×3 affine transform is applied, and the transformed points are merged as contours on the UFO glyph. This makes the glyph self-contained (no dependency on component glyphs being present in the output).

Constant Summary collapse

MAX_COMPOUND_DEPTH =

Compound (composite) glyph: recursively flatten into UFO contours. Mirrors Stitcher::Source#flatten_compound_into — resolves each component's base glyph, applies the 2x3 affine transform, and merges the result as contours on the UFO glyph.

32

Class Method Summary collapse

Class Method Details

.convert(font) ⇒ Fontisan::Ufo::Font

Returns typed UFO model.

Parameters:

Returns:



21
22
23
24
25
26
27
28
# File 'lib/fontisan/ufo/convert/from_bin_data.rb', line 21

def self.convert(font)
  ufo = Ufo::Font.new
  ufo.ufo_version = 3

  extract_info(font, ufo)
  extract_glyphs(font, ufo)
  ufo
end

.convert_cff_path_to_ufo(path, glyph) ⇒ Object

Convert a CFF CharString path (array of command hashes) to UFO contours. Each :move_to starts a new contour; :line_to and :curve_to append points to the current contour. Cubic bezier curves produce 2 offcurve + 1 curve points per segment (GLIF convention).



258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
# File 'lib/fontisan/ufo/convert/from_bin_data.rb', line 258

def self.convert_cff_path_to_ufo(path, glyph)
  return if path.empty?

  current_contour = nil

  path.each do |cmd|
    case cmd[:type]
    when :move_to
      glyph.add_contour(current_contour) if current_contour
      current_contour = Ufo::Contour.new
      current_contour.points << Ufo::Point.new(
        x: cmd[:x].to_i, y: cmd[:y].to_i, type: "move",
      )
    when :line_to
      next unless current_contour

      current_contour.points << Ufo::Point.new(
        x: cmd[:x].to_i, y: cmd[:y].to_i, type: "line",
      )
    when :curve_to
      next unless current_contour

      current_contour.points << Ufo::Point.new(
        x: cmd[:x1].to_i, y: cmd[:y1].to_i, type: "offcurve",
      )
      current_contour.points << Ufo::Point.new(
        x: cmd[:x2].to_i, y: cmd[:y2].to_i, type: "offcurve",
      )
      current_contour.points << Ufo::Point.new(
        x: cmd[:x].to_i, y: cmd[:y].to_i, type: "curve",
      )
    end
  end

  glyph.add_contour(current_contour) if current_contour
end

.extract_cff_glyphs_stub(font, ufo, cmap, widths, num_glyphs) ⇒ Object

Fallback: widths only, no contours (used when CFF table can't be parsed — e.g., corrupted or unsupported variant).



243
244
245
246
247
248
249
250
251
# File 'lib/fontisan/ufo/convert/from_bin_data.rb', line 243

def self.extract_cff_glyphs_stub(font, ufo, cmap, widths, num_glyphs)
  num_glyphs.times do |gid|
    glyph_name = glyph_name_for(font, gid) || "gid#{gid}"
    ufo_glyph = Ufo::Glyph.new(name: glyph_name)
    ufo_glyph.width = widths.fetch(gid, 0).to_f
    cmap.fetch(gid, []).each { |cp| ufo_glyph.add_unicode(cp) }
    ufo.layers.default_layer.add(ufo_glyph)
  end
end