Class: Fontisan::Tables::Cff::DictBuilder

Inherits:
Object
  • Object
show all
Defined in:
lib/fontisan/tables/cff/dict_builder.rb

Overview

CFF DICT (Dictionary) structure builder

[‘DictBuilder`](lib/fontisan/tables/cff/dict_builder.rb) constructs binary DICT structures from hash representations. DICTs in CFF use a compact operand-operator format similar to PostScript.

The builder encodes operands in various compact formats and writes operators according to the CFF specification.

Operand Encoding:

  • Small integers (-107 to +107): Single byte (32-246)

  • Medium integers (108 to 1131): Two bytes (247-250 + byte)

  • Medium integers (-1131 to -108): Two bytes (251-254 + byte)

  • Larger integers: Three bytes (28 + 2 bytes) or five bytes (29 + 4 bytes)

  • Real numbers: Nibble-encoded (30 + nibbles + 0xF terminator)

Operators:

  • Single-byte: 0-21

  • Two-byte: 12 followed by second byte

Reference: CFF specification section 4 “DICT Data” adobe-type-tools.github.io/font-tech-notes/pdfs/5176.CFF.pdf

Examples:

Building a DICT

dict_hash = { version: 391, notice: 392, charset: 0 }
dict_data = Fontisan::Tables::Cff::DictBuilder.build(dict_hash)

Constant Summary collapse

OPERATORS =

Operator mapping (name => byte(s))

{
  version: 0,
  notice: 1,
  full_name: 2,
  family_name: 3,
  weight: 4,
  charset: 15,
  encoding: 16,
  charstrings: 17,
  private: 18,
  copyright: [12, 0],
  is_fixed_pitch: [12, 1],
  italic_angle: [12, 2],
  underline_position: [12, 3],
  underline_thickness: [12, 4],
  paint_type: [12, 5],
  charstring_type: [12, 6],
  font_matrix: [12, 7],
  stroke_width: [12, 8],
  font_bbox: 5,
  synthetic_base: [12, 20],
  postscript: [12, 21],
  base_font_name: [12, 22],
  base_font_blend: [12, 23],
  # Private DICT operators
  subrs: 19,
  default_width_x: 20,
  nominal_width_x: 21,
  # Hint-related Private DICT operators
  blue_values: 6,
  other_blues: 7,
  family_blues: 8,
  family_other_blues: 9,
  std_hw: 10,
  std_vw: 11,
  stem_snap_h: [12, 12],
  stem_snap_v: [12, 13],
  blue_scale: [12, 9],
  blue_shift: [12, 10],
  blue_fuzz: [12, 11],
  force_bold: [12, 14],
  language_group: [12, 17],
}.freeze

Class Method Summary collapse

Class Method Details

.build(dict_hash) ⇒ String

Build DICT structure from hash

Parameters:

  • dict_hash (Hash)

    Hash of operator => value pairs

Returns:

  • (String)

    Binary DICT data

Raises:

  • (ArgumentError)

    If dict_hash is invalid



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
# File 'lib/fontisan/tables/cff/dict_builder.rb', line 85

def self.build(dict_hash)
  validate_dict!(dict_hash)

  return "".b if dict_hash.empty?

  output = StringIO.new("".b)

  # Encode each operator with its operands
  dict_hash.each do |operator_name, value|
    # Get operator bytes
    operator_bytes = operator_for_name(operator_name)
    unless operator_bytes
      raise ArgumentError,
            "Unknown operator: #{operator_name}"
    end

    # Write operands (value can be single value or array)
    if value.is_a?(Array)
      value.each { |v| write_operand(output, v) }
    else
      write_operand(output, value)
    end

    # Write operator
    write_operator(output, operator_bytes)
  end

  output.string
end