Class: PDF::Core::Renderer

Inherits:
Object
  • Object
show all
Defined in:
lib/pdf/core/renderer.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(state) ⇒ Renderer

Returns a new instance of Renderer.



6
7
8
9
10
11
12
13
# File 'lib/pdf/core/renderer.rb', line 6

def initialize(state)
  @state = state
  @state.populate_pages_from_store(self)
  
  min_version(state.store.min_version) if state.store.min_version

  @page_number = 0
end

Instance Attribute Details

#stateObject (readonly)

Returns the value of attribute state.



15
16
17
# File 'lib/pdf/core/renderer.rb', line 15

def state
  @state
end

Instance Method Details

#add_content(str) ⇒ Object

Appends a raw string to the current page content.

# Raw line drawing example:
x1,y1,x2,y2 = 100,500,300,550

pdf.add_content("#{PDF::Core.real_params([x1, y1])} m")   # move
pdf.add_content("#{PDF::Core.real_params([ x2, y2 ])} l") # draw path
pdf.add_content("S") # stroke


55
56
57
58
# File 'lib/pdf/core/renderer.rb', line 55

def add_content(str)
  save_graphics_state if graphic_state.nil?
  state.page.content << str << "\n"
end

#before_render(&block) ⇒ Object

Defines a block to be called just before the document is rendered.



76
77
78
# File 'lib/pdf/core/renderer.rb', line 76

def before_render(&block)
  state.before_render_callbacks << block
end

#close_graphics_stateObject



228
229
230
# File 'lib/pdf/core/renderer.rb', line 228

def close_graphics_state
  add_content "Q"
end

#compression_enabled?Boolean

Returns true if content streams will be compressed before rendering, false otherwise

Returns:

  • (Boolean)


244
245
246
# File 'lib/pdf/core/renderer.rb', line 244

def compression_enabled?
  !!state.compress
end

#deref(obj) ⇒ Object

At any stage in the object tree an object can be replaced with an indirect reference. To get access to the object safely, regardless of if it’s hidden behind a Prawn::Reference, wrap it in deref().



42
43
44
# File 'lib/pdf/core/renderer.rb', line 42

def deref(obj)
  obj.is_a?(PDF::Core::Reference) ? obj.data : obj
end

#finalize_all_page_contentsObject



130
131
132
133
134
135
136
137
138
# File 'lib/pdf/core/renderer.rb', line 130

def finalize_all_page_contents
  (1..page_count).each do |i|
    go_to_page i
    while graphic_stack.present?
      restore_graphics_state
    end
    state.page.finalize
  end
end

#go_to_page(k) ⇒ Object

Re-opens the page with the given (1-based) page number so that you can draw on it.

See Prawn::Document#number_pages for a sample usage of this capability.



125
126
127
128
# File 'lib/pdf/core/renderer.rb', line 125

def go_to_page(k)
  @page_number = k
  state.page = state.pages[k-1]
end

#graphic_stackObject



259
260
261
# File 'lib/pdf/core/renderer.rb', line 259

def graphic_stack
  state.page.stack
end

#graphic_stateObject



263
264
265
266
# File 'lib/pdf/core/renderer.rb', line 263

def graphic_state
  save_graphics_state unless graphic_stack.current_state
  graphic_stack.current_state
end

#min_version(min) ⇒ Object

raise the PDF version of the file we’re going to generate. A private method, designed for internal use when the user adds a feature to their document that requires a particular version.



144
145
146
# File 'lib/pdf/core/renderer.rb', line 144

def min_version(min)
  state.version = min if min > state.version
end

#namesObject

The Name dictionary (PDF spec 3.6.3) for this document. It is lazily initialized, so that documents that do not need a name dictionary do not incur the additional overhead.



64
65
66
# File 'lib/pdf/core/renderer.rb', line 64

def names
  state.store.root.data[:Names] ||= ref!(:Type => :Names)
end

#names?Boolean

Returns true if the Names dictionary is in use for this document.

Returns:

  • (Boolean)


70
71
72
# File 'lib/pdf/core/renderer.rb', line 70

def names?
  state.store.root.data[:Names]
end

#on_page_create(&block) ⇒ Object

Defines a block to be called just before a new page is started.



82
83
84
85
86
87
88
# File 'lib/pdf/core/renderer.rb', line 82

def on_page_create(&block)
   if block_given?
      state.on_page_create_callback = block
   else
      state.on_page_create_callback = nil
   end
end

#open_graphics_stateObject



224
225
226
# File 'lib/pdf/core/renderer.rb', line 224

def open_graphics_state
  add_content "q"
end

#page_countObject



116
117
118
# File 'lib/pdf/core/renderer.rb', line 116

def page_count
  state.page_count
end

#ref(data) ⇒ Object

Creates a new Reference and adds it to the Document’s object list. The data argument is anything that Prawn::PdfObject() can convert.

Returns the identifier which points to the reference in the ObjectStore



22
23
24
# File 'lib/pdf/core/renderer.rb', line 22

def ref(data)
  ref!(data).identifier
end

#ref!(data) ⇒ Object

Like ref, but returns the actual reference instead of its identifier.

While you can use this to build up nested references within the object tree, it is recommended to persist only identifiers, and then provide helper methods to look up the actual references in the ObjectStore if needed. If you take this approach, Document::Snapshot will probably work with your extension



34
35
36
# File 'lib/pdf/core/renderer.rb', line 34

def ref!(data)
  state.store.ref(data)
end

#render(output = StringIO.new) ⇒ Object

Renders the PDF document to string. Pass an open file descriptor to render to file.



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/pdf/core/renderer.rb', line 151

def render(output = StringIO.new)
  if output.instance_of?(StringIO)
    output.set_encoding(::Encoding::ASCII_8BIT)
  end
  finalize_all_page_contents

  render_header(output)
  render_body(output)
  render_xref(output)
  render_trailer(output)
  if output.instance_of?(StringIO)
    str = output.string
    str.force_encoding(::Encoding::ASCII_8BIT)
    return str
  else
    return nil
  end
end

#render_body(output) ⇒ Object

Write out the PDF Body, as per spec 3.4.2



192
193
194
# File 'lib/pdf/core/renderer.rb', line 192

def render_body(output)
  state.render_body(output)
end

#render_file(filename) ⇒ Object

Renders the PDF document to file.

pdf.render_file "foo.pdf"


174
175
176
# File 'lib/pdf/core/renderer.rb', line 174

def render_file(filename)
  File.open(filename, "wb") { |f| render(f) }
end

#render_header(output) ⇒ Object

Write out the PDF Header, as per spec 3.4.1



180
181
182
183
184
185
186
187
188
# File 'lib/pdf/core/renderer.rb', line 180

def render_header(output)
  state.before_render_actions(self)

  # pdf version
  output << "%PDF-#{state.version}\n"

  # 4 binary chars, as recommended by the spec
  output << "%\xFF\xFF\xFF\xFF\n"
end

#render_trailer(output) ⇒ Object

Write out the PDF Trailer, as per spec 3.4.4



211
212
213
214
215
216
217
218
219
220
221
222
# File 'lib/pdf/core/renderer.rb', line 211

def render_trailer(output)
  trailer_hash = {:Size => state.store.size + 1,
                  :Root => state.store.root,
                  :Info => state.store.info}
  trailer_hash.merge!(state.trailer) if state.trailer

  output << "trailer\n"
  output << PDF::Core::PdfObject(trailer_hash) << "\n"
  output << "startxref\n"
  output << @xref_offset << "\n"
  output << "%%EOF" << "\n"
end

#render_xref(output) ⇒ Object

Write out the PDF Cross Reference Table, as per spec 3.4.3



198
199
200
201
202
203
204
205
206
207
# File 'lib/pdf/core/renderer.rb', line 198

def render_xref(output)
  @xref_offset = output.size
  output << "xref\n"
  output << "0 #{state.store.size + 1}\n"
  output << "0000000000 65535 f \n"
  state.store.each do |ref|
    output.printf("%010d", ref.offset)
    output << " 00000 n \n"
  end
end

#restore_graphics_stateObject

Pops the last saved graphics state off the graphics state stack and restores the state to those values



250
251
252
253
254
255
256
257
# File 'lib/pdf/core/renderer.rb', line 250

def restore_graphics_state
  if graphic_stack.empty?
    raise PDF::Core::Errors::EmptyGraphicStateStack,
      "\n You have reached the end of the graphic state stack"
  end
  close_graphics_state
  graphic_stack.restore_graphic_state
end

#save_graphics_state(graphic_state = nil) ⇒ Object



232
233
234
235
236
237
238
239
# File 'lib/pdf/core/renderer.rb', line 232

def save_graphics_state(graphic_state = nil)
  graphic_stack.save_graphic_state(graphic_state)
  open_graphics_state
  if block_given?
    yield
    restore_graphics_state
  end
end

#start_new_page(options = {}) ⇒ Object



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
# File 'lib/pdf/core/renderer.rb', line 90

def start_new_page(options = {})
  if last_page = state.page
    last_page_size    = last_page.size
    last_page_layout  = last_page.layout
    last_page_margins = last_page.margins
  end

  page_options = {:size => options[:size] || last_page_size,
                  :layout  => options[:layout] || last_page_layout,
                  :margins => last_page_margins}
  if last_page
    new_graphic_state = last_page.graphic_state.dup  if last_page.graphic_state

    #erase the color space so that it gets reset on new page for fussy pdf-readers
    new_graphic_state.color_space = {} if new_graphic_state
    page_options.merge!(:graphic_state => new_graphic_state)
  end

  state.page = PDF::Core::Page.new(self, page_options)

  state.insert_page(state.page, @page_number)
  @page_number += 1

  state.on_page_create_action(self)
end