File: object_store.rb

package info (click to toggle)
ruby-pdf-core 0.10.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 408 kB
  • sloc: ruby: 2,270; makefile: 4
file content (151 lines) | stat: -rw-r--r-- 3,746 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# frozen_string_literal: true

module PDF
  module Core
    # PDF object repository
    #
    # @api private
    class ObjectStore
      include Enumerable

      # Minimum PDF version
      # @return [Float]
      attr_reader :min_version

      # @param opts [Hash]
      # @option opts :info [Hash] Documnt info dict
      # @option opts :print_scaling [:none, nil] (nil) Print scaling viewer
      #   option
      def initialize(opts = {})
        @objects = {}
        @identifiers = []

        @info ||= ref(opts[:info] || {}).identifier
        @root ||= ref(Type: :Catalog).identifier
        if opts[:print_scaling] == :none
          root.data[:ViewerPreferences] = { PrintScaling: :None }
        end
        if pages.nil?
          root.data[:Pages] = ref(Type: :Pages, Count: 0, Kids: [])
        end
      end

      # Wrap an object into a reference.
      #
      # @param data [Hash, Array, Numeric, String, Symbol, Date, Time, nil]
      #   object data
      # @return [Reference]
      def ref(data)
        push(size + 1, data)
      end

      # Document info dict reference
      #
      # @return [Reference]
      def info
        @objects[@info]
      end

      # Document root dict reference
      #
      # @return [Reference]
      def root
        @objects[@root]
      end

      # Document pages reference
      #
      # @return [Reference]
      def pages
        root.data[:Pages]
      end

      # Number of pages in the document
      #
      # @return [Integer]
      def page_count
        pages.data[:Count]
      end

      # Adds the given reference to the store and returns the reference object.
      # If the object provided is not a PDF::Core::Reference, one is created
      # from the arguments provided.
      #
      # @overload push(reference)
      #   @param reference [Reference]
      #   @return [reference]
      # @overload push(id, data)
      #   @param id [Integer] reference identifier
      #   @param data [Hash, Array, Numeric, String, Symbol, Date, Time, nil]
      #     object data
      #   @return [Reference] - the added reference
      def push(*args)
        reference =
          if args.first.is_a?(PDF::Core::Reference)
            args.first
          else
            PDF::Core::Reference.new(*args)
          end

        @objects[reference.identifier] = reference
        @identifiers << reference.identifier
        reference
      end

      alias << push

      # Iterate over document object references.
      #
      # @yieldparam ref [Reference]
      # @return [void]
      def each
        @identifiers.each do |id|
          yield(@objects[id])
        end
      end

      # Get object reference by its identifier.
      #
      # @param id [Integer] object identifier
      # @return [Reference]
      def [](id)
        @objects[id]
      end

      # Number of object references in the document.
      #
      # @return [Integer]
      def size
        @identifiers.size
      end
      alias length size

      # Get page reference identifier by page number.Pages are indexed starting
      # at 1 (**not 0**).
      #
      # @example
      #   !!!ruby
      #   object_id_for_page(1)
      #   #=> 5
      #   object_id_for_page(10)
      #   #=> 87
      #   object_id_for_page(-11)
      #   #=> 17
      #
      # @param page [Integer] page number
      # @return [Integer] page object identifier
      def object_id_for_page(page)
        page -= 1 if page.positive?
        flat_page_ids = get_page_objects(pages).flatten
        flat_page_ids[page]
      end

      private

      # returns an array with the object IDs for all pages
      def get_page_objects(pages)
        pages.data[:Kids].map(&:identifier)
      end
    end
  end
end