Class: Fontisan::Hints::HintConverter

Inherits:
Object
  • Object
show all
Defined in:
lib/fontisan/hints/hint_converter.rb

Overview

Converts hints between TrueType and PostScript formats

This converter handles bidirectional conversion of rendering hints, translating between TrueType instruction-based hinting and PostScript operator-based hinting while preserving intent where possible.

Conversion Strategy:

  • TrueType → PostScript: Extract semantic meaning from instructions and convert to corresponding PostScript operators
  • PostScript → TrueType: Analyze hint operators and generate equivalent TrueType instructions

Examples:

Convert TrueType hints to PostScript

converter = HintConverter.new
ps_hints = converter.to_postscript(tt_hints)

Convert PostScript hints to TrueType

converter = HintConverter.new
tt_hints = converter.to_truetype(ps_hints)

Instance Method Summary collapse

Instance Method Details

#convert_hint_set(hint_set, target_format) ⇒ Models::HintSet

Convert entire HintSet between formats

Parameters:

  • hint_set (Models::HintSet)

    Source hint set

  • target_format (Symbol)

    Target format (:truetype or :postscript)

Returns:



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/hints/hint_converter.rb', line 75

def convert_hint_set(hint_set, target_format)
  return hint_set if hint_set.format == target_format.to_s

  result = Models::HintSet.new(format: target_format.to_s)

  case target_format
  when :postscript
    # Convert font-level TT → PS
    if hint_set.font_program || hint_set.control_value_program ||
        hint_set.control_values&.any?
      ps_dict = convert_tt_programs_to_ps_dict(
        hint_set.font_program,
        hint_set.control_value_program,
        hint_set.control_values,
      )
      result.private_dict_hints = ps_dict.to_json
    end

    # Convert per-glyph hints
    hint_set.hinted_glyph_ids.each do |glyph_id|
      glyph_hints = hint_set.get_glyph_hints(glyph_id)
      ps_hints = to_postscript(glyph_hints)
      result.add_glyph_hints(glyph_id, ps_hints) unless ps_hints.empty?
    end

  when :truetype
    # Convert font-level PS → TT
    if hint_set.private_dict_hints && hint_set.private_dict_hints != "{}"
      tt_programs = convert_ps_dict_to_tt_programs(
        JSON.parse(hint_set.private_dict_hints),
      )
      result.font_program = tt_programs[:fpgm]
      result.control_value_program = tt_programs[:prep]
      result.control_values = tt_programs[:cvt]
    end

    # Convert per-glyph hints
    hint_set.hinted_glyph_ids.each do |glyph_id|
      glyph_hints = hint_set.get_glyph_hints(glyph_id)
      tt_hints = to_truetype(glyph_hints)
      result.add_glyph_hints(glyph_id, tt_hints) unless tt_hints.empty?
    end
  end

  result.has_hints = !result.empty?
  result
end

#optimize(hints) ⇒ Array<Hint>

Optimize hint set by removing redundant hints

Parameters:

  • hints (Array<Hint>)

    Hints to optimize

Returns:

  • (Array<Hint>)

    Optimized hints



60
61
62
63
64
65
66
67
68
# File 'lib/fontisan/hints/hint_converter.rb', line 60

def optimize(hints)
  return [] if hints.nil? || hints.empty?

  # Remove duplicate hints
  unique_hints = hints.uniq { |h| [h.type, h.data] }

  # Remove conflicting hints (keep first)
  remove_conflicts(unique_hints)
end

#to_postscript(hints) ⇒ Array<Hint>

Convert hints to PostScript format

Parameters:

  • hints (Array<Hint>)

    Source hints (any format)

Returns:

  • (Array<Hint>)

    Hints in PostScript format



32
33
34
35
36
37
38
39
40
# File 'lib/fontisan/hints/hint_converter.rb', line 32

def to_postscript(hints)
  return [] if hints.nil? || hints.empty?

  hints.map do |hint|
    next hint if hint.source_format == :postscript

    convert_hint_to_postscript(hint)
  end.compact
end

#to_truetype(hints) ⇒ Array<Hint>

Convert hints to TrueType format

Parameters:

  • hints (Array<Hint>)

    Source hints (any format)

Returns:

  • (Array<Hint>)

    Hints in TrueType format



46
47
48
49
50
51
52
53
54
# File 'lib/fontisan/hints/hint_converter.rb', line 46

def to_truetype(hints)
  return [] if hints.nil? || hints.empty?

  hints.map do |hint|
    next hint if hint.source_format == :truetype

    convert_hint_to_truetype(hint)
  end.compact
end