Class: CorpPdf::ObjStm
- Inherits:
-
Object
- Object
- CorpPdf::ObjStm
- Defined in:
- lib/corp_pdf/objstm.rb
Class Method Summary collapse
-
.create(patches, compress: true) ⇒ Object
Create an object stream from patches (array of [num, gen], body: String).
-
.parse(bytes, n:, first:) ⇒ Object
Parse an object stream body given N and First.
Class Method Details
.create(patches, compress: true) ⇒ Object
Create an object stream from patches (array of [num, gen], body: String). Returns: { dictionary: String, stream_body: String, object_count: Integer } The dictionary includes /Type /ObjStm, /N (count), /First (header size), and /Filter /FlateDecode
24 25 26 27 28 29 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 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/corp_pdf/objstm.rb', line 24 def self.create(patches, compress: true) return nil if patches.empty? # Sort patches by object number for consistency sorted_patches = patches.sort_by { |p| p[:ref][0] } # Build header: "obj_num offset obj_num offset ..." # Offsets are relative to the start of the object data section (after header) header_parts = [] body_parts = [] current_offset = 0 sorted_patches.each do |patch| obj_num, = patch[:ref] body = patch[:body].to_s # Ensure body ends with newline for proper parsing body += "\n" unless body.end_with?("\n") header_parts << obj_num.to_s header_parts << current_offset.to_s body_parts << body current_offset += body.bytesize end header = "#{header_parts.join(' ')}\n" first = header.bytesize object_bodies = body_parts.join # Combine header and bodies raw_data = header + object_bodies # Compress if requested stream_body = if compress Zlib::Deflate.deflate(raw_data) else raw_data end # Build dictionary dict = "<<\n/Type /ObjStm\n/N #{sorted_patches.length}\n/First #{first}".b dict << "\n/Filter /FlateDecode".b if compress dict << "\n/Length #{stream_body.bytesize}\n>>".b { dictionary: dict, stream_body: stream_body.b, object_count: sorted_patches.length, patches: sorted_patches } end |
.parse(bytes, n:, first:) ⇒ Object
Parse an object stream body given N and First. Returns: array like [{ ref:, body:String }, …] in order of header listing.
7 8 9 10 11 12 13 14 15 16 17 18 19 |
# File 'lib/corp_pdf/objstm.rb', line 7 def self.parse(bytes, n:, first:) head = bytes[0...first] entries = head.strip.split(/\s+/).map!(&:to_i) refs = [] n.times do |i| obj = entries[2 * i] off = entries[(2 * i) + 1] next_off = i + 1 < n ? entries[(2 * (i + 1)) + 1] : (bytes.bytesize - first) body = bytes[first + off, (first + next_off) - (first + off)] refs << { ref: [obj, 0], body: body } end refs end |