pdf-core 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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