prawn 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|