prawn 1.2.1 → 1.3.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: 4853225e17270cdd3f00813349b44209903ab6b2
4
- data.tar.gz: 9ef5c9cf24f812537776b41b3503a87aa9fe52b6
3
+ metadata.gz: 287dd21a281ca025939e562e2d9d0dae14373d21
4
+ data.tar.gz: 0c08643d45840aad66a59661f7593bc3abb89302
5
5
  SHA512:
6
- metadata.gz: cef52ab9b8e81515a1314f63bbb6ee27d8ed2fd8d0832def46e4a49b40296eedc633c5f05b3689ea5fae33905e42747ac2ac5a6e00d434528caa9e7f171a113f
7
- data.tar.gz: 6dca2892f00d9c7b11d2124e09b17d11d82f5f50e0f0fbe76befba7cc263a02fc33946736f70c90c3ba456bba1151aa48c2df5fc42c1f066550323dda600fb14
6
+ metadata.gz: 013f40d6fa76d1cf34ed85578e8ce5700c3ba47bbf6b373b9856ae2a34fe42421d83da002604f1acb5bdfd7fdcf0acc85a1f58d9397c89d46254c2e01da5764a
7
+ data.tar.gz: b478644390db0dcd837063a79c126cf0d8d70a53746755dae3797bda11553b8520dd33d3ca983301a7627a76b74d824337d3497abba5966683eedd81efb5a2d5
data/Rakefile CHANGED
@@ -16,10 +16,9 @@ end
16
16
 
17
17
  desc "Show library's code statistics"
18
18
  task :stats do
19
- require 'code_statistics'
20
- CodeStatistics::TEST_TYPES << "Specs"
21
- CodeStatistics.new( ["Prawn", "lib"],
22
- ["Specs", "spec"] ).to_s
19
+ require 'code_statistics/code_statistics'
20
+ puts CodeStatistics::CodeStatistics.new( [["Prawn", "lib"],
21
+ ["Specs", "spec"]] ).to_s
23
22
  end
24
23
 
25
24
  YARD::Rake::YardocTask.new do |t|
@@ -21,8 +21,6 @@ module Prawn
21
21
  BASEDIR = File.expand_path(File.join(dir, '..'))
22
22
  DATADIR = File.expand_path(File.join(dir, '..', 'data'))
23
23
 
24
- VERSION = File.read("#{BASEDIR}/VERSION").strip
25
-
26
24
  FLOAT_PRECISION = 1.0e-9
27
25
 
28
26
  # Whe set to true, Prawn will verify hash options to ensure only valid keys
@@ -64,8 +62,9 @@ module Prawn
64
62
  end
65
63
  end
66
64
 
67
- require_relative "prawn/errors"
65
+ require_relative "prawn/version"
68
66
 
67
+ require_relative "prawn/errors"
69
68
 
70
69
  require_relative "prawn/utilities"
71
70
  require_relative "prawn/text"
@@ -84,10 +83,8 @@ require_relative "prawn/measurements"
84
83
  require_relative "prawn/repeater"
85
84
  require_relative "prawn/outline"
86
85
  require_relative "prawn/grid"
87
-
86
+ require_relative "prawn/view"
88
87
  require_relative "prawn/image_handler"
89
88
 
90
-
91
-
92
89
  Prawn.image_handler.register(Prawn::Images::PNG)
93
90
  Prawn.image_handler.register(Prawn::Images::JPG)
@@ -12,7 +12,6 @@ require_relative "document/bounding_box"
12
12
  require_relative "document/column_box"
13
13
  require_relative "document/internals"
14
14
  require_relative "document/span"
15
- require_relative "document/graphics_state"
16
15
 
17
16
  module Prawn
18
17
 
@@ -53,7 +52,6 @@ module Prawn
53
52
  include Prawn::Document::Internals
54
53
  include PDF::Core::Annotations
55
54
  include PDF::Core::Destinations
56
- include Prawn::Document::GraphicsState
57
55
  include Prawn::Document::Security
58
56
  include Prawn::Text
59
57
  include Prawn::Graphics
@@ -202,9 +200,9 @@ module Prawn
202
200
  self.class.extensions.reverse_each { |e| extend e }
203
201
  @internal_state = PDF::Core::DocumentState.new(options)
204
202
  @internal_state.populate_pages_from_store(self)
205
- min_version(state.store.min_version) if state.store.min_version
203
+ renderer.min_version(state.store.min_version) if state.store.min_version
206
204
 
207
- min_version(1.6) if options[:print_scaling] == :none
205
+ renderer.min_version(1.6) if options[:print_scaling] == :none
208
206
 
209
207
  @background = options[:background]
210
208
  @background_scale = options[:background_scale] || 1
@@ -349,23 +347,13 @@ module Prawn
349
347
  # Renders the PDF document to string.
350
348
  # Pass an open file descriptor to render to file.
351
349
  #
352
- def render(output = StringIO.new)
353
- if output.instance_of?(StringIO)
354
- output.set_encoding(::Encoding::ASCII_8BIT)
355
- end
356
- finalize_all_page_contents
357
-
358
- render_header(output)
359
- render_body(output)
360
- render_xref(output)
361
- render_trailer(output)
362
- if output.instance_of?(StringIO)
363
- str = output.string
364
- str.force_encoding(::Encoding::ASCII_8BIT)
365
- return str
366
- else
367
- return nil
350
+ def render(*a, &b)
351
+ (1..page_count).each do |i|
352
+ go_to_page i
353
+ repeaters.each { |r| r.run(i) }
368
354
  end
355
+
356
+ renderer.render(*a, &b)
369
357
  end
370
358
 
371
359
  # Renders the PDF document to file.
@@ -567,13 +555,6 @@ module Prawn
567
555
  end
568
556
  end
569
557
 
570
- # Returns true if content streams will be compressed before rendering,
571
- # false otherwise
572
- #
573
- def compression_enabled?
574
- !!state.compress
575
- end
576
-
577
558
  # @group Experimental API
578
559
 
579
560
  # Attempts to group the given block vertically within the current context.
@@ -6,6 +6,8 @@
6
6
  #
7
7
  # This is free software. Please see the LICENSE and COPYING files for details.
8
8
 
9
+ require "forwardable"
10
+
9
11
  module Prawn
10
12
  class Document
11
13
 
@@ -16,159 +18,40 @@ module Prawn
16
18
  #
17
19
  # @private
18
20
  module Internals
19
- # Creates a new Prawn::Reference and adds it to the Document's object
20
- # list. The +data+ argument is anything that Prawn::PdfObject() can convert.
21
- #
22
- # Returns the identifier which points to the reference in the ObjectStore
23
- #
24
- def ref(data)
25
- ref!(data).identifier
26
- end
27
-
28
- # Like ref, but returns the actual reference instead of its identifier.
29
- #
30
- # While you can use this to build up nested references within the object
31
- # tree, it is recommended to persist only identifiers, and them provide
32
- # helper methods to look up the actual references in the ObjectStore
33
- # if needed. If you take this approach, Prawn::Document::Snapshot
34
- # will probably work with your extension
35
- #
36
- def ref!(data)
37
- state.store.ref(data)
38
- end
39
-
40
- # At any stage in the object tree an object can be replaced with an
41
- # indirect reference. To get access to the object safely, regardless
42
- # of if it's hidden behind a Prawn::Reference, wrap it in deref().
43
- #
44
- def deref(obj)
45
- obj.is_a?(PDF::Core::Reference) ? obj.data : obj
46
- end
47
-
48
- # Appends a raw string to the current page content.
49
- #
50
- # # Raw line drawing example:
51
- # x1,y1,x2,y2 = 100,500,300,550
52
- # pdf.add_content("%.3f %.3f m" % [ x1, y1 ]) # move
53
- # pdf.add_content("%.3f %.3f l" % [ x2, y2 ]) # draw path
54
- # pdf.add_content("S") # stroke
55
- #
56
- def add_content(str)
57
- save_graphics_state if graphic_state.nil?
58
- state.page.content << str << "\n"
59
- end
60
-
61
- # The Name dictionary (PDF spec 3.6.3) for this document. It is
62
- # lazily initialized, so that documents that do not need a name
63
- # dictionary do not incur the additional overhead.
64
- #
65
- def names
66
- state.store.root.data[:Names] ||= ref!(:Type => :Names)
67
- end
68
-
69
- # Returns true if the Names dictionary is in use for this document.
70
- #
71
- def names?
72
- state.store.root.data[:Names]
73
- end
74
-
75
- # Defines a block to be called just before the document is rendered.
76
- #
77
- def before_render(&block)
78
- state.before_render_callbacks << block
79
- end
80
-
81
- # Defines a block to be called just before a new page is started.
82
- #
83
- def on_page_create(&block)
84
- if block_given?
85
- state.on_page_create_callback = block
86
- else
87
- state.on_page_create_callback = nil
88
- end
89
- end
90
-
91
- private
92
-
93
- # adds a new, empty content stream to each page. Used in templating so
94
- # that imported content streams can be left pristine
95
- #
96
- def fresh_content_streams(options={})
97
- (1..page_count).each do |i|
98
- go_to_page i
99
- state.page.new_content_stream
100
- apply_margin_options(options)
101
- generate_margin_box
102
- use_graphic_settings(options[:template])
103
- forget_text_rendering_mode!
104
- end
105
- end
106
-
107
- def finalize_all_page_contents
108
- (1..page_count).each do |i|
109
- go_to_page i
110
- repeaters.each { |r| r.run(i) }
111
- while graphic_stack.present?
112
- restore_graphics_state
113
- end
114
- state.page.finalize
115
- end
116
- end
21
+ extend Forwardable
117
22
 
118
- # raise the PDF version of the file we're going to generate.
119
- # A private method, designed for internal use when the user adds a feature
120
- # to their document that requires a particular version.
121
- #
122
- def min_version(min)
123
- state.version = min if min > state.version
124
- end
23
+ # These methods are not officially part of Prawn's public API,
24
+ # but they are used in documentation and possibly in extensions.
25
+ # Perhaps they will become part of the extension API?
26
+ # Anyway, for now it's not clear what we should do w. them.
27
+ delegate [ :graphic_state,
28
+ :save_graphics_state,
29
+ :restore_graphics_state ] => :renderer
125
30
 
126
- # Write out the PDF Header, as per spec 3.4.1
31
+ # FIXME: This is a circular reference, because in theory Prawn should
32
+ # be passing instances of renderer to PDF::Core::Page, but it's
33
+ # passing Prawn::Document objects instead.
127
34
  #
128
- def render_header(output)
129
- state.before_render_actions(self)
35
+ # A proper design would probably not require Prawn to directly instantiate
36
+ # PDF::Core::Page objects at all!
37
+ delegate [:compression_enabled?] => :renderer
130
38
 
131
- # pdf version
132
- output << "%PDF-#{state.version}\n"
39
+ # FIXME: More circular references in PDF::Core::Page.
40
+ delegate [ :ref, :ref!, :deref ] => :renderer
133
41
 
134
- # 4 binary chars, as recommended by the spec
135
- output << "%\xFF\xFF\xFF\xFF\n"
136
- end
42
+ # FIXME: Another circular reference, because we mix in a module from
43
+ # PDF::Core to provide destinations, which in theory should not
44
+ # rely on a Prawn::Document object but is currently wired up that way.
45
+ delegate [:names] => :renderer
137
46
 
138
- # Write out the PDF Body, as per spec 3.4.2
139
- #
140
- def render_body(output)
141
- state.render_body(output)
142
- end
47
+ # FIXME: Circular reference because we mix PDF::Core::Text into
48
+ # Prawn::Document. PDF::Core::Text should either be split up or
49
+ # moved in its entirety back up into Prawn.
50
+ delegate [:add_content] => :renderer
143
51
 
144
- # Write out the PDF Cross Reference Table, as per spec 3.4.3
145
- #
146
- def render_xref(output)
147
- @xref_offset = output.size
148
- output << "xref\n"
149
- output << "0 #{state.store.size + 1}\n"
150
- output << "0000000000 65535 f \n"
151
- state.store.each do |ref|
152
- output.printf("%010d", ref.offset)
153
- output << " 00000 n \n"
154
- end
52
+ def renderer
53
+ @renderer ||= PDF::Core::Renderer.new(state)
155
54
  end
156
-
157
- # Write out the PDF Trailer, as per spec 3.4.4
158
- #
159
- def render_trailer(output)
160
- trailer_hash = {:Size => state.store.size + 1,
161
- :Root => state.store.root,
162
- :Info => state.store.info}
163
- trailer_hash.merge!(state.trailer) if state.trailer
164
-
165
- output << "trailer\n"
166
- output << PDF::Core::PdfObject(trailer_hash) << "\n"
167
- output << "startxref\n"
168
- output << @xref_offset << "\n"
169
- output << "%%EOF" << "\n"
170
- end
171
-
172
55
  end
173
56
  end
174
57
  end
@@ -398,31 +398,10 @@ module Prawn
398
398
 
399
399
  private
400
400
 
401
- # generate a font identifier that hasn't been used on the curretn page yet
401
+ # generate a font identifier that hasn't been used on the current page yet
402
402
  #
403
403
  def generate_unique_id
404
- offset, id = 0, nil
405
-
406
- while id.nil? || page_contains_font_id?(id)
407
- offset += 1
408
- id = :"F#{@document.font_registry.size + offset}"
409
- end
410
-
411
- id
412
- end
413
-
414
- # Returns true if the provided font identifier already exists in the document.
415
- # This is used when adding new fonts to a document to ensure we don't step
416
- # on fonts imported from a template.
417
- #
418
- # page_contains_font_id?("F1")
419
- # => true
420
- #
421
- def page_contains_font_id?(id)
422
- id = id.to_s
423
- @document.state.page.fonts.keys.any? { |exist_id|
424
- exist_id.to_s[0,id.size] == id
425
- }
404
+ :"F#{@document.font_registry.size + 1}"
426
405
  end
427
406
 
428
407
  def size
@@ -245,7 +245,7 @@ module Prawn
245
245
 
246
246
  # Embed the font metrics in the document after everything has been
247
247
  # drawn, just before the document is emitted.
248
- @document.before_render { |doc| embed(ref, subset) }
248
+ @document.renderer.before_render { |doc| embed(ref, subset) }
249
249
 
250
250
  ref
251
251
  end
@@ -47,7 +47,7 @@ module Prawn
47
47
  #
48
48
  def move_to(*point)
49
49
  x,y = map_to_absolute(point)
50
- add_content("%.3f %.3f m" % [ x, y ])
50
+ renderer.add_content("%.3f %.3f m" % [ x, y ])
51
51
  end
52
52
 
53
53
  # Draws a line from the current drawing position to the specified point.
@@ -58,7 +58,7 @@ module Prawn
58
58
  #
59
59
  def line_to(*point)
60
60
  x,y = map_to_absolute(point)
61
- add_content("%.3f %.3f l" % [ x, y ])
61
+ renderer.add_content("%.3f %.3f l" % [ x, y ])
62
62
  end
63
63
 
64
64
  # Draws a Bezier curve from the current drawing position to the
@@ -72,7 +72,7 @@ module Prawn
72
72
  "as :bounds => [[x1,y1],[x2,y2]]"
73
73
 
74
74
  curve_points = (options[:bounds] << dest).map { |e| map_to_absolute(e) }
75
- add_content("%.3f %.3f %.3f %.3f %.3f %.3f c" %
75
+ renderer.add_content("%.3f %.3f %.3f %.3f %.3f %.3f c" %
76
76
  curve_points.flatten )
77
77
  end
78
78
 
@@ -83,7 +83,7 @@ module Prawn
83
83
  #
84
84
  def rectangle(point,width,height)
85
85
  x,y = map_to_absolute(point)
86
- add_content("%.3f %.3f %.3f %.3f re" % [ x, y - height, width, height ])
86
+ renderer.add_content("%.3f %.3f %.3f %.3f re" % [ x, y - height, width, height ])
87
87
  end
88
88
 
89
89
  # Draws a rounded rectangle given <tt>point</tt>, <tt>width</tt> and
@@ -239,7 +239,7 @@ module Prawn
239
239
  line_to(*point)
240
240
  end
241
241
  # close the path
242
- add_content "h"
242
+ renderer.add_content "h"
243
243
  end
244
244
 
245
245
  # Draws a rounded polygon from specified points using the radius to define bezier curves
@@ -255,7 +255,7 @@ module Prawn
255
255
  rounded_vertex(radius, points[i], points[i + 1], points[i + 2])
256
256
  end
257
257
  # close the path
258
- add_content "h"
258
+ renderer.add_content "h"
259
259
  end
260
260
 
261
261
 
@@ -276,7 +276,7 @@ module Prawn
276
276
  #
277
277
  def stroke
278
278
  yield if block_given?
279
- add_content "S"
279
+ renderer.add_content "S"
280
280
  end
281
281
 
282
282
  # Closes and strokes the current path. If a block is provided, yields to
@@ -284,7 +284,7 @@ module Prawn
284
284
  #
285
285
  def close_and_stroke
286
286
  yield if block_given?
287
- add_content "s"
287
+ renderer.add_content "s"
288
288
  end
289
289
 
290
290
  # Draws and strokes a rectangle represented by the current bounding box
@@ -364,7 +364,7 @@ module Prawn
364
364
  #
365
365
  def fill(options={})
366
366
  yield if block_given?
367
- add_content(options[:fill_rule] == :even_odd ? "f*" : "f")
367
+ renderer.add_content(options[:fill_rule] == :even_odd ? "f*" : "f")
368
368
  end
369
369
 
370
370
  # Closes, fills, and strokes the current path. If a block is provided,
@@ -378,13 +378,13 @@ module Prawn
378
378
  #
379
379
  def fill_and_stroke(options={})
380
380
  yield if block_given?
381
- add_content(options[:fill_rule] == :even_odd ? "b*" : "b")
381
+ renderer.add_content(options[:fill_rule] == :even_odd ? "b*" : "b")
382
382
  end
383
383
 
384
384
  # Closes the current path.
385
385
  #
386
386
  def close_path
387
- add_content "h"
387
+ renderer.add_content "h"
388
388
  end
389
389
 
390
390
  ##
@@ -612,7 +612,7 @@ module Prawn
612
612
  end
613
613
 
614
614
  def write_line_width
615
- add_content("#{current_line_width} w")
615
+ renderer.add_content("#{current_line_width} w")
616
616
  end
617
617
 
618
618
  def map_to_absolute(*point)