Class: Fontisan::Type1::CharStrings

Inherits:
Object
  • Object
show all
Defined in:
lib/fontisan/type1/charstrings.rb

Overview

Type 1 CharStrings parser

CharStrings parses and stores the CharStrings dictionary from a Type 1 font, which contains glyph outline descriptions.

CharStrings in Type 1 fonts use a stack-based language with commands for drawing curves, lines, and composite glyphs (via the seac operator).

Examples:

Parse CharStrings from decrypted font data

charstrings = Fontisan::Type1::CharStrings.parse(decrypted_data, private_dict)
outline = charstrings.outline_for("A")

See Also:

Defined Under Namespace

Classes: CharStringParser

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(private_dict = nil) ⇒ CharStrings

Initialize a new CharStrings parser

Parameters:

  • private_dict (PrivateDict, nil) (defaults to: nil)

    Private dictionary for lenIV



42
43
44
45
46
# File 'lib/fontisan/type1/charstrings.rb', line 42

def initialize(private_dict = nil)
  @private_dict = private_dict || PrivateDict.new
  @charstrings = {}
  @encoding_override = nil
end

Instance Attribute Details

#charstringsHash (readonly)

Returns Glyph name to CharString data mapping.

Returns:

  • (Hash)

    Glyph name to CharString data mapping



21
22
23
# File 'lib/fontisan/type1/charstrings.rb', line 21

def charstrings
  @charstrings
end

#private_dictPrivateDict (readonly)

Returns Private dictionary for decryption.

Returns:



24
25
26
# File 'lib/fontisan/type1/charstrings.rb', line 24

def private_dict
  @private_dict
end

Class Method Details

.from_hash(charstrings_hash, encoding: nil, private_dict: nil) ⇒ CharStrings

Build a CharStrings from a pre-built glyph-name → charstring-bytecode hash. Useful for constructing test fixtures without parsing a full Type 1 font. Optionally accepts encoding: to override the default Adobe Standard Encoding (char code → glyph name).

Parameters:

  • charstrings_hash (Hash{String=>String})
  • encoding (Hash{Integer=>String}, nil) (defaults to: nil)
  • private_dict (PrivateDict, nil) (defaults to: nil)

Returns:



57
58
59
60
61
62
# File 'lib/fontisan/type1/charstrings.rb', line 57

def self.from_hash(charstrings_hash, encoding: nil, private_dict: nil)
  cs = new(private_dict)
  charstrings_hash.each { |name, data| cs.register(name, data) }
  cs.set_encoding(encoding) if encoding
  cs
end

.parse(data, private_dict = nil) ⇒ CharStrings

Parse CharStrings dictionary from decrypted Type 1 font data

Examples:

Parse from decrypted font data

charstrings = Fontisan::Type1::CharStrings.parse(decrypted_data, private_dict)

Parameters:

  • data (String)

    Decrypted Type 1 font data

  • private_dict (PrivateDict) (defaults to: nil)

    Private dictionary for lenIV

Returns:

Raises:



35
36
37
# File 'lib/fontisan/type1/charstrings.rb', line 35

def self.parse(data, private_dict = nil)
  new(private_dict).parse(data)
end

Instance Method Details

#[](glyph_name) ⇒ String?

Get CharString data for glyph

Parameters:

  • glyph_name (String)

    Glyph name

Returns:

  • (String, nil)

    CharString data or nil if not found



133
134
135
# File 'lib/fontisan/type1/charstrings.rb', line 133

def [](glyph_name)
  @charstrings[glyph_name]
end

#charstring(glyph_name) ⇒ String?

Alias for #[]

Parameters:

  • glyph_name (String)

    Glyph name

Returns:

  • (String, nil)

    CharString data or nil if not found



141
142
143
# File 'lib/fontisan/type1/charstrings.rb', line 141

def charstring(glyph_name)
  @charstrings[glyph_name]
end

#components_for(glyph_name) ⇒ Hash?

Get components for composite glyph

Parameters:

  • glyph_name (String)

    Glyph name

Returns:

  • (Hash, nil)

    Component info :accent or nil



174
175
176
177
178
179
180
181
182
# File 'lib/fontisan/type1/charstrings.rb', line 174

def components_for(glyph_name)
  return nil unless composite?(glyph_name)

  charstring = @charstrings[glyph_name]
  parser = CharStringParser.new(@private_dict)
  parser.parse(charstring)

  parser.seac_components
end

#composite?(glyph_name) ⇒ Boolean

Check if glyph is composite (uses seac)

Parameters:

  • glyph_name (String)

    Glyph name

Returns:

  • (Boolean)

    True if glyph uses seac operator



163
164
165
166
167
168
# File 'lib/fontisan/type1/charstrings.rb', line 163

def composite?(glyph_name)
  charstring = @charstrings[glyph_name]
  return false if charstring.nil?

  charstring.include?(SEAC_OPCODE)
end

#countInteger

Get the number of charstrings

Returns:

  • (Integer)

    Number of charstrings



100
101
102
# File 'lib/fontisan/type1/charstrings.rb', line 100

def count
  @charstrings.size
end

#each_charstring {|glyph_name, charstring_data| ... } ⇒ Enumerator

Iterate over all charstrings

Yields:

  • (glyph_name, charstring_data)

    Each glyph name and its charstring data

Returns:

  • (Enumerator)

    If no block given



115
116
117
118
119
# File 'lib/fontisan/type1/charstrings.rb', line 115

def each_charstring(&)
  return enum_for(:each_charstring) unless block_given?

  @charstrings.each(&)
end

#encodingHash

Get encoding map

Returns:

  • (Hash)

    Character code to glyph name mapping



107
108
109
# File 'lib/fontisan/type1/charstrings.rb', line 107

def encoding
  @encoding_override || (@encoding ||= build_standard_encoding)
end

#glyph_namesArray<String>

Get list of glyph names

Returns:

  • (Array<String>)

    Glyph names



93
94
95
# File 'lib/fontisan/type1/charstrings.rb', line 93

def glyph_names
  @charstrings.keys
end

#has_glyph?(glyph_name) ⇒ Boolean

Check if glyph exists

Parameters:

  • glyph_name (String)

    Glyph name

Returns:

  • (Boolean)

    True if glyph exists



125
126
127
# File 'lib/fontisan/type1/charstrings.rb', line 125

def has_glyph?(glyph_name)
  @charstrings.key?(glyph_name)
end

#outline_for(glyph_name) ⇒ Array

Get outline for glyph by name

Parses the CharString and returns outline commands.

Parameters:

  • glyph_name (String)

    Glyph name

Returns:

  • (Array)

    Outline commands



151
152
153
154
155
156
157
# File 'lib/fontisan/type1/charstrings.rb', line 151

def outline_for(glyph_name)
  charstring = @charstrings[glyph_name]
  return nil if charstring.nil?

  parser = CharStringParser.new(@private_dict)
  parser.parse(charstring)
end

#parse(data) ⇒ CharStrings

Parse CharStrings dictionary from decrypted Type 1 font data

Parameters:

  • data (String)

    Decrypted Type 1 font data

Returns:



84
85
86
87
88
# File 'lib/fontisan/type1/charstrings.rb', line 84

def parse(data)
  extract_charstrings(data)
  decrypt_charstrings
  self
end

#register(glyph_name, charstring_data) ⇒ Object

Register (or replace) a glyph's charstring data.

Parameters:

  • glyph_name (String)
  • charstring_data (String)

    binary charstring bytecode



68
69
70
# File 'lib/fontisan/type1/charstrings.rb', line 68

def register(glyph_name, charstring_data)
  @charstrings[glyph_name] = charstring_data
end

#set_encoding(encoding) ⇒ Object

Override the default Adobe Standard Encoding with a custom char_code → glyph_name map.

Parameters:

  • encoding (Hash{Integer=>String})


76
77
78
# File 'lib/fontisan/type1/charstrings.rb', line 76

def set_encoding(encoding)
  @encoding_override = encoding
end