Class: Fontisan::Type1::CharStringConverter
- Inherits:
-
Object
- Object
- Fontisan::Type1::CharStringConverter
- Defined in:
- lib/fontisan/type1/charstring_converter.rb
Overview
Converter for Type 1 CharStrings to CFF CharStrings
[‘CharStringConverter`](lib/fontisan/type1/charstring_converter.rb) converts Type 1 CharString bytecode to CFF (Compact Font Format) CharString bytecode.
Type 1 and CFF use similar stack-based languages but have different operator codes and some structural differences:
-
Operator codes differ between formats
-
Type 1 has seac operator for composites; CFF doesn’t support it
-
Hint operators need to be preserved with code translation
Constant Summary collapse
- TYPE1_TO_CFF =
Type 1 to CFF operator mapping
Maps Type 1 operator codes to CFF operator codes. Some operators have the same code, others differ.
{ # Path construction operators hmoveto: 22, # Type 1: 22, CFF: 22 vmoveto: 4, # Type 1: 4, CFF: 4 rlineto: 5, # Type 1: 5, CFF: 5 hlineto: 6, # Type 1: 6, CFF: 6 vlineto: 7, # Type 1: 7, CFF: 7 rrcurveto: 8, # Type 1: 8, CFF: 8 hhcurveto: 27, # Type 1: 27, CFF: 27 hvcurveto: 31, # Type 1: 31, CFF: 31 vhcurveto: 30, # Type 1: 30, CFF: 30 rcurveline: 24, # Type 1: 24, CFF: 24 rlinecurve: 25, # Type 1: 25, CFF: 25 # Hint operators hstem: 1, # Type 1: 1, CFF: 1 vstem: 3, # Type 1: 3, CFF: 3 hstemhm: 18, # Type 1: 18, CFF: 18 vstemhm: 23, # Type 1: 23, CFF: 23 # Hint substitution (not in Type 1, but we preserve for compatibility) hintmask: 19, # Type 1: N/A, CFF: 19 cntrmask: 20, # Type 1: N/A, CFF: 20 # End char endchar: 14, # Type 1: 14 (or 11 in some specs), CFF: 14 # Miscellaneous callsubr: 10, # Type 1: 10, CFF: 10 return: 11, # Type 1: 11, CFF: 11 # Deprecated operators (preserve for compatibility) hstem3: 12, # Type 1: 12 (escape 0), CFF: 12 (escape 0) vstem3: 13, # Type 1: 13 (escape 1), CFF: 13 (escape 1) seac: 12, # Type 1: 12 (escape 6), CFF: Not supported }.freeze
- ESCAPE_BYTE =
Escape code for two-byte operators
12- SEAC_ESCAPE_CODE =
seac operator escape code (second byte)
6
Instance Method Summary collapse
-
#convert(type1_charstring) ⇒ String
Convert Type 1 CharString to CFF CharString.
-
#convert_commands(commands) ⇒ String
Convert parsed commands to CFF CharString.
-
#expand_seac(seac_data) ⇒ String
Expand seac composite glyph.
-
#initialize(charstrings = nil) ⇒ CharStringConverter
constructor
Initialize a new CharStringConverter.
-
#seac?(type1_charstring) ⇒ Boolean
Check if CharString contains seac operator.
Constructor Details
#initialize(charstrings = nil) ⇒ CharStringConverter
Initialize a new CharStringConverter
73 74 75 |
# File 'lib/fontisan/type1/charstring_converter.rb', line 73 def initialize(charstrings = nil) @charstrings = charstrings end |
Instance Method Details
#convert(type1_charstring) ⇒ String
Convert Type 1 CharString to CFF CharString
85 86 87 88 89 90 91 92 93 94 95 96 97 |
# File 'lib/fontisan/type1/charstring_converter.rb', line 85 def convert(type1_charstring) # Parse Type 1 CharString into commands parser = Type1::CharStrings::CharStringParser.new commands = parser.parse(type1_charstring) # Check for seac operator and expand if needed if parser.seac_components return (parser.seac_components) end # Convert commands to CFF format convert_commands(commands) end |
#convert_commands(commands) ⇒ String
Convert parsed commands to CFF CharString
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/fontisan/type1/charstring_converter.rb', line 103 def convert_commands(commands) result = String.new(encoding: Encoding::ASCII_8BIT) commands.each do |command| case command[0] when :number # Encode number in CFF format result << encode_cff_number(command[1]) when :seac # seac should be expanded before this point raise Fontisan::Error, "seac operator not supported in CFF, must be expanded first" else # Convert operator op_code = TYPE1_TO_CFF[command[0]] if op_code.nil? # Unknown operator, skip or raise error next end result << encode_cff_operator(op_code) end end result end |
#expand_seac(seac_data) ⇒ String
Expand seac composite glyph
The seac operator in Type 1 creates composite glyphs (like À = A + ‘). CFF doesn’t support seac, so we need to expand it into the base glyphs with appropriate positioning.
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
# File 'lib/fontisan/type1/charstring_converter.rb', line 138 def (seac_data) # seac format: adx ady bchar achar seac # adx, ady: accent offset # bchar: base character code # achar: accent character code # The accent is positioned at (adx, ady) relative to the base seac_data[:base] seac_data[:accent] seac_data[:adx] seac_data[:ady] # For now, we'll create a simple placeholder that indicates seac expansion # In a full implementation, we would: # 1. Parse the base glyph's CharString # 2. Parse the accent glyph's CharString # 3. Merge them with the appropriate offset # 4. Convert to CFF format # This is a simplified implementation that creates a composite reference # CFF doesn't have native seac, so we need to actually merge the outlines # For now, return endchar as placeholder # TODO: Implement full seac expansion by merging glyph outlines encode_cff_operator(TYPE1_TO_CFF[:endchar]) end |
#seac?(type1_charstring) ⇒ Boolean
Check if CharString contains seac operator
169 170 171 172 173 |
# File 'lib/fontisan/type1/charstring_converter.rb', line 169 def seac?(type1_charstring) parser = Type1::CharStrings::CharStringParser.new parser.parse(type1_charstring) !parser.seac_components.nil? end |