Class: Fontisan::Tables::Cff::CharString
- Inherits:
-
Object
- Object
- Fontisan::Tables::Cff::CharString
- Defined in:
- lib/fontisan/tables/cff/charstring.rb
Overview
Type 2 CharString interpreter
CharStrings are stack-based programs that draw glyph outlines using a series of operators. They are stored in the CharStrings INDEX and contain path construction, hinting, and arithmetic operations.
Type 2 CharString Format:
-
Numbers are pushed onto an operand stack
-
Operators pop operands and execute commands
-
Path operators build the glyph outline
-
Hint operators define stem hints (can be ignored for rendering)
-
Subroutine operators allow code reuse
-
Arithmetic operators perform calculations on the stack
Path Construction Flow:
-
Optional width value (first operand if odd number before first move)
-
Initial moveto operator to start a path
-
Line/curve operators to construct the path
-
Optional closepath (implicit at endchar)
-
endchar to finish the glyph
Reference: Adobe Type 2 CharString Format adobe-type-tools.github.io/font-tech-notes/pdfs/5177.Type2.pdf
Constant Summary collapse
- OPERATORS =
Type 2 CharString operators
These operators define the behavior of the CharString interpreter
{ # Path construction operators 1 => :hstem, 3 => :vstem, 4 => :vmoveto, 5 => :rlineto, 6 => :hlineto, 7 => :vlineto, 8 => :rrcurveto, 10 => :callsubr, 11 => :return, 14 => :endchar, 18 => :hstemhm, 19 => :hintmask, 20 => :cntrmask, 21 => :rmoveto, 22 => :hmoveto, 23 => :vstemhm, 24 => :rcurveline, 25 => :rlinecurve, 26 => :vvcurveto, 27 => :hhcurveto, 28 => :shortint, 29 => :callgsubr, 30 => :vhcurveto, 31 => :hvcurveto, # 12 prefix for two-byte operators [12, 3] => :and, [12, 4] => :or, [12, 5] => :not, [12, 9] => :abs, [12, 10] => :add, [12, 11] => :sub, [12, 12] => :div, [12, 14] => :neg, [12, 15] => :eq, [12, 18] => :drop, [12, 20] => :put, [12, 21] => :get, [12, 22] => :ifelse, [12, 23] => :random, [12, 24] => :mul, [12, 26] => :sqrt, [12, 27] => :dup, [12, 28] => :exch, [12, 29] => :index, [12, 30] => :roll, [12, 34] => :hflex, [12, 35] => :flex, [12, 36] => :hflex1, [12, 37] => :flex1, }.freeze
Instance Attribute Summary collapse
-
#path ⇒ Array<Hash>
readonly
Path commands array.
-
#width ⇒ Integer?
readonly
Glyph width (nil if using default width).
-
#x ⇒ Float
readonly
Current X coordinate.
-
#y ⇒ Float
readonly
Current Y coordinate.
Instance Method Summary collapse
-
#bounding_box ⇒ Array<Float>
Calculate the bounding box of the glyph.
-
#initialize(data, private_dict, global_subrs, local_subrs = nil) ⇒ CharString
constructor
Initialize and interpret a CharString.
-
#to_commands ⇒ Array<Array>
Convert path to drawing commands.
Constructor Details
#initialize(data, private_dict, global_subrs, local_subrs = nil) ⇒ CharString
Initialize and interpret a CharString
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
# File 'lib/fontisan/tables/cff/charstring.rb', line 114 def initialize(data, private_dict, global_subrs, local_subrs = nil) @data = data @private_dict = private_dict @global_subrs = global_subrs @local_subrs = local_subrs @stack = [] @path = [] @x = 0.0 @y = 0.0 @width = nil @stems = 0 @transient_array = [] @subroutine_bias = calculate_bias(local_subrs) @global_subroutine_bias = calculate_bias(global_subrs) parse! end |
Instance Attribute Details
#path ⇒ Array<Hash> (readonly)
Returns Path commands array.
44 45 46 |
# File 'lib/fontisan/tables/cff/charstring.rb', line 44 def path @path end |
#width ⇒ Integer? (readonly)
Returns Glyph width (nil if using default width).
41 42 43 |
# File 'lib/fontisan/tables/cff/charstring.rb', line 41 def width @width end |
#x ⇒ Float (readonly)
Returns Current X coordinate.
47 48 49 |
# File 'lib/fontisan/tables/cff/charstring.rb', line 47 def x @x end |
#y ⇒ Float (readonly)
Returns Current Y coordinate.
50 51 52 |
# File 'lib/fontisan/tables/cff/charstring.rb', line 50 def y @y end |
Instance Method Details
#bounding_box ⇒ Array<Float>
Calculate the bounding box of the glyph
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/fontisan/tables/cff/charstring.rb', line 136 def bounding_box return nil if @path.empty? x_coords = [] y_coords = [] @path.each do |cmd| case cmd[:type] when :move_to, :line_to x_coords << cmd[:x] y_coords << cmd[:y] when :curve_to x_coords << cmd[:x1] << cmd[:x2] << cmd[:x] y_coords << cmd[:y1] << cmd[:y2] << cmd[:y] end end return nil if x_coords.empty? [x_coords.min, y_coords.min, x_coords.max, y_coords.max] end |
#to_commands ⇒ Array<Array>
Convert path to drawing commands
163 164 165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/fontisan/tables/cff/charstring.rb', line 163 def to_commands @path.map do |cmd| case cmd[:type] when :move_to [:move_to, cmd[:x], cmd[:y]] when :line_to [:line_to, cmd[:x], cmd[:y]] when :curve_to [:curve_to, cmd[:x1], cmd[:y1], cmd[:x2], cmd[:y2], cmd[:x], cmd[:y]] end end end |