Class: Pdfrb::Content::Parser
- Inherits:
-
Object
- Object
- Pdfrb::Content::Parser
- Defined in:
- lib/pdfrb/content/parser.rb
Overview
Groups a token stream into (operator, operands) invocations.
Reuses Source::Tokenizer for operand lexing (content streams
use the same PDF object syntax as COS values).
Each invocation is yielded as [operator_class, operands].
Constant Summary collapse
- ABBREV_TABLE =
{ BPC: :BitsPerComponent, CS: :ColorSpace, D: :Decode, DP: :DecodeParms, F: :Filter, H: :Height, IM: :ImageMask, Intent: :Intent, I: :Interpolate, W: :Width, }.freeze
- WHITESPACE_BYTE_VALUES =
[0, 9, 10, 12, 13, 32].freeze
Instance Attribute Summary collapse
-
#tokenizer ⇒ Object
readonly
Returns the value of attribute tokenizer.
Class Method Summary collapse
Instance Method Summary collapse
-
#abbrev_for(name) ⇒ Object
Map inline-image abbreviation keys to full PDF names per ISO 32000-2 §8.9.7 Table 89.
-
#each_invocation ⇒ Object
Yields (operator_class, operands) pairs.
-
#initialize(tokenizer) ⇒ Parser
constructor
A new instance of Parser.
-
#parse_inline_image ⇒ Object
Parse a BI ...
- #read_inline_image_data ⇒ Object
- #whitespace_byte?(byte) ⇒ Boolean
Constructor Details
#initialize(tokenizer) ⇒ Parser
Returns a new instance of Parser.
15 16 17 |
# File 'lib/pdfrb/content/parser.rb', line 15 def initialize(tokenizer) @tokenizer = tokenizer end |
Instance Attribute Details
#tokenizer ⇒ Object (readonly)
Returns the value of attribute tokenizer.
13 14 15 |
# File 'lib/pdfrb/content/parser.rb', line 13 def tokenizer @tokenizer end |
Class Method Details
Instance Method Details
#abbrev_for(name) ⇒ Object
Map inline-image abbreviation keys to full PDF names per ISO 32000-2 §8.9.7 Table 89.
90 91 92 |
# File 'lib/pdfrb/content/parser.rb', line 90 def abbrev_for(name) ABBREV_TABLE[name.to_sym] end |
#each_invocation ⇒ Object
Yields (operator_class, operands) pairs. Returns an Enumerator if no block.
Special-cases the BI/ID/EI inline image sequence: when BI is seen, the inline image dict + raw byte payload are read as a single InlineImage invocation rather than as discrete tokens.
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/pdfrb/content/parser.rb', line 30 def each_invocation return enum_for(:each_invocation) unless block_given? operands = [] while (tok = tokenizer.next_token) if tok.type == :keyword && tok.value == "BI" yield Pdfrb::Content::Operator::BeginInlineImage, [parse_inline_image] operands = [] next end case tok.type when :keyword op = Pdfrb::Content::Operator[tok.value] yield(op || Pdfrb::Content::Operator::Unknown, operands) if op operands = [] when :name operands << Pdfrb::Model::Cos::NameEncoding.decode(tok.value) when :integer, :real, :true, :false, :null operands << tok.value when :string, :hex_string operands << tok.value when :array_open operands << consume_array when :dict_open operands << consume_dict end end self end |
#parse_inline_image ⇒ Object
Parse a BI ... ID
Returns a Hash with :header (the key-value pairs) and :data (the raw image bytes).
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/pdfrb/content/parser.rb', line 68 def parse_inline_image header = {} # Read header pairs until we hit the ID keyword. while (tok = tokenizer.next_token) break if tok.type == :keyword && tok.value == "ID" if tok.type == :name key = abbrev_for(tok.value) || tok.value.to_sym val_tok = tokenizer.next_token header[key] = token_value(val_tok) end end # After ID, exactly one whitespace byte separates the # keyword from the data. Read raw bytes until "\nEI" or # " EI" terminator. data = read_inline_image_data { header: header, data: data } end |
#read_inline_image_data ⇒ Object
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/pdfrb/content/parser.rb', line 107 def read_inline_image_data # Skip exactly one whitespace byte after ID. tokenizer.skip_whitespace bytes = +"".b # Read until we see the "EI" marker. The marker is usually # preceded by whitespace and followed by whitespace or EOF. until tokenizer.eof? b = tokenizer.read_byte break if b.nil? bytes << b if bytes.bytesize >= 3 && whitespace_byte?(bytes.getbyte(-3)) && bytes.byteslice(-2, 2) == "EI" return bytes.byteslice(0, bytes.bytesize - 3).b end end bytes.b end |
#whitespace_byte?(byte) ⇒ Boolean
129 130 131 |
# File 'lib/pdfrb/content/parser.rb', line 129 def whitespace_byte?(byte) WHITESPACE_BYTE_VALUES.include?(byte) end |