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 +4 -4
- data/Rakefile +3 -4
- data/lib/prawn.rb +3 -6
- data/lib/prawn/document.rb +8 -27
- data/lib/prawn/document/internals.rb +28 -145
- data/lib/prawn/font.rb +2 -23
- data/lib/prawn/font/ttf.rb +1 -1
- data/lib/prawn/graphics.rb +12 -12
- data/lib/prawn/graphics/cap_style.rb +1 -1
- data/lib/prawn/graphics/color.rb +3 -3
- data/lib/prawn/graphics/dash.rb +1 -1
- data/lib/prawn/graphics/join_style.rb +1 -1
- data/lib/prawn/graphics/patterns.rb +1 -1
- data/lib/prawn/graphics/transformation.rb +1 -1
- data/lib/prawn/graphics/transparency.rb +2 -2
- data/lib/prawn/grid.rb +5 -5
- data/lib/prawn/images.rb +2 -2
- data/lib/prawn/security.rb +1 -1
- data/lib/prawn/soft_mask.rb +3 -3
- data/lib/prawn/stamp.rb +1 -1
- data/lib/prawn/text.rb +8 -0
- data/lib/prawn/text/formatted/fragment.rb +19 -8
- data/lib/prawn/version.rb +5 -0
- data/lib/prawn/view.rb +91 -0
- data/manual/basic_concepts/basic_concepts.rb +3 -1
- data/manual/basic_concepts/view.rb +42 -0
- data/prawn.gemspec +9 -4
- data/spec/document_spec.rb +14 -19
- data/spec/graphics_spec.rb +11 -11
- data/spec/line_wrap_spec.rb +10 -7
- data/spec/view_spec.rb +43 -0
- metadata +25 -8
- data/VERSION +0 -1
- data/lib/prawn/document/graphics_state.rb +0 -73
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 287dd21a281ca025939e562e2d9d0dae14373d21
|
4
|
+
data.tar.gz: 0c08643d45840aad66a59661f7593bc3abb89302
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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::
|
21
|
-
|
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|
|
data/lib/prawn.rb
CHANGED
@@ -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/
|
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)
|
data/lib/prawn/document.rb
CHANGED
@@ -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(
|
353
|
-
|
354
|
-
|
355
|
-
|
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
|
-
|
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
|
-
#
|
119
|
-
#
|
120
|
-
#
|
121
|
-
#
|
122
|
-
|
123
|
-
|
124
|
-
|
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
|
-
#
|
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
|
-
|
129
|
-
|
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
|
-
|
132
|
-
|
39
|
+
# FIXME: More circular references in PDF::Core::Page.
|
40
|
+
delegate [ :ref, :ref!, :deref ] => :renderer
|
133
41
|
|
134
|
-
|
135
|
-
|
136
|
-
|
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
|
-
#
|
139
|
-
#
|
140
|
-
|
141
|
-
|
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
|
-
|
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
|
data/lib/prawn/font.rb
CHANGED
@@ -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
|
401
|
+
# generate a font identifier that hasn't been used on the current page yet
|
402
402
|
#
|
403
403
|
def generate_unique_id
|
404
|
-
|
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
|
data/lib/prawn/font/ttf.rb
CHANGED
@@ -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
|
data/lib/prawn/graphics.rb
CHANGED
@@ -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)
|