pdf-core 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f0290a0011b662d535affad39a3429a005f9cf7a
4
- data.tar.gz: 9b22752a0a1d9e8595994ffd555a0ca8cb68daa2
3
+ metadata.gz: 7f20557e9a614c10244d01e2b1ed78d4434cef6c
4
+ data.tar.gz: 8668979b6592e45d81d8274e8acd387642e5a3fb
5
5
  SHA512:
6
- metadata.gz: 043e585e7e4ea111d09ccad6a8c713cedbaff314a9521394507bf3a77c862d360daa0fbda9c57b5bcf5a4feae4a1cdab1468114c5f6ceac9c37a18cebcf858fd
7
- data.tar.gz: 35088210934d898e38a255a754277c3530e4fe8b7c7f5f0800eeb1f6a2680d56bec8420d8533e62e3fdc3c48bd234f8c213f912e89b6e4b235e2176a45f664e1
6
+ metadata.gz: 68d6e43d2579ff909d9cabc4a9d641648e9830685a2d2b76d24fe85046e48ea22fb7bbb4bf005d3442d4595b44b18dddd29dad37f99ecd32a3b9fa515490503e
7
+ data.tar.gz: f6f49f285719b0d72d3113bc465db2e588d52c2b1c096c7285cb56f43744a31122d4a0c8338ab88353b29555bb352d4c2cc662eac2c73164948dda3ca5c72933
@@ -15,6 +15,7 @@ require_relative "core/graphics_state"
15
15
  require_relative "core/page_geometry"
16
16
  require_relative "core/outline_root"
17
17
  require_relative "core/outline_item"
18
+ require_relative "core/renderer"
18
19
 
19
20
  module PDF
20
21
  module Core
@@ -0,0 +1,268 @@
1
+ require "stringio"
2
+
3
+ module PDF
4
+ module Core
5
+ class Renderer
6
+ def initialize(state)
7
+ @state = state
8
+ @state.populate_pages_from_store(self)
9
+
10
+ min_version(state.store.min_version) if state.store.min_version
11
+
12
+ @page_number = 0
13
+ end
14
+
15
+ attr_reader :state
16
+
17
+ # Creates a new Reference and adds it to the Document's object
18
+ # list. The +data+ argument is anything that Prawn::PdfObject() can convert.
19
+ #
20
+ # Returns the identifier which points to the reference in the ObjectStore
21
+ #
22
+ def ref(data)
23
+ ref!(data).identifier
24
+ end
25
+
26
+ # Like ref, but returns the actual reference instead of its identifier.
27
+ #
28
+ # While you can use this to build up nested references within the object
29
+ # tree, it is recommended to persist only identifiers, and then provide
30
+ # helper methods to look up the actual references in the ObjectStore
31
+ # if needed. If you take this approach, Document::Snapshot
32
+ # will probably work with your extension
33
+ #
34
+ def ref!(data)
35
+ state.store.ref(data)
36
+ end
37
+
38
+ # At any stage in the object tree an object can be replaced with an
39
+ # indirect reference. To get access to the object safely, regardless
40
+ # of if it's hidden behind a Prawn::Reference, wrap it in deref().
41
+ #
42
+ def deref(obj)
43
+ obj.is_a?(PDF::Core::Reference) ? obj.data : obj
44
+ end
45
+
46
+ # Appends a raw string to the current page content.
47
+ #
48
+ # # Raw line drawing example:
49
+ # x1,y1,x2,y2 = 100,500,300,550
50
+ # pdf.add_content("%.3f %.3f m" % [ x1, y1 ]) # move
51
+ # pdf.add_content("%.3f %.3f l" % [ x2, y2 ]) # draw path
52
+ # pdf.add_content("S") # stroke
53
+ #
54
+ def add_content(str)
55
+ save_graphics_state if graphic_state.nil?
56
+ state.page.content << str << "\n"
57
+ end
58
+
59
+ # The Name dictionary (PDF spec 3.6.3) for this document. It is
60
+ # lazily initialized, so that documents that do not need a name
61
+ # dictionary do not incur the additional overhead.
62
+ #
63
+ def names
64
+ state.store.root.data[:Names] ||= ref!(:Type => :Names)
65
+ end
66
+
67
+ # Returns true if the Names dictionary is in use for this document.
68
+ #
69
+ def names?
70
+ state.store.root.data[:Names]
71
+ end
72
+
73
+ # Defines a block to be called just before the document is rendered.
74
+ #
75
+ def before_render(&block)
76
+ state.before_render_callbacks << block
77
+ end
78
+
79
+ # Defines a block to be called just before a new page is started.
80
+ #
81
+ def on_page_create(&block)
82
+ if block_given?
83
+ state.on_page_create_callback = block
84
+ else
85
+ state.on_page_create_callback = nil
86
+ end
87
+ end
88
+
89
+ def start_new_page(options = {})
90
+ if last_page = state.page
91
+ last_page_size = last_page.size
92
+ last_page_layout = last_page.layout
93
+ last_page_margins = last_page.margins
94
+ end
95
+
96
+ page_options = {:size => options[:size] || last_page_size,
97
+ :layout => options[:layout] || last_page_layout,
98
+ :margins => last_page_margins}
99
+ if last_page
100
+ new_graphic_state = last_page.graphic_state.dup if last_page.graphic_state
101
+
102
+ #erase the color space so that it gets reset on new page for fussy pdf-readers
103
+ new_graphic_state.color_space = {} if new_graphic_state
104
+ page_options.merge!(:graphic_state => new_graphic_state)
105
+ end
106
+
107
+ state.page = PDF::Core::Page.new(self, page_options)
108
+
109
+ state.insert_page(state.page, @page_number)
110
+ @page_number += 1
111
+
112
+ state.on_page_create_action(self)
113
+ end
114
+
115
+ def page_count
116
+ state.page_count
117
+ end
118
+
119
+ # Re-opens the page with the given (1-based) page number so that you can
120
+ # draw on it.
121
+ #
122
+ # See Prawn::Document#number_pages for a sample usage of this capability.
123
+
124
+ def go_to_page(k)
125
+ @page_number = k
126
+ state.page = state.pages[k-1]
127
+ end
128
+
129
+ def finalize_all_page_contents
130
+ (1..page_count).each do |i|
131
+ go_to_page i
132
+ while graphic_stack.present?
133
+ restore_graphics_state
134
+ end
135
+ state.page.finalize
136
+ end
137
+ end
138
+
139
+ # raise the PDF version of the file we're going to generate.
140
+ # A private method, designed for internal use when the user adds a feature
141
+ # to their document that requires a particular version.
142
+ #
143
+ def min_version(min)
144
+ state.version = min if min > state.version
145
+ end
146
+
147
+ # Renders the PDF document to string.
148
+ # Pass an open file descriptor to render to file.
149
+ #
150
+ def render(output = StringIO.new)
151
+ if output.instance_of?(StringIO)
152
+ output.set_encoding(::Encoding::ASCII_8BIT)
153
+ end
154
+ finalize_all_page_contents
155
+
156
+ render_header(output)
157
+ render_body(output)
158
+ render_xref(output)
159
+ render_trailer(output)
160
+ if output.instance_of?(StringIO)
161
+ str = output.string
162
+ str.force_encoding(::Encoding::ASCII_8BIT)
163
+ return str
164
+ else
165
+ return nil
166
+ end
167
+ end
168
+
169
+ # Renders the PDF document to file.
170
+ #
171
+ # pdf.render_file "foo.pdf"
172
+ #
173
+ def render_file(filename)
174
+ File.open(filename, "wb") { |f| render(f) }
175
+ end
176
+
177
+ # Write out the PDF Header, as per spec 3.4.1
178
+ #
179
+ def render_header(output)
180
+ state.before_render_actions(self)
181
+
182
+ # pdf version
183
+ output << "%PDF-#{state.version}\n"
184
+
185
+ # 4 binary chars, as recommended by the spec
186
+ output << "%\xFF\xFF\xFF\xFF\n"
187
+ end
188
+
189
+ # Write out the PDF Body, as per spec 3.4.2
190
+ #
191
+ def render_body(output)
192
+ state.render_body(output)
193
+ end
194
+
195
+ # Write out the PDF Cross Reference Table, as per spec 3.4.3
196
+ #
197
+ def render_xref(output)
198
+ @xref_offset = output.size
199
+ output << "xref\n"
200
+ output << "0 #{state.store.size + 1}\n"
201
+ output << "0000000000 65535 f \n"
202
+ state.store.each do |ref|
203
+ output.printf("%010d", ref.offset)
204
+ output << " 00000 n \n"
205
+ end
206
+ end
207
+
208
+ # Write out the PDF Trailer, as per spec 3.4.4
209
+ #
210
+ def render_trailer(output)
211
+ trailer_hash = {:Size => state.store.size + 1,
212
+ :Root => state.store.root,
213
+ :Info => state.store.info}
214
+ trailer_hash.merge!(state.trailer) if state.trailer
215
+
216
+ output << "trailer\n"
217
+ output << PDF::Core::PdfObject(trailer_hash) << "\n"
218
+ output << "startxref\n"
219
+ output << @xref_offset << "\n"
220
+ output << "%%EOF" << "\n"
221
+ end
222
+
223
+ def open_graphics_state
224
+ add_content "q"
225
+ end
226
+
227
+ def close_graphics_state
228
+ add_content "Q"
229
+ end
230
+
231
+ def save_graphics_state(graphic_state = nil)
232
+ graphic_stack.save_graphic_state(graphic_state)
233
+ open_graphics_state
234
+ if block_given?
235
+ yield
236
+ restore_graphics_state
237
+ end
238
+ end
239
+
240
+ # Returns true if content streams will be compressed before rendering,
241
+ # false otherwise
242
+ #
243
+ def compression_enabled?
244
+ !!state.compress
245
+ end
246
+
247
+ # Pops the last saved graphics state off the graphics state stack and
248
+ # restores the state to those values
249
+ def restore_graphics_state
250
+ if graphic_stack.empty?
251
+ raise PDF::Core::Errors::EmptyGraphicStateStack,
252
+ "\n You have reached the end of the graphic state stack"
253
+ end
254
+ close_graphics_state
255
+ graphic_stack.restore_graphic_state
256
+ end
257
+
258
+ def graphic_stack
259
+ state.page.stack
260
+ end
261
+
262
+ def graphic_state
263
+ save_graphics_state unless graphic_stack.current_state
264
+ graphic_stack.current_state
265
+ end
266
+ end
267
+ end
268
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pdf-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gregory Brown
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2014-09-11 00:00:00.000000000 Z
15
+ date: 2014-09-16 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: pdf-reader
@@ -118,6 +118,7 @@ files:
118
118
  - lib/pdf/core/page_geometry.rb
119
119
  - lib/pdf/core/pdf_object.rb
120
120
  - lib/pdf/core/reference.rb
121
+ - lib/pdf/core/renderer.rb
121
122
  - lib/pdf/core/stream.rb
122
123
  - lib/pdf/core/text.rb
123
124
  - pdf-core.gemspec