Class: HexaPDF::Stream

Inherits:
Dictionary show all
Defined in:
lib/hexapdf/stream.rb

Overview

Implements Stream objects of the PDF object system.

Stream Objects

A stream may also be associated with a PDF object but only if the value is a PDF dictionary. This associated dictionary further describes the stream, like its length or how it is encoded.

Such a stream object in PDF contains string data but of possibly unlimited length. Therefore it is used for large amounts of data like images, page descriptions or embedded files.

The basic Object class cannot hold stream data, only this subclass contains the necessary methods to conveniently work with the stream data!

See: PDF1.7 s7.3.8, Dictionary

Constant Summary

Constants included from DictionaryFields

DictionaryFields::Boolean, DictionaryFields::PDFByteString, DictionaryFields::PDFDate

Constants inherited from Object

Object::NOT_DUPLICATABLE_CLASSES

Instance Attribute Summary

Attributes inherited from Object

#data, #document, #must_be_indirect

Instance Method Summary collapse

Methods inherited from Dictionary

#[], #[]=, define_field, #delete, #each, each_field, #empty?, field, #key?, #to_hash, #type

Methods inherited from Object

#<=>, #==, #deep_copy, deep_copy, #document?, #eql?, #gen, #gen=, #hash, #indirect?, #initialize, #inspect, #null?, #oid, #oid=, #type, #validate, #value, #value=

Constructor Details

This class inherits a constructor from HexaPDF::Object

Instance Method Details

#must_be_indirect?Boolean

Stream objects must always be indirect.

Returns:



126
127
128
# File 'lib/hexapdf/stream.rb', line 126

def must_be_indirect?
  true
end

#raw_streamObject

Returns the raw stream object.

The returned value can be of many different types (see #stream=). For working with the decoded stream contents use #stream.



156
157
158
# File 'lib/hexapdf/stream.rb', line 156

def raw_stream
  data.stream
end

#set_filter(filter, decode_parms = nil) ⇒ Object

Sets the filters that should be used for encoding the stream.

The arguments filter as well as decode_parms can either be a single items or arrays.

The filters have to be specified in the *decoding order*! For example, if the filters would be [:A85, :Fl], the stream would first be encoded with the Flate and then with the ASCII85 filter.



223
224
225
226
227
228
229
230
231
232
233
234
235
# File 'lib/hexapdf/stream.rb', line 223

def set_filter(filter, decode_parms = nil)
  if filter.nil? || (filter.kind_of?(Array) && filter.empty?)
    delete(:Filter)
  else
    self[:Filter] = filter
  end
  if decode_parms.nil? || (decode_parms.kind_of?(Array) && decode_parms.empty?) ||
      !key?(:Filter)
    delete(:DecodeParms)
  else
    self[:DecodeParms] = decode_parms
  end
end

#streamObject

Returns the (possibly decoded) stream data as string.

Note that modifications done to the returned string are not reflected in the Stream object itself. The modified string must explicitly be assigned via #stream= to take effect.



144
145
146
147
148
149
150
# File 'lib/hexapdf/stream.rb', line 144

def stream
  if data.stream.kind_of?(String)
    data.stream.dup
  else
    HexaPDF::Filter.string_from_source(stream_decoder)
  end
end

#stream=(stream) ⇒ Object

Assigns a new stream data object.

The stream argument can be a HexaPDF::StreamData object, a String object or nil.

If stream is nil, an empty binary string is used instead.



135
136
137
138
# File 'lib/hexapdf/stream.rb', line 135

def stream=(stream)
  data.stream = stream
  after_data_change
end

#stream_decoderObject

Returns the decoder Fiber for the stream data.

See the Filter module for more information on how to work with the fiber.



172
173
174
175
176
177
178
179
180
181
182
# File 'lib/hexapdf/stream.rb', line 172

def stream_decoder
  source = stream_source

  if data.stream.kind_of?(StreamData)
    data.stream.filter.zip(data.stream.decode_parms) do |filter, decode_parms|
      source = filter_for_name(filter).decoder(source, decode_parms)
    end
  end

  source
end

#stream_encoder(additional_filter = nil, additional_decode_parms = nil) ⇒ Object

Returns the encoder Fiber for the stream data.

The two arguments can be used to add additional filters for only this returned encoder Fiber. They should normally not be used and are here for use by the encryption facilities.

See the Filter module for more information on how to work with the fiber.



190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
# File 'lib/hexapdf/stream.rb', line 190

def stream_encoder(additional_filter = nil, additional_decode_parms = nil)
  encoder_data = [additional_filter, document.unwrap(self[:Filter])].flatten.
    zip([additional_decode_parms, document.unwrap(self[:DecodeParms])].flatten).
    delete_if {|f, _| f.nil?}
  source = stream_source

  if data.stream.kind_of?(StreamData)
    decoder_data = data.stream.filter.zip(data.stream.decode_parms)

    while !decoder_data.empty? && !encoder_data.empty? && decoder_data.last == encoder_data.last
      decoder_data.pop
      encoder_data.pop
    end

    decoder_data.each do |filter, decode_parms|
      source = filter_for_name(filter).decoder(source, decode_parms)
    end
  end

  encoder_data.reverse!.each do |filter, decode_parms|
    source = filter_for_name(filter).encoder(source, decode_parms)
  end

  source
end

#stream_sourceObject

Returns the Fiber representing the unprocessed content of the stream.



161
162
163
164
165
166
167
# File 'lib/hexapdf/stream.rb', line 161

def stream_source
  if data.stream.kind_of?(String)
    HexaPDF::Filter.source_from_string(data.stream)
  else
    data.stream.fiber(config['io.chunk_size'.freeze])
  end
end