prawn 1.2.1 → 1.3.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: 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)