prawn 2.0.1 → 2.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Rakefile +7 -5
- data/lib/prawn.rb +4 -4
- data/lib/prawn/document.rb +47 -46
- data/lib/prawn/document/bounding_box.rb +13 -19
- data/lib/prawn/document/column_box.rb +3 -5
- data/lib/prawn/document/internals.rb +0 -1
- data/lib/prawn/document/span.rb +12 -12
- data/lib/prawn/errors.rb +32 -33
- data/lib/prawn/font.rb +29 -36
- data/lib/prawn/font/afm.rb +20 -20
- data/lib/prawn/font/dfont.rb +0 -1
- data/lib/prawn/font/ttf.rb +30 -27
- data/lib/prawn/font_metric_cache.rb +4 -8
- data/lib/prawn/graphics.rb +37 -42
- data/lib/prawn/graphics/cap_style.rb +1 -1
- data/lib/prawn/graphics/color.rb +21 -23
- data/lib/prawn/graphics/dash.rb +5 -6
- data/lib/prawn/graphics/join_style.rb +1 -2
- data/lib/prawn/graphics/patterns.rb +25 -21
- data/lib/prawn/graphics/transformation.rb +4 -5
- data/lib/prawn/graphics/transparency.rb +6 -8
- data/lib/prawn/grid.rb +21 -14
- data/lib/prawn/image_handler.rb +2 -2
- data/lib/prawn/images.rb +29 -31
- data/lib/prawn/images/image.rb +1 -1
- data/lib/prawn/images/jpg.rb +10 -12
- data/lib/prawn/images/png.rb +13 -13
- data/lib/prawn/measurements.rb +7 -14
- data/lib/prawn/outline.rb +6 -6
- data/lib/prawn/repeater.rb +1 -5
- data/lib/prawn/security.rb +17 -25
- data/lib/prawn/security/arcfour.rb +1 -1
- data/lib/prawn/soft_mask.rb +11 -12
- data/lib/prawn/stamp.rb +16 -8
- data/lib/prawn/text.rb +23 -20
- data/lib/prawn/text/box.rb +3 -6
- data/lib/prawn/text/formatted/arranger.rb +9 -12
- data/lib/prawn/text/formatted/box.rb +23 -22
- data/lib/prawn/text/formatted/fragment.rb +0 -4
- data/lib/prawn/text/formatted/line_wrap.rb +13 -24
- data/lib/prawn/text/formatted/parser.rb +16 -20
- data/lib/prawn/text/formatted/wrap.rb +2 -7
- data/lib/prawn/utilities.rb +6 -3
- data/lib/prawn/version.rb +1 -1
- data/manual/basic_concepts/basic_concepts.rb +0 -2
- data/manual/basic_concepts/view.rb +1 -1
- data/manual/bounding_box/bounding_box.rb +0 -3
- data/manual/bounding_box/russian_boxes.rb +7 -8
- data/manual/bounding_box/stretchy.rb +0 -1
- data/manual/contents.rb +2 -2
- data/manual/cover.rb +11 -12
- data/manual/document_and_page_options/document_and_page_options.rb +2 -5
- data/manual/document_and_page_options/metadata.rb +10 -10
- data/manual/document_and_page_options/page_size.rb +0 -1
- data/manual/graphics/fill_rules.rb +5 -4
- data/manual/graphics/graphics.rb +0 -3
- data/manual/graphics/lines_and_curves.rb +1 -1
- data/manual/graphics/rotate.rb +0 -2
- data/manual/graphics/scale.rb +4 -2
- data/manual/graphics/soft_masks.rb +0 -1
- data/manual/graphics/stroke_cap.rb +1 -1
- data/manual/graphics/stroke_join.rb +1 -1
- data/manual/graphics/translate.rb +3 -3
- data/manual/graphics/transparency.rb +0 -1
- data/manual/how_to_read_this_manual.rb +0 -1
- data/manual/images/images.rb +0 -3
- data/manual/layout/boxes.rb +5 -5
- data/manual/layout/content.rb +2 -2
- data/manual/layout/layout.rb +0 -3
- data/manual/outline/outline.rb +0 -3
- data/manual/repeatable_content/page_numbering.rb +1 -1
- data/manual/repeatable_content/repeatable_content.rb +0 -3
- data/manual/repeatable_content/repeater.rb +6 -6
- data/manual/security/encryption.rb +0 -2
- data/manual/security/permissions.rb +0 -2
- data/manual/security/security.rb +0 -3
- data/manual/text/alignment.rb +3 -3
- data/manual/text/color.rb +0 -1
- data/manual/text/column_box.rb +0 -1
- data/manual/text/fallback_fonts.rb +2 -2
- data/manual/text/formatted_callbacks.rb +3 -2
- data/manual/text/paragraph_indentation.rb +2 -3
- data/manual/text/registering_families.rb +13 -9
- data/manual/text/rotation.rb +0 -1
- data/manual/text/text.rb +0 -3
- data/manual/text/text_box_overflow.rb +7 -5
- data/manual/text/utf8.rb +1 -1
- data/manual/text/win_ansi_charset.rb +2 -2
- data/prawn.gemspec +4 -4
- data/spec/acceptance/png.rb +6 -7
- data/spec/annotations_spec.rb +21 -28
- data/spec/bounding_box_spec.rb +100 -109
- data/spec/column_box_spec.rb +26 -32
- data/spec/destinations_spec.rb +2 -4
- data/spec/document_spec.rb +145 -151
- data/spec/extensions/mocha.rb +0 -1
- data/spec/font_metric_cache_spec.rb +7 -7
- data/spec/font_spec.rb +103 -102
- data/spec/formatted_text_arranger_spec.rb +76 -74
- data/spec/formatted_text_box_spec.rb +170 -159
- data/spec/formatted_text_fragment_spec.rb +57 -56
- data/spec/graphics_spec.rb +158 -175
- data/spec/grid_spec.rb +28 -29
- data/spec/image_handler_spec.rb +4 -5
- data/spec/images_spec.rb +50 -36
- data/spec/inline_formatted_text_parser_spec.rb +397 -393
- data/spec/jpg_spec.rb +4 -6
- data/spec/line_wrap_spec.rb +54 -55
- data/spec/measurement_units_spec.rb +12 -15
- data/spec/outline_spec.rb +77 -98
- data/spec/png_spec.rb +55 -65
- data/spec/reference_spec.rb +3 -3
- data/spec/repeater_spec.rb +20 -26
- data/spec/security_spec.rb +42 -49
- data/spec/soft_mask_spec.rb +4 -5
- data/spec/span_spec.rb +5 -6
- data/spec/spec_helper.rb +2 -4
- data/spec/stamp_spec.rb +41 -22
- data/spec/stroke_styles_spec.rb +36 -39
- data/spec/text_at_spec.rb +28 -29
- data/spec/text_box_spec.rb +160 -165
- data/spec/text_rendering_mode_spec.rb +9 -9
- data/spec/text_spacing_spec.rb +13 -13
- data/spec/text_spec.rb +116 -124
- data/spec/text_with_inline_formatting_spec.rb +5 -5
- data/spec/transparency_spec.rb +20 -20
- data/spec/view_spec.rb +0 -1
- metadata +7 -7
data/spec/png_spec.rb
CHANGED
@@ -10,7 +10,6 @@
|
|
10
10
|
require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
|
11
11
|
|
12
12
|
describe "When reading a greyscale PNG file (color type 0)" do
|
13
|
-
|
14
13
|
before(:each) do
|
15
14
|
@filename = "#{Prawn::DATADIR}/images/web-links.png"
|
16
15
|
@data_filename = "#{Prawn::DATADIR}/images/web-links.dat"
|
@@ -20,24 +19,23 @@ describe "When reading a greyscale PNG file (color type 0)" do
|
|
20
19
|
it "should read the attributes from the header chunk correctly" do
|
21
20
|
png = Prawn::Images::PNG.new(@img_data)
|
22
21
|
|
23
|
-
png.width.
|
24
|
-
png.height.
|
25
|
-
png.bits.
|
26
|
-
png.color_type.
|
27
|
-
png.compression_method.
|
28
|
-
png.filter_method.
|
29
|
-
png.interlace_method.
|
22
|
+
expect(png.width).to eq(21)
|
23
|
+
expect(png.height).to eq(14)
|
24
|
+
expect(png.bits).to eq(8)
|
25
|
+
expect(png.color_type).to eq(0)
|
26
|
+
expect(png.compression_method).to eq(0)
|
27
|
+
expect(png.filter_method).to eq(0)
|
28
|
+
expect(png.interlace_method).to eq(0)
|
30
29
|
end
|
31
30
|
|
32
31
|
it "should read the image data chunk correctly" do
|
33
32
|
png = Prawn::Images::PNG.new(@img_data)
|
34
33
|
data = Zlib::Inflate.inflate(File.binread(@data_filename))
|
35
|
-
png.img_data.
|
34
|
+
expect(png.img_data).to eq(data)
|
36
35
|
end
|
37
36
|
end
|
38
37
|
|
39
38
|
describe "When reading a greyscale PNG file with transparency (color type 0)" do
|
40
|
-
|
41
39
|
before(:each) do
|
42
40
|
@filename = "#{Prawn::DATADIR}/images/ruport_type0.png"
|
43
41
|
@img_data = File.binread(@filename)
|
@@ -49,12 +47,11 @@ describe "When reading a greyscale PNG file with transparency (color type 0)" do
|
|
49
47
|
# http://www.w3.org/TR/PNG/#11tRNS
|
50
48
|
it "should read the tRNS chunk correctly" do
|
51
49
|
png = Prawn::Images::PNG.new(@img_data)
|
52
|
-
png.transparency[:grayscale].
|
50
|
+
expect(png.transparency[:grayscale]).to eq(255)
|
53
51
|
end
|
54
52
|
end
|
55
53
|
|
56
54
|
describe "When reading an RGB PNG file (color type 2)" do
|
57
|
-
|
58
55
|
before(:each) do
|
59
56
|
@filename = "#{Prawn::DATADIR}/images/ruport.png"
|
60
57
|
@data_filename = "#{Prawn::DATADIR}/images/ruport_data.dat"
|
@@ -64,24 +61,23 @@ describe "When reading an RGB PNG file (color type 2)" do
|
|
64
61
|
it "should read the attributes from the header chunk correctly" do
|
65
62
|
png = Prawn::Images::PNG.new(@img_data)
|
66
63
|
|
67
|
-
png.width.
|
68
|
-
png.height.
|
69
|
-
png.bits.
|
70
|
-
png.color_type.
|
71
|
-
png.compression_method.
|
72
|
-
png.filter_method.
|
73
|
-
png.interlace_method.
|
64
|
+
expect(png.width).to eq(258)
|
65
|
+
expect(png.height).to eq(105)
|
66
|
+
expect(png.bits).to eq(8)
|
67
|
+
expect(png.color_type).to eq(2)
|
68
|
+
expect(png.compression_method).to eq(0)
|
69
|
+
expect(png.filter_method).to eq(0)
|
70
|
+
expect(png.interlace_method).to eq(0)
|
74
71
|
end
|
75
72
|
|
76
73
|
it "should read the image data chunk correctly" do
|
77
74
|
png = Prawn::Images::PNG.new(@img_data)
|
78
75
|
data = Zlib::Inflate.inflate(File.binread(@data_filename))
|
79
|
-
png.img_data.
|
76
|
+
expect(png.img_data).to eq(data)
|
80
77
|
end
|
81
78
|
end
|
82
79
|
|
83
80
|
describe "When reading an RGB PNG file with transparency (color type 2)" do
|
84
|
-
|
85
81
|
before(:each) do
|
86
82
|
@filename = "#{Prawn::DATADIR}/images/arrow2.png"
|
87
83
|
@img_data = File.binread(@filename)
|
@@ -94,22 +90,19 @@ describe "When reading an RGB PNG file with transparency (color type 2)" do
|
|
94
90
|
# http://www.w3.org/TR/PNG/#11tRNS
|
95
91
|
it "should read the tRNS chunk correctly" do
|
96
92
|
png = Prawn::Images::PNG.new(@img_data)
|
97
|
-
png.transparency[:rgb].
|
93
|
+
expect(png.transparency[:rgb]).to eq([0, 255, 0])
|
98
94
|
end
|
99
95
|
end
|
100
96
|
|
101
|
-
describe "When reading an indexed color PNG file "
|
102
|
-
"wiih transparency (color type 3)" do
|
103
|
-
|
97
|
+
describe "When reading an indexed color PNG file with transparency (color type 3)" do
|
104
98
|
it "raises a not supported error" do
|
105
99
|
bin = File.binread("#{Prawn::DATADIR}/images/pal_bk.png")
|
106
|
-
expect { Prawn::Images::PNG.new(bin)}.to(
|
100
|
+
expect { Prawn::Images::PNG.new(bin) }.to(
|
107
101
|
raise_error(Prawn::Errors::UnsupportedImageType))
|
108
102
|
end
|
109
103
|
end
|
110
104
|
|
111
105
|
describe "When reading an indexed color PNG file (color type 3)" do
|
112
|
-
|
113
106
|
before(:each) do
|
114
107
|
@filename = "#{Prawn::DATADIR}/images/indexed_color.png"
|
115
108
|
@data_filename = "#{Prawn::DATADIR}/images/indexed_color.dat"
|
@@ -119,24 +112,23 @@ describe "When reading an indexed color PNG file (color type 3)" do
|
|
119
112
|
it "should read the attributes from the header chunk correctly" do
|
120
113
|
png = Prawn::Images::PNG.new(@img_data)
|
121
114
|
|
122
|
-
png.width.
|
123
|
-
png.height.
|
124
|
-
png.bits.
|
125
|
-
png.color_type.
|
126
|
-
png.compression_method.
|
127
|
-
png.filter_method.
|
128
|
-
png.interlace_method.
|
115
|
+
expect(png.width).to eq(150)
|
116
|
+
expect(png.height).to eq(200)
|
117
|
+
expect(png.bits).to eq(8)
|
118
|
+
expect(png.color_type).to eq(3)
|
119
|
+
expect(png.compression_method).to eq(0)
|
120
|
+
expect(png.filter_method).to eq(0)
|
121
|
+
expect(png.interlace_method).to eq(0)
|
129
122
|
end
|
130
123
|
|
131
124
|
it "should read the image data chunk correctly" do
|
132
125
|
png = Prawn::Images::PNG.new(@img_data)
|
133
126
|
data = Zlib::Inflate.inflate(File.binread(@data_filename))
|
134
|
-
png.img_data.
|
127
|
+
expect(png.img_data).to eq(data)
|
135
128
|
end
|
136
129
|
end
|
137
130
|
|
138
131
|
describe "When reading a greyscale+alpha PNG file (color type 4)" do
|
139
|
-
|
140
132
|
before(:each) do
|
141
133
|
@filename = "#{Prawn::DATADIR}/images/page_white_text.png"
|
142
134
|
@color_data_filename = "#{Prawn::DATADIR}/images/page_white_text.color"
|
@@ -147,32 +139,31 @@ describe "When reading a greyscale+alpha PNG file (color type 4)" do
|
|
147
139
|
it "should read the attributes from the header chunk correctly" do
|
148
140
|
png = Prawn::Images::PNG.new(@img_data)
|
149
141
|
|
150
|
-
png.width.
|
151
|
-
png.height.
|
152
|
-
png.bits.
|
153
|
-
png.color_type.
|
154
|
-
png.compression_method.
|
155
|
-
png.filter_method.
|
156
|
-
png.interlace_method.
|
142
|
+
expect(png.width).to eq(16)
|
143
|
+
expect(png.height).to eq(16)
|
144
|
+
expect(png.bits).to eq(8)
|
145
|
+
expect(png.color_type).to eq(4)
|
146
|
+
expect(png.compression_method).to eq(0)
|
147
|
+
expect(png.filter_method).to eq(0)
|
148
|
+
expect(png.interlace_method).to eq(0)
|
157
149
|
end
|
158
150
|
|
159
151
|
it "should correctly return the raw image data (with no alpha channel) from the image data chunk" do
|
160
152
|
png = Prawn::Images::PNG.new(@img_data)
|
161
153
|
png.split_alpha_channel!
|
162
154
|
data = File.binread(@color_data_filename)
|
163
|
-
png.img_data.
|
155
|
+
expect(png.img_data).to eq(data)
|
164
156
|
end
|
165
157
|
|
166
158
|
it "should correctly extract the alpha channel data from the image data chunk" do
|
167
159
|
png = Prawn::Images::PNG.new(@img_data)
|
168
160
|
png.split_alpha_channel!
|
169
161
|
data = File.binread(@alpha_data_filename)
|
170
|
-
png.alpha_channel.
|
162
|
+
expect(png.alpha_channel).to eq(data)
|
171
163
|
end
|
172
164
|
end
|
173
165
|
|
174
166
|
describe "When reading an RGB+alpha PNG file (color type 6)" do
|
175
|
-
|
176
167
|
before(:each) do
|
177
168
|
@filename = "#{Prawn::DATADIR}/images/dice.png"
|
178
169
|
@color_data_filename = "#{Prawn::DATADIR}/images/dice.color"
|
@@ -183,32 +174,31 @@ describe "When reading an RGB+alpha PNG file (color type 6)" do
|
|
183
174
|
it "should read the attributes from the header chunk correctly" do
|
184
175
|
png = Prawn::Images::PNG.new(@img_data)
|
185
176
|
|
186
|
-
png.width.
|
187
|
-
png.height.
|
188
|
-
png.bits.
|
189
|
-
png.color_type.
|
190
|
-
png.compression_method.
|
191
|
-
png.filter_method.
|
192
|
-
png.interlace_method.
|
177
|
+
expect(png.width).to eq(320)
|
178
|
+
expect(png.height).to eq(240)
|
179
|
+
expect(png.bits).to eq(8)
|
180
|
+
expect(png.color_type).to eq(6)
|
181
|
+
expect(png.compression_method).to eq(0)
|
182
|
+
expect(png.filter_method).to eq(0)
|
183
|
+
expect(png.interlace_method).to eq(0)
|
193
184
|
end
|
194
185
|
|
195
186
|
it "should correctly return the raw image data (with no alpha channel) from the image data chunk" do
|
196
187
|
png = Prawn::Images::PNG.new(@img_data)
|
197
188
|
png.split_alpha_channel!
|
198
189
|
data = File.binread(@color_data_filename)
|
199
|
-
png.img_data.
|
190
|
+
expect(png.img_data).to eq(data)
|
200
191
|
end
|
201
192
|
|
202
193
|
it "should correctly extract the alpha channel data from the image data chunk" do
|
203
194
|
png = Prawn::Images::PNG.new(@img_data)
|
204
195
|
png.split_alpha_channel!
|
205
196
|
data = File.binread(@alpha_data_filename)
|
206
|
-
png.alpha_channel.
|
197
|
+
expect(png.alpha_channel).to eq(data)
|
207
198
|
end
|
208
199
|
end
|
209
200
|
|
210
201
|
describe "When reading a 16bit RGB+alpha PNG file (color type 6)" do
|
211
|
-
|
212
202
|
before(:each) do
|
213
203
|
@filename = "#{Prawn::DATADIR}/images/16bit.png"
|
214
204
|
@color_data_filename = "#{Prawn::DATADIR}/images/16bit.color"
|
@@ -220,26 +210,26 @@ describe "When reading a 16bit RGB+alpha PNG file (color type 6)" do
|
|
220
210
|
it "should read the attributes from the header chunk correctly" do
|
221
211
|
png = Prawn::Images::PNG.new(@img_data)
|
222
212
|
|
223
|
-
png.width.
|
224
|
-
png.height.
|
225
|
-
png.bits.
|
226
|
-
png.color_type.
|
227
|
-
png.compression_method.
|
228
|
-
png.filter_method.
|
229
|
-
png.interlace_method.
|
213
|
+
expect(png.width).to eq(32)
|
214
|
+
expect(png.height).to eq(32)
|
215
|
+
expect(png.bits).to eq(16)
|
216
|
+
expect(png.color_type).to eq(6)
|
217
|
+
expect(png.compression_method).to eq(0)
|
218
|
+
expect(png.filter_method).to eq(0)
|
219
|
+
expect(png.interlace_method).to eq(0)
|
230
220
|
end
|
231
221
|
|
232
222
|
it "should correctly return the raw image data (with no alpha channel) from the image data chunk" do
|
233
223
|
png = Prawn::Images::PNG.new(@img_data)
|
234
224
|
png.split_alpha_channel!
|
235
225
|
data = File.binread(@color_data_filename)
|
236
|
-
png.img_data.
|
226
|
+
expect(png.img_data).to eq(data)
|
237
227
|
end
|
238
228
|
|
239
229
|
it "should correctly extract the alpha channel data from the image data chunk" do
|
240
230
|
png = Prawn::Images::PNG.new(@img_data)
|
241
231
|
png.split_alpha_channel!
|
242
232
|
data = File.binread(@alpha_data_filename)
|
243
|
-
png.alpha_channel.
|
233
|
+
expect(png.alpha_channel).to eq(data)
|
244
234
|
end
|
245
235
|
end
|
data/spec/reference_spec.rb
CHANGED
@@ -6,20 +6,20 @@ describe "A Reference object" do
|
|
6
6
|
describe "generated via Prawn::Document" do
|
7
7
|
it "should return a proper reference on ref!" do
|
8
8
|
pdf = Prawn::Document.new
|
9
|
-
pdf.ref!({}).is_a?(PDF::Core::Reference).
|
9
|
+
expect(pdf.ref!({}).is_a?(PDF::Core::Reference)).to eq(true)
|
10
10
|
end
|
11
11
|
|
12
12
|
it "should return an identifier on ref" do
|
13
13
|
pdf = Prawn::Document.new
|
14
14
|
r = pdf.ref({})
|
15
|
-
r.is_a?(Integer).
|
15
|
+
expect(r.is_a?(Integer)).to eq(true)
|
16
16
|
end
|
17
17
|
|
18
18
|
it "should have :Length of stream if it has one when compression disabled" do
|
19
19
|
pdf = Prawn::Document.new :compress => false
|
20
20
|
ref = pdf.ref!({})
|
21
21
|
ref << 'Hello'
|
22
|
-
ref.stream.data[:Length].
|
22
|
+
expect(ref.stream.data[:Length]).to eq(5)
|
23
23
|
end
|
24
24
|
end
|
25
25
|
end
|
data/spec/repeater_spec.rb
CHANGED
@@ -3,7 +3,6 @@
|
|
3
3
|
require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
|
4
4
|
|
5
5
|
describe "Repeaters" do
|
6
|
-
|
7
6
|
it "creates a stamp and increments Prawn::Repeater.count on initialize" do
|
8
7
|
orig_count = Prawn::Repeater.count
|
9
8
|
|
@@ -12,45 +11,45 @@ describe "Repeaters" do
|
|
12
11
|
|
13
12
|
r = repeater(doc, :all) { :do_nothing }
|
14
13
|
|
15
|
-
Prawn::Repeater.count.
|
14
|
+
expect(Prawn::Repeater.count).to eq(orig_count + 1)
|
16
15
|
end
|
17
16
|
|
18
17
|
it "must provide an :all filter" do
|
19
18
|
doc = sample_document
|
20
19
|
r = repeater(doc, :all) { :do_nothing }
|
21
20
|
|
22
|
-
(1..doc.page_count).all? { |i| r.match?(i) }.
|
21
|
+
expect((1..doc.page_count).all? { |i| r.match?(i) }).to be_true
|
23
22
|
end
|
24
23
|
|
25
24
|
it "must provide an :odd filter" do
|
26
25
|
doc = sample_document
|
27
26
|
r = repeater(doc, :odd) { :do_nothing }
|
28
27
|
|
29
|
-
odd, even = (1..doc.page_count).partition
|
28
|
+
odd, even = (1..doc.page_count).partition(&:odd?)
|
30
29
|
|
31
|
-
odd.all? { |i| r.match?(i) }.
|
32
|
-
even.any? { |i| r.match?(i) }.
|
30
|
+
expect(odd.all? { |i| r.match?(i) }).to be_true
|
31
|
+
expect(even.any? { |i| r.match?(i) }).to be_false
|
33
32
|
end
|
34
33
|
|
35
34
|
it "must be able to filter by an array of page numbers" do
|
36
35
|
doc = sample_document
|
37
|
-
r = repeater(doc, [1,2,7]) { :do_nothing }
|
36
|
+
r = repeater(doc, [1, 2, 7]) { :do_nothing }
|
38
37
|
|
39
|
-
(1..10).select { |i| r.match?(i) }.
|
38
|
+
expect((1..10).select { |i| r.match?(i) }).to eq([1, 2, 7])
|
40
39
|
end
|
41
40
|
|
42
41
|
it "must be able to filter by a range of page numbers" do
|
43
42
|
doc = sample_document
|
44
43
|
r = repeater(doc, 2..4) { :do_nothing }
|
45
44
|
|
46
|
-
(1..10).select { |i| r.match?(i) }.
|
45
|
+
expect((1..10).select { |i| r.match?(i) }).to eq([2, 3, 4])
|
47
46
|
end
|
48
47
|
|
49
48
|
it "must be able to filter by an arbitrary proc" do
|
50
49
|
doc = sample_document
|
51
50
|
r = repeater(doc, lambda { |x| x == 1 or x % 3 == 0 })
|
52
51
|
|
53
|
-
(1..10).select { |i| r.match?(i) }.
|
52
|
+
expect((1..10).select { |i| r.match?(i) }).to eq([1, 3, 6, 9])
|
54
53
|
end
|
55
54
|
|
56
55
|
it "must try to run a stamp if the page number matches" do
|
@@ -71,21 +70,21 @@ describe "Repeaters" do
|
|
71
70
|
doc = sample_document
|
72
71
|
|
73
72
|
doc.expects(:stamp).never
|
74
|
-
(1..10).each { |p| repeater(doc, :all, true){:do_nothing}.run(p) }
|
73
|
+
(1..10).each { |p| repeater(doc, :all, true){ :do_nothing }.run(p) }
|
75
74
|
end
|
76
75
|
|
77
76
|
it "must try to run a block if the page number matches" do
|
78
77
|
doc = sample_document
|
79
78
|
|
80
79
|
doc.expects(:draw_text).twice
|
81
|
-
(1..10).each { |p| repeater(doc, [1,2], true){doc.draw_text "foo"}.run(p) }
|
80
|
+
(1..10).each { |p| repeater(doc, [1, 2], true){ doc.draw_text "foo" }.run(p) }
|
82
81
|
end
|
83
82
|
|
84
83
|
it "must not try to run a block unless the page number matches" do
|
85
84
|
doc = sample_document
|
86
85
|
|
87
86
|
doc.expects(:draw_text).never
|
88
|
-
repeater(doc, :odd, true){doc.draw_text "foo"}.run(2)
|
87
|
+
repeater(doc, :odd, true){ doc.draw_text "foo" }.run(2)
|
89
88
|
end
|
90
89
|
|
91
90
|
it "must treat any block as a closure" do
|
@@ -97,7 +96,7 @@ describe "Repeaters" do
|
|
97
96
|
end
|
98
97
|
|
99
98
|
text = PDF::Inspector::Text.analyze(doc.render)
|
100
|
-
text.strings.
|
99
|
+
expect(text.strings).to eq((1..10).to_a.map{ |p| "Page #{p}" })
|
101
100
|
end
|
102
101
|
|
103
102
|
it "must treat any block as a closure (Document.new instance_eval form)" do
|
@@ -112,7 +111,7 @@ describe "Repeaters" do
|
|
112
111
|
end
|
113
112
|
|
114
113
|
text = PDF::Inspector::Text.analyze(doc.render)
|
115
|
-
text.strings.
|
114
|
+
expect(text.strings).to eq((1..10).to_a.map{ |p| "Page #{p}" })
|
116
115
|
end
|
117
116
|
|
118
117
|
def sample_document
|
@@ -122,22 +121,20 @@ describe "Repeaters" do
|
|
122
121
|
end
|
123
122
|
|
124
123
|
def repeater(*args, &b)
|
125
|
-
Prawn::Repeater.new(*args
|
124
|
+
Prawn::Repeater.new(*args, &b)
|
126
125
|
end
|
127
126
|
|
128
127
|
context "graphic state" do
|
129
|
-
|
130
128
|
it "should not alter the graphic state stack color space" do
|
131
129
|
create_pdf
|
132
130
|
starting_color_space = @pdf.state.page.graphic_state.color_space.dup
|
133
131
|
@pdf.repeat :all do
|
134
132
|
@pdf.text "Testing", :size => 24, :style => :bold
|
135
133
|
end
|
136
|
-
@pdf.state.page.graphic_state.color_space.
|
134
|
+
expect(@pdf.state.page.graphic_state.color_space).to eq(starting_color_space)
|
137
135
|
end
|
138
136
|
|
139
137
|
context "dynamic repeaters" do
|
140
|
-
|
141
138
|
it "should preserve the graphic state at creation time" do
|
142
139
|
create_pdf
|
143
140
|
@pdf.repeat :all, :dynamic => true do
|
@@ -147,14 +144,11 @@ describe "Repeaters" do
|
|
147
144
|
@pdf.fill_color "666666"
|
148
145
|
@pdf.cap_style :round
|
149
146
|
text = PDF::Inspector::Text.analyze(@pdf.render)
|
150
|
-
text.strings.include?("fill_color: 666666").
|
151
|
-
text.strings.include?("fill_color: 000000").
|
152
|
-
text.strings.include?("cap_style: round").
|
153
|
-
text.strings.include?("cap_style: butt").
|
147
|
+
expect(text.strings.include?("fill_color: 666666")).to eq(false)
|
148
|
+
expect(text.strings.include?("fill_color: 000000")).to eq(true)
|
149
|
+
expect(text.strings.include?("cap_style: round")).to eq(false)
|
150
|
+
expect(text.strings.include?("cap_style: butt")).to eq(true)
|
154
151
|
end
|
155
|
-
|
156
152
|
end
|
157
|
-
|
158
153
|
end
|
159
|
-
|
160
154
|
end
|
data/spec/security_spec.rb
CHANGED
@@ -4,36 +4,32 @@ require "tempfile"
|
|
4
4
|
require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
|
5
5
|
|
6
6
|
describe "Document encryption" do
|
7
|
-
|
8
7
|
describe "Password padding" do
|
9
|
-
|
10
8
|
include Prawn::Document::Security
|
11
9
|
|
12
10
|
it "should truncate long passwords" do
|
13
11
|
pw = "Long long string" * 30
|
14
12
|
padded = pad_password(pw)
|
15
|
-
padded.length.
|
16
|
-
padded.
|
13
|
+
expect(padded.length).to eq(32)
|
14
|
+
expect(padded).to eq(pw[0, 32])
|
17
15
|
end
|
18
16
|
|
19
17
|
it "should pad short passwords" do
|
20
18
|
pw = "abcd"
|
21
19
|
padded = pad_password(pw)
|
22
|
-
padded.length.
|
23
|
-
padded.
|
20
|
+
expect(padded.length).to eq(32)
|
21
|
+
expect(padded).to eq(pw + Prawn::Document::Security::PasswordPadding[0, 28])
|
24
22
|
end
|
25
23
|
|
26
24
|
it "should fully pad null passwords" do
|
27
25
|
pw = ""
|
28
26
|
padded = pad_password(pw)
|
29
|
-
padded.length.
|
30
|
-
padded.
|
27
|
+
expect(padded.length).to eq(32)
|
28
|
+
expect(padded).to eq(Prawn::Document::Security::PasswordPadding)
|
31
29
|
end
|
32
|
-
|
33
30
|
end
|
34
31
|
|
35
32
|
describe "Setting permissions" do
|
36
|
-
|
37
33
|
def doc_with_permissions(permissions)
|
38
34
|
pdf = Prawn::Document.new
|
39
35
|
|
@@ -47,31 +43,30 @@ describe "Document encryption" do
|
|
47
43
|
end
|
48
44
|
|
49
45
|
it "should default to full permissions" do
|
50
|
-
doc_with_permissions({}).permissions_value.
|
51
|
-
doc_with_permissions(:print_document => true,
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
46
|
+
expect(doc_with_permissions({}).permissions_value).to eq(0xFFFFFFFF)
|
47
|
+
expect(doc_with_permissions(:print_document => true,
|
48
|
+
:modify_contents => true,
|
49
|
+
:copy_contents => true,
|
50
|
+
:modify_annotations => true).permissions_value).
|
51
|
+
to eq(0xFFFFFFFF)
|
56
52
|
end
|
57
53
|
|
58
54
|
it "should clear the appropriate bits for each permission flag" do
|
59
|
-
doc_with_permissions(:print_document => false).permissions_value.
|
60
|
-
|
61
|
-
doc_with_permissions(:modify_contents => false).permissions_value.
|
62
|
-
|
63
|
-
doc_with_permissions(:copy_contents => false).permissions_value.
|
64
|
-
|
65
|
-
doc_with_permissions(:modify_annotations => false).permissions_value.
|
66
|
-
|
55
|
+
expect(doc_with_permissions(:print_document => false).permissions_value).
|
56
|
+
to eq(0b1111_1111_1111_1111_1111_1111_1111_1011)
|
57
|
+
expect(doc_with_permissions(:modify_contents => false).permissions_value).
|
58
|
+
to eq(0b1111_1111_1111_1111_1111_1111_1111_0111)
|
59
|
+
expect(doc_with_permissions(:copy_contents => false).permissions_value).
|
60
|
+
to eq(0b1111_1111_1111_1111_1111_1111_1110_1111)
|
61
|
+
expect(doc_with_permissions(:modify_annotations => false).permissions_value).
|
62
|
+
to eq(0b1111_1111_1111_1111_1111_1111_1101_1111)
|
67
63
|
end
|
68
64
|
|
69
65
|
it "should raise_error ArgumentError if invalid option is provided" do
|
70
|
-
|
66
|
+
expect {
|
71
67
|
doc_with_permissions(:modify_document => false)
|
72
|
-
}.
|
68
|
+
}.to raise_error(ArgumentError)
|
73
69
|
end
|
74
|
-
|
75
70
|
end
|
76
71
|
|
77
72
|
describe "Encryption keys" do
|
@@ -84,65 +79,64 @@ describe "Document encryption" do
|
|
84
79
|
class << @pdf
|
85
80
|
public :owner_password_hash, :user_password_hash, :user_encryption_key
|
86
81
|
end
|
87
|
-
@pdf.encrypt_document :user_password => 'foo',
|
88
|
-
|
82
|
+
@pdf.encrypt_document :user_password => 'foo',
|
83
|
+
:owner_password => 'bar',
|
84
|
+
:permissions => { :print_document => false }
|
89
85
|
end
|
90
86
|
|
91
87
|
it "should calculate the correct owner hash" do
|
92
|
-
@pdf.owner_password_hash.unpack("H*").first.
|
88
|
+
expect(@pdf.owner_password_hash.unpack("H*").first).to match(/^61CA855012/i)
|
93
89
|
end
|
94
90
|
|
95
91
|
it "should calculate the correct user hash" do
|
96
|
-
@pdf.user_password_hash.unpack("H*").first.
|
92
|
+
expect(@pdf.user_password_hash.unpack("H*").first).to match(/^6BC8C51031/i)
|
97
93
|
end
|
98
94
|
|
99
95
|
it "should calculate the correct user_encryption_key" do
|
100
|
-
@pdf.user_encryption_key.unpack("H*").first.upcase.
|
96
|
+
expect(@pdf.user_encryption_key.unpack("H*").first.upcase).to eq("B100AB6429")
|
101
97
|
end
|
102
|
-
|
103
|
-
|
104
98
|
end
|
105
99
|
|
106
100
|
describe "EncryptedPdfObject" do
|
107
|
-
|
108
101
|
it "should delegate to PdfObject for simple types" do
|
109
|
-
PDF::Core::EncryptedPdfObject(true, nil, nil, nil).
|
110
|
-
PDF::Core::EncryptedPdfObject(42, nil, nil, nil).
|
102
|
+
expect(PDF::Core::EncryptedPdfObject(true, nil, nil, nil)).to eq("true")
|
103
|
+
expect(PDF::Core::EncryptedPdfObject(42, nil, nil, nil)).to eq("42")
|
111
104
|
end
|
112
105
|
|
113
106
|
it "should encrypt strings properly" do
|
114
|
-
PDF::Core::EncryptedPdfObject("foo", "12345", 123, 0).
|
107
|
+
expect(PDF::Core::EncryptedPdfObject("foo", "12345", 123, 0)).to eq("<4ad6e3>")
|
115
108
|
end
|
116
109
|
|
117
110
|
it "should encrypt literal strings properly" do
|
118
|
-
|
119
|
-
|
111
|
+
expect(PDF::Core::EncryptedPdfObject(PDF::Core::LiteralString.new("foo"), "12345", 123, 0)).to eq(bin_string("(J\xD6\xE3)"))
|
112
|
+
expect(PDF::Core::EncryptedPdfObject(PDF::Core::LiteralString.new("lhfbqg3do5u0satu3fjf"), nil, 123, 0)).to eq(bin_string("(\xF1\x8B\\(\b\xBB\xE18S\x130~4*#\\(%\x87\xE7\x8E\\\n)"))
|
120
113
|
end
|
121
114
|
|
122
115
|
it "should encrypt time properly" do
|
123
|
-
|
116
|
+
expect(PDF::Core::EncryptedPdfObject(Time.utc(2050, 04, 26, 10, 17, 10), "12345", 123, 0)).to eq(bin_string("(h\x83\xBE\xDC\xEC\x99\x0F\xD7\\)%\x13\xD4$\xB8\xF0\x16\xB8\x80\xC5\xE91+\xCF)"))
|
124
117
|
end
|
125
118
|
|
126
119
|
it "should properly handle compound types" do
|
127
|
-
PDF::Core::EncryptedPdfObject({:Bar => "foo"}, "12345", 123, 0).
|
120
|
+
expect(PDF::Core::EncryptedPdfObject({ :Bar => "foo" }, "12345", 123, 0)).to eq(
|
128
121
|
"<< /Bar <4ad6e3>\n>>"
|
129
|
-
|
122
|
+
)
|
123
|
+
expect(PDF::Core::EncryptedPdfObject(["foo", "bar"], "12345", 123, 0)).to eq(
|
130
124
|
"[<4ad6e3> <4ed8fe>]"
|
125
|
+
)
|
131
126
|
end
|
132
|
-
|
133
127
|
end
|
134
128
|
|
135
129
|
describe "Reference#encrypted_object" do
|
136
130
|
it "should encrypt references properly" do
|
137
|
-
ref = PDF::Core::Reference(1,["foo"])
|
138
|
-
ref.encrypted_object(nil).
|
131
|
+
ref = PDF::Core::Reference(1, ["foo"])
|
132
|
+
expect(ref.encrypted_object(nil)).to eq("1 0 obj\n[<4fca3f>]\nendobj\n")
|
139
133
|
end
|
140
134
|
|
141
135
|
it "should encrypt references with streams properly" do
|
142
136
|
ref = PDF::Core::Reference(1, {})
|
143
137
|
ref << 'foo'
|
144
138
|
result = bin_string("1 0 obj\n<< /Length 3\n>>\nstream\nO\xCA?\nendstream\nendobj\n")
|
145
|
-
ref.encrypted_object(nil).
|
139
|
+
expect(ref.encrypted_object(nil)).to eq(result)
|
146
140
|
end
|
147
141
|
end
|
148
142
|
|
@@ -151,8 +145,7 @@ describe "Document encryption" do
|
|
151
145
|
stream = PDF::Core::Stream.new
|
152
146
|
stream << "foo"
|
153
147
|
result = bin_string("stream\nO\xCA?\nendstream\n")
|
154
|
-
stream.encrypted_object(nil, 1, 0).
|
148
|
+
expect(stream.encrypted_object(nil, 1, 0)).to eq(result)
|
155
149
|
end
|
156
150
|
end
|
157
|
-
|
158
151
|
end
|