prawn 0.1.2 → 0.2.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.
- data/README +16 -2
- data/Rakefile +3 -3
- data/data/images/arrow.png +0 -0
- data/data/images/arrow2.png +0 -0
- data/data/images/barcode_issue.png +0 -0
- data/data/images/ruport_type0.png +0 -0
- data/examples/cell.rb +14 -3
- data/examples/chinese_text_wrapping.rb +17 -0
- data/examples/family_based_styling.rb +21 -0
- data/examples/fancy_table.rb +4 -4
- data/examples/flowing_text_with_header_and_footer.rb +72 -0
- data/examples/font_size.rb +2 -2
- data/examples/lazy_bounding_boxes.rb +19 -0
- data/examples/table.rb +13 -11
- data/examples/text_flow.rb +1 -1
- data/lib/prawn.rb +44 -15
- data/lib/prawn/compatibility.rb +20 -7
- data/lib/prawn/document.rb +72 -122
- data/lib/prawn/document/bounding_box.rb +124 -24
- data/lib/prawn/document/internals.rb +107 -0
- data/lib/prawn/document/table.rb +99 -70
- data/lib/prawn/document/text.rb +92 -314
- data/lib/prawn/errors.rb +13 -2
- data/lib/prawn/font.rb +312 -1
- data/lib/prawn/font/cmap.rb +1 -1
- data/lib/prawn/font/metrics.rb +52 -49
- data/lib/prawn/font/wrapping.rb +14 -12
- data/lib/prawn/graphics.rb +23 -74
- data/lib/prawn/graphics/cell.rb +30 -25
- data/lib/prawn/graphics/color.rb +132 -0
- data/lib/prawn/images.rb +37 -16
- data/lib/prawn/images/png.rb +29 -24
- data/lib/prawn/pdf_object.rb +3 -1
- data/spec/bounding_box_spec.rb +12 -3
- data/spec/document_spec.rb +40 -72
- data/spec/font_spec.rb +97 -0
- data/spec/graphics_spec.rb +46 -99
- data/spec/images_spec.rb +4 -21
- data/spec/pdf_object_spec.rb +8 -8
- data/spec/png_spec.rb +47 -12
- data/spec/spec_helper.rb +5 -24
- data/spec/table_spec.rb +53 -59
- data/spec/text_spec.rb +28 -93
- data/vendor/pdf-inspector/README +18 -0
- data/vendor/pdf-inspector/lib/pdf/inspector.rb +25 -0
- data/vendor/pdf-inspector/lib/pdf/inspector/graphics.rb +80 -0
- data/vendor/pdf-inspector/lib/pdf/inspector/page.rb +16 -0
- data/vendor/pdf-inspector/lib/pdf/inspector/text.rb +31 -0
- data/vendor/pdf-inspector/lib/pdf/inspector/xobject.rb +19 -0
- metadata +63 -38
- data/examples/on_page_start.rb +0 -17
- data/examples/table_bench.rb +0 -92
- data/spec/box_calculation_spec.rb +0 -17
data/spec/spec_helper.rb
CHANGED
@@ -6,35 +6,16 @@ require "rubygems"
|
|
6
6
|
require "test/spec"
|
7
7
|
require "mocha"
|
8
8
|
$LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib')
|
9
|
+
$LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'vendor','pdf-inspector','lib')
|
9
10
|
require "prawn"
|
10
|
-
gem 'pdf-reader', ">=0.7.3"
|
11
|
-
require "pdf/reader"
|
12
11
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
end
|
17
|
-
end
|
12
|
+
gem 'pdf-reader', ">=0.7.3"
|
13
|
+
require "pdf/reader"
|
14
|
+
require "pdf/inspector"
|
18
15
|
|
19
16
|
def create_pdf
|
20
17
|
@pdf = Prawn::Document.new(:left_margin => 0,
|
21
18
|
:right_margin => 0,
|
22
19
|
:top_margin => 0,
|
23
20
|
:bottom_margin => 0)
|
24
|
-
end
|
25
|
-
|
26
|
-
def observer(klass)
|
27
|
-
@output = @pdf.render
|
28
|
-
obs = klass.new
|
29
|
-
PDF::Reader.string(@output,obs)
|
30
|
-
obs
|
31
|
-
end
|
32
|
-
|
33
|
-
def parse_pdf_object(obj)
|
34
|
-
PDF::Reader::Parser.new(
|
35
|
-
PDF::Reader::Buffer.new(sio = StringIO.new(obj)), nil).parse_token
|
36
|
-
end
|
37
|
-
|
38
|
-
def rb_flag
|
39
|
-
ruby_18 { "rb" } || ruby_19 { "rb:ASCII-8BIT" }
|
40
|
-
end
|
21
|
+
end
|
data/spec/table_spec.rb
CHANGED
@@ -12,17 +12,17 @@ describe "A table's width" do
|
|
12
12
|
end
|
13
13
|
|
14
14
|
it "should calculate unspecified column widths as "+
|
15
|
-
"(max(string_width) + 2*horizontal_padding)" do
|
15
|
+
"(max(string_width).ceil + 2*horizontal_padding)" do
|
16
16
|
pdf = Prawn::Document.new
|
17
17
|
hpad, fs = 3, 12
|
18
18
|
columns = 2
|
19
19
|
table = Prawn::Document::Table.new( [%w[ foo b ], %w[d foobar]], pdf,
|
20
20
|
:horizontal_padding => hpad, :font_size => fs)
|
21
21
|
|
22
|
-
col0_width = pdf.
|
23
|
-
col1_width = pdf.
|
22
|
+
col0_width = pdf.font.metrics.string_width("foo",fs)
|
23
|
+
col1_width = pdf.font.metrics.string_width("foobar",fs)
|
24
24
|
|
25
|
-
table.width.should == col0_width + col1_width + 2*columns*hpad
|
25
|
+
table.width.should == col0_width.ceil + col1_width.ceil + 2*columns*hpad
|
26
26
|
end
|
27
27
|
|
28
28
|
it "should allow mixing autocalculated and preset"+
|
@@ -33,8 +33,8 @@ describe "A table's width" do
|
|
33
33
|
stretchy_columns = 2
|
34
34
|
|
35
35
|
col0_width = 50
|
36
|
-
col1_width = pdf.
|
37
|
-
col2_width = pdf.
|
36
|
+
col1_width = pdf.font.metrics.string_width("foo",fs)
|
37
|
+
col2_width = pdf.font.metrics.string_width("foobar",fs)
|
38
38
|
col3_width = 150
|
39
39
|
|
40
40
|
table = Prawn::Document::Table.new( [%w[snake foo b apple],
|
@@ -42,76 +42,44 @@ describe "A table's width" do
|
|
42
42
|
:horizontal_padding => hpad, :font_size => fs,
|
43
43
|
:widths => { 0 => col0_width, 3 => col3_width } )
|
44
44
|
|
45
|
-
table.width.should == col1_width + col2_width +
|
46
|
-
|
45
|
+
table.width.should == col1_width.ceil + col2_width.ceil +
|
46
|
+
2*stretchy_columns*hpad +
|
47
|
+
col0_width.ceil + col3_width.ceil
|
47
48
|
|
48
49
|
end
|
50
|
+
|
51
|
+
end
|
49
52
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
pdf = Prawn::Document.new
|
54
|
-
|
55
|
-
pdf.table data
|
56
|
-
pdf.page_count.should == 2
|
57
|
-
|
58
|
-
pdf.table data
|
59
|
-
pdf.page_count.should == 3
|
60
|
-
end
|
61
|
-
|
62
|
-
it "should have a height of n rows + vertical padding" do
|
53
|
+
describe "A table's height" do
|
54
|
+
|
55
|
+
before :each do
|
63
56
|
data = [["foo"],["bar"],["baaaz"]]
|
64
57
|
pdf = Prawn::Document.new
|
65
|
-
num_rows = data.length
|
66
|
-
|
67
|
-
|
58
|
+
@num_rows = data.length
|
59
|
+
|
60
|
+
@vpad = 4
|
68
61
|
origin = pdf.y
|
69
|
-
pdf.table data, :vertical_padding => vpad
|
70
|
-
|
71
|
-
table_height = origin - pdf.y
|
72
|
-
|
73
|
-
font_height = pdf.font_metrics.font_height(12)
|
74
|
-
|
75
|
-
table_height.should.be.close(num_rows*font_height + 2*vpad*num_rows + vpad, 0.001)
|
76
|
-
end
|
62
|
+
pdf.table data, :vertical_padding => @vpad
|
77
63
|
|
78
|
-
|
64
|
+
@table_height = origin - pdf.y
|
79
65
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
def initialize
|
84
|
-
@font_settings = []
|
85
|
-
@fonts = {}
|
86
|
-
@strings = []
|
87
|
-
end
|
66
|
+
@font_height = pdf.font.height
|
67
|
+
end
|
88
68
|
|
89
|
-
|
90
|
-
@
|
69
|
+
it "should have a height of n rows" do
|
70
|
+
@table_height.should.be.close(
|
71
|
+
@num_rows*@font_height + 2*@vpad*@num_rows, 0.001 )
|
91
72
|
end
|
92
|
-
|
93
|
-
def set_text_font_and_size(*params)
|
94
|
-
@font_settings << { :name => @fonts[params[0]], :size => params[1] }
|
95
|
-
end
|
96
73
|
|
97
|
-
def show_text(*params)
|
98
|
-
@strings << params[0]
|
99
|
-
end
|
100
|
-
|
101
|
-
def show_text_with_positioning(*params)
|
102
|
-
# ignore kerning information
|
103
|
-
@strings << params[0].reject { |e| Numeric === e }.join
|
104
|
-
end
|
105
74
|
end
|
106
75
|
|
107
|
-
|
108
76
|
describe "A table's content" do
|
109
77
|
|
110
78
|
it "should output content cell by cell, row by row" do
|
111
79
|
data = [["foo","bar"],["baz","bang"]]
|
112
80
|
@pdf = Prawn::Document.new
|
113
81
|
@pdf.table(data)
|
114
|
-
output =
|
82
|
+
output = PDF::Inspector::Text.analyze(@pdf.render)
|
115
83
|
output.strings.should == data.flatten
|
116
84
|
end
|
117
85
|
|
@@ -120,7 +88,7 @@ describe "A table's content" do
|
|
120
88
|
headers = %w[a b]
|
121
89
|
@pdf = Prawn::Document.new
|
122
90
|
@pdf.table(data, :headers => headers)
|
123
|
-
output =
|
91
|
+
output = PDF::Inspector::Text.analyze(@pdf.render)
|
124
92
|
output.strings.should == headers + data.flatten
|
125
93
|
end
|
126
94
|
|
@@ -129,7 +97,7 @@ describe "A table's content" do
|
|
129
97
|
headers = ["baz","foobar"]
|
130
98
|
@pdf = Prawn::Document.new
|
131
99
|
@pdf.table(data, :headers => headers)
|
132
|
-
output =
|
100
|
+
output = PDF::Inspector::Text.analyze(@pdf.render)
|
133
101
|
output.strings.should == headers + data.flatten[0..-3] + headers +
|
134
102
|
data.flatten[-2..-1]
|
135
103
|
end
|
@@ -140,6 +108,32 @@ describe "A table's content" do
|
|
140
108
|
@pdf = Prawn::Document.new
|
141
109
|
@pdf.table(data)
|
142
110
|
}.should.not.raise
|
111
|
+
end
|
112
|
+
|
113
|
+
it "should paginate for large tables" do
|
114
|
+
# 30 rows fit on the table with default setting, 31 exceed.
|
115
|
+
data = [["foo"]] * 31
|
116
|
+
pdf = Prawn::Document.new
|
117
|
+
|
118
|
+
pdf.table data
|
119
|
+
pdf.page_count.should == 2
|
120
|
+
|
121
|
+
pdf.table data
|
122
|
+
pdf.page_count.should == 3
|
143
123
|
end
|
144
124
|
|
145
125
|
end
|
126
|
+
|
127
|
+
describe "An invalid table" do
|
128
|
+
|
129
|
+
before(:each) do
|
130
|
+
@pdf = Prawn::Document.new
|
131
|
+
@bad_data = ["Single Nested Array"]
|
132
|
+
end
|
133
|
+
|
134
|
+
it "should raise error when invalid table data is given" do
|
135
|
+
assert_raises(Prawn::Errors::InvalidTableData) do
|
136
|
+
@pdf.table(@bad_data)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
data/spec/text_spec.rb
CHANGED
@@ -1,69 +1,8 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
-
require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
|
3
|
+
require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
attr_accessor :font_settings, :size, :string
|
8
|
-
|
9
|
-
def initialize
|
10
|
-
@font_settings = []
|
11
|
-
@fonts = {}
|
12
|
-
end
|
13
|
-
|
14
|
-
def resource_font(*params)
|
15
|
-
@fonts[params[0]] = params[1].basefont
|
16
|
-
end
|
17
|
-
|
18
|
-
def set_text_font_and_size(*params)
|
19
|
-
@font_settings << { :name => @fonts[params[0]], :size => params[1] }
|
20
|
-
end
|
21
|
-
|
22
|
-
def show_text(*params)
|
23
|
-
@string = params[0]
|
24
|
-
end
|
25
|
-
|
26
|
-
def show_text_with_positioning(*params)
|
27
|
-
@string = params[0].join
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
class FontObserver
|
32
|
-
attr_accessor :page_fonts
|
33
|
-
|
34
|
-
def initialize
|
35
|
-
@page_fonts = []
|
36
|
-
end
|
37
|
-
|
38
|
-
def resource_font(*params)
|
39
|
-
@page_fonts.last << params[1].basefont
|
40
|
-
end
|
41
|
-
|
42
|
-
def begin_page(*params)
|
43
|
-
@page_fonts << []
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
describe "Font Metrics" do
|
48
|
-
|
49
|
-
it "should default to Helvetica if no font is specified" do
|
50
|
-
@pdf = Prawn::Document.new
|
51
|
-
@pdf.font_metrics.should == Prawn::Font::Metrics["Helvetica"]
|
52
|
-
end
|
53
|
-
|
54
|
-
it "should use the currently set font for font_metrics" do
|
55
|
-
@pdf = Prawn::Document.new
|
56
|
-
@pdf.font "Courier"
|
57
|
-
@pdf.font_metrics.should == Prawn::Font::Metrics["Courier"]
|
58
|
-
|
59
|
-
comicsans = "#{Prawn::BASEDIR}/data/fonts/comicsans.ttf"
|
60
|
-
@pdf.font(comicsans)
|
61
|
-
@pdf.font_metrics.should == Prawn::Font::Metrics[comicsans]
|
62
|
-
end
|
63
|
-
|
64
|
-
end
|
65
|
-
|
66
|
-
describe "when drawing text" do
|
5
|
+
describe "when drawing text" do
|
67
6
|
|
68
7
|
before(:each) { create_pdf }
|
69
8
|
|
@@ -71,92 +10,88 @@ describe "when drawing text" do
|
|
71
10
|
position = @pdf.y
|
72
11
|
@pdf.text "Foo"
|
73
12
|
|
74
|
-
@pdf.y.should.be.close(position - @pdf.
|
75
|
-
0.0001)
|
13
|
+
@pdf.y.should.be.close(position - @pdf.font.height, 0.0001)
|
76
14
|
|
77
15
|
position = @pdf.y
|
78
16
|
@pdf.text "Foo\nBar\nBaz"
|
79
|
-
@pdf.y.should.be.close(position - 3*@pdf.
|
80
|
-
0.0001)
|
17
|
+
@pdf.y.should.be.close(position - 3*@pdf.font.height, 0.0001)
|
81
18
|
end
|
82
19
|
|
83
20
|
it "should default to 12 point helvetica" do
|
84
21
|
@pdf.text "Blah", :at => [100,100]
|
85
|
-
text =
|
22
|
+
text = PDF::Inspector::Text.analyze(@pdf.render)
|
86
23
|
text.font_settings[0][:name].should == :Helvetica
|
87
24
|
text.font_settings[0][:size].should == 12
|
88
|
-
text.
|
25
|
+
text.strings.first.should == "Blah"
|
89
26
|
end
|
90
27
|
|
91
28
|
it "should allow setting font size" do
|
92
29
|
@pdf.text "Blah", :at => [100,100], :size => 16
|
93
|
-
text =
|
30
|
+
text = PDF::Inspector::Text.analyze(@pdf.render)
|
94
31
|
text.font_settings[0][:size].should == 16
|
95
32
|
end
|
96
33
|
|
97
34
|
it "should allow setting a default font size" do
|
98
|
-
@pdf.
|
35
|
+
@pdf.font.size = 16
|
99
36
|
@pdf.text "Blah"
|
100
|
-
text =
|
37
|
+
text = PDF::Inspector::Text.analyze(@pdf.render)
|
101
38
|
text.font_settings[0][:size].should == 16
|
102
39
|
end
|
103
40
|
|
104
41
|
it "should allow overriding default font for a single instance" do
|
105
|
-
@pdf.
|
42
|
+
@pdf.font.size = 16
|
106
43
|
|
107
44
|
@pdf.text "Blah", :size => 11
|
108
45
|
@pdf.text "Blaz"
|
109
|
-
text =
|
46
|
+
text = PDF::Inspector::Text.analyze(@pdf.render)
|
110
47
|
text.font_settings[0][:size].should == 11
|
111
48
|
text.font_settings[1][:size].should == 16
|
112
49
|
end
|
113
50
|
|
114
|
-
|
115
51
|
it "should allow setting a font size transaction with a block" do
|
116
|
-
@pdf.
|
52
|
+
@pdf.font.size 16 do
|
117
53
|
@pdf.text 'Blah'
|
118
54
|
end
|
119
55
|
|
120
56
|
@pdf.text 'blah'
|
121
57
|
|
122
|
-
text =
|
58
|
+
text = PDF::Inspector::Text.analyze(@pdf.render)
|
123
59
|
text.font_settings[0][:size].should == 16
|
124
60
|
text.font_settings[1][:size].should == 12
|
125
61
|
end
|
126
62
|
|
127
63
|
it "should allow manual setting the font size " +
|
128
64
|
"when in a font size block" do
|
129
|
-
@pdf.
|
65
|
+
@pdf.font.size(16) do
|
130
66
|
@pdf.text 'Foo'
|
131
67
|
@pdf.text 'Blah', :size => 11
|
132
68
|
@pdf.text 'Blaz'
|
133
69
|
end
|
134
|
-
text =
|
70
|
+
text = PDF::Inspector::Text.analyze(@pdf.render)
|
135
71
|
text.font_settings[0][:size].should == 16
|
136
72
|
text.font_settings[1][:size].should == 11
|
137
73
|
text.font_settings[2][:size].should == 16
|
138
74
|
end
|
139
75
|
|
140
76
|
it "should allow registering of built-in font_settings on the fly" do
|
141
|
-
@pdf.font "
|
77
|
+
@pdf.font "Times-Roman"
|
142
78
|
@pdf.text "Blah", :at => [100,100]
|
143
|
-
@pdf.font "
|
79
|
+
@pdf.font "Courier"
|
144
80
|
@pdf.text "Blaz", :at => [150,150]
|
145
|
-
text =
|
146
|
-
|
147
|
-
text.font_settings[
|
148
|
-
text.font_settings[1][:name].should == :"Times-Roman"
|
81
|
+
text = PDF::Inspector::Text.analyze(@pdf.render)
|
82
|
+
text.font_settings[0][:name].should == :"Times-Roman"
|
83
|
+
text.font_settings[1][:name].should == :Courier
|
149
84
|
end
|
150
85
|
|
151
86
|
it "should utilise the same default font across multiple pages" do
|
152
87
|
@pdf.text "Blah", :at => [100,100]
|
153
88
|
@pdf.start_new_page
|
154
89
|
@pdf.text "Blaz", :at => [150,150]
|
155
|
-
text =
|
90
|
+
text = PDF::Inspector::Text.analyze(@pdf.render)
|
156
91
|
|
157
|
-
text.
|
158
|
-
text.
|
159
|
-
text.
|
92
|
+
text.font_settings.size.should == 2
|
93
|
+
text.font_settings[0][:name].should == :Helvetica
|
94
|
+
text.font_settings[1][:name].should == :Helvetica
|
160
95
|
end
|
161
96
|
|
162
97
|
it "should raise an exception when an unknown font is used" do
|
@@ -168,10 +103,10 @@ describe "when drawing text" do
|
|
168
103
|
@pdf.text str
|
169
104
|
|
170
105
|
# grab the text from the rendered PDF and ensure it matches
|
171
|
-
text =
|
172
|
-
text.
|
106
|
+
text = PDF::Inspector::Text.analyze(@pdf.render)
|
107
|
+
text.strings.first.should == str
|
173
108
|
end
|
174
|
-
|
109
|
+
|
175
110
|
if "spec".respond_to?(:encode!)
|
176
111
|
# Handle non utf-8 string encodings in a sane way on M17N aware VMs
|
177
112
|
it "should raise an exception when a utf-8 incompatible string is rendered" do
|
@@ -195,6 +130,6 @@ describe "when drawing text" do
|
|
195
130
|
sjis_str = File.read("#{Prawn::BASEDIR}/data/shift_jis_text.txt")
|
196
131
|
lambda { @pdf.text sjis_str }.should.raise(Prawn::Errors::IncompatibleStringEncoding)
|
197
132
|
end
|
198
|
-
end
|
133
|
+
end
|
199
134
|
|
200
135
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
PDF::Inspector : A tool for analyzing PDF output
|
2
|
+
|
3
|
+
This library provides a number of PDF::Reader[0] based tools for use in testing
|
4
|
+
PDF output. Presently, the primary purpose of this tool is to support the
|
5
|
+
tests found in Prawn[1], a pure Ruby PDF generation library.
|
6
|
+
|
7
|
+
However, it may be useful to others, so we have made it available on Github[2]
|
8
|
+
|
9
|
+
Questions can be directed to the Prawn mailing list[3], but please remember
|
10
|
+
that this code is not necessarily suitable for production and has no officially
|
11
|
+
planned release date.
|
12
|
+
|
13
|
+
That having been said, patches are welcome!
|
14
|
+
|
15
|
+
[0] http://github.com/yob/pdf-reader
|
16
|
+
[1] http://github.com/sandal/prawn
|
17
|
+
[2] http://github.com/sandal/pdf-inspector
|
18
|
+
[3] http://groups.google.com/group/prawn-ruby
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "pdf/reader"
|
3
|
+
require "pdf/inspector/text"
|
4
|
+
require "pdf/inspector/xobject"
|
5
|
+
require "pdf/inspector/graphics"
|
6
|
+
require "pdf/inspector/page"
|
7
|
+
|
8
|
+
module PDF
|
9
|
+
class Inspector
|
10
|
+
def self.analyze(output,*args,&block)
|
11
|
+
obs = self.new(*args, &block)
|
12
|
+
PDF::Reader.string(output,obs)
|
13
|
+
obs
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.analyze_file(filename,*args,&block)
|
17
|
+
analyze(File.open(filenmame, "rb") { |f| f.read },*args,&block)
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.parse(obj)
|
21
|
+
PDF::Reader::Parser.new(
|
22
|
+
PDF::Reader::Buffer.new(StringIO.new(obj)), nil).parse_token
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|