-
Notifications
You must be signed in to change notification settings - Fork 40
Expand file tree
/
Copy pathdocument_state.rb
More file actions
163 lines (139 loc) · 4.68 KB
/
document_state.rb
File metadata and controls
163 lines (139 loc) · 4.68 KB
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
152
153
154
155
156
157
158
159
160
161
162
163
# frozen_string_literal: true
module PDF
module Core
# Low-level PDF document representation mostly for keeping intermediate
# state while document is being constructed.
#
# @api private
class DocumentState
# @param options [Hash<Symbol, any>]
# @option options :info [Hash] Document's information dictionary
# @option options :print_scaling [:none, nil] Viewr preference for
# printing scaling
# @option options :trailer [Hash] ({}) File trailer
# @option options :compress [Boolean] (false) Whether to compress streams
# @option options :encrypt [Boolean] (false) Whether to encrypt the
# document
# @option options :encryption_key [String] (nil) Encryption key. Must be
# provided if `:encrypt` is `true`
def initialize(options)
normalize_metadata(options)
store_opts = { info: options[:info] }
store_opts[:print_scaling] = options[:print_scaling] if options[:print_scaling]
store_opts[:marked] = options[:marked] if options[:marked]
@store = PDF::Core::ObjectStore.new(store_opts)
@version = 1.3
@pages = []
@page = nil
@trailer = options.fetch(:trailer, {})
@compress = options.fetch(:compress, false)
@encrypt = options.fetch(:encrypt, false)
@encryption_key = options[:encryption_key]
@skip_encoding = options.fetch(:skip_encoding, false)
@before_render_callbacks = []
@on_page_create_callback = nil
end
# Object store
# @return [PDF::Core::ObjectStore]
attr_accessor :store
# PDF version used in this document
# @return [Float]
attr_accessor :version
# Document pages
# @return [Array<PDF::Core::Page>]
attr_accessor :pages
# Current page
# @return [PDF::Core::Page]
attr_accessor :page
# Document trailer dict
# @return [Hash]
attr_accessor :trailer
# Whether to compress streams
# @return [Boolean]
attr_accessor :compress
# Whether to encrypt document
# @return [Boolean]
attr_accessor :encrypt
# Encryption key
# @return [String, nil]
attr_accessor :encryption_key
# @deprecated Unused
attr_accessor :skip_encoding
# Before render callbacks
# @return [Array<Proc>]
attr_accessor :before_render_callbacks
# A block to call when a new page is created
# @return [Proc, nil]
attr_accessor :on_page_create_callback
# Loads pages from object store. Only does it when there are no pages
# loaded and there are some pages in the store.
#
# @return [0] if no pages were loaded
# @return [Array<PDF::Core::Page>] if pages were laded
def populate_pages_from_store(document)
return 0 if @store.page_count <= 0 || [email protected]?
count = ([email protected]_count)
@pages =
count.map { |index|
orig_dict_id = @store.object_id_for_page(index)
PDF::Core::Page.new(document, object_id: orig_dict_id)
}
end
# Adds Prawn metadata to document info
#
# @param options [Hash]
# @return [Hash] Document `info` hash
def normalize_metadata(options)
options[:info] ||= {}
options[:info][:Creator] ||= 'Prawn'
options[:info][:Producer] ||= 'Prawn'
options[:info]
end
# Insert a page at the specified position.
#
# @param page [PDF::Core::Page]
# @param page_number [Integer]
# @return [void]
def insert_page(page, page_number)
pages.insert(page_number, page)
store.pages.data[:Kids].insert(page_number, page.dictionary)
store.pages.data[:Count] += 1
end
# Execute page creation callback if one is defined
#
# @param doc [Prawn::Document]
# @return [void]
def on_page_create_action(doc)
on_page_create_callback[doc] if on_page_create_callback
end
# Executes before render callbacks
#
# @param _doc [Prawn::Document] Unused
# @return [void]
def before_render_actions(_doc)
before_render_callbacks.each { |c| c.call(self) }
end
# Number of pages in the document
#
# @return [Integer]
def page_count
pages.length
end
# Renders document body to the output
#
# @param output [#<<]
# @return [void]
def render_body(output)
store.each do |ref|
ref.offset = output.size
output <<
if @encrypt
ref.encrypted_object(@encryption_key)
else
ref.object
end
end
end
end
end
end