pdf-wrapper 0.0.1 → 0.0.2

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.
@@ -0,0 +1 @@
1
+ メインページ
Binary file
@@ -0,0 +1,451 @@
1
+ # -* coding: UTF-8 -*-
2
+
3
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../lib')
4
+
5
+ require 'pdf/wrapper'
6
+ require 'tempfile'
7
+ require 'rubygems'
8
+ require 'pdf/reader'
9
+
10
+ # make some private methods of PDF::Wrapper public for testing
11
+ class PDF::Wrapper
12
+ public :build_pango_layout
13
+ public :load_librsvg
14
+ public :load_libpixbuf
15
+ public :load_libpango
16
+ public :load_libpoppler
17
+ public :default_text_options
18
+ public :detect_image_type
19
+ public :validate_color
20
+ end
21
+
22
+ # a helper class for couting the number of pages in a PDF
23
+ class PageReceiver
24
+ attr_accessor :page_count
25
+
26
+ def initialize
27
+ @page_count = 0
28
+ end
29
+
30
+ # Called when page parsing ends
31
+ def end_page
32
+ @page_count += 1
33
+ end
34
+ end
35
+
36
+ class PageTextReceiver
37
+ attr_accessor :content
38
+
39
+ def initialize
40
+ @content = []
41
+ end
42
+
43
+ # Called when page parsing starts
44
+ def begin_page(arg = nil)
45
+ @content << ""
46
+ end
47
+
48
+ def show_text(string, *params)
49
+ @content.last << string.strip
50
+ end
51
+
52
+ # there's a few text callbacks, so make sure we process them all
53
+ alias :super_show_text :show_text
54
+ alias :move_to_next_line_and_show_text :show_text
55
+ alias :set_spacing_next_line_show_text :show_text
56
+
57
+ def show_text_with_positioning(*params)
58
+ params = params.first
59
+ params.each { |str| show_text(str) if str.kind_of?(String) }
60
+ end
61
+
62
+ end
63
+
64
+ context "The PDF::Wrapper class" do
65
+
66
+ setup do
67
+ #@file = File.new(File.dirname(__FILE__) + "/data/cairo-basic.pdf")
68
+ @shortstr = "Chunky Bacon"
69
+ @medstr = "This is a medium length string\nthat is also multi line. one two three four."
70
+ end
71
+
72
+ specify "should load external libs correctly" do
73
+ pdf = PDF::Wrapper.new
74
+
75
+ # lib gdkpixbuf
76
+ ::Object.const_defined?(:Gdk).should eql(false)
77
+ pdf.load_libpixbuf
78
+ ::Object.const_defined?(:Gdk).should eql(true)
79
+ ::Gdk.const_defined?(:Pixbuf).should eql(true)
80
+
81
+ # pango
82
+ ::Object.const_defined?(:Pango).should eql(false)
83
+ pdf.load_libpango
84
+ ::Object.const_defined?(:Pango).should eql(true)
85
+
86
+ # libpoppler
87
+ ::Object.const_defined?(:Poppler).should eql(false)
88
+ pdf.load_libpoppler
89
+ ::Object.const_defined?(:Poppler).should eql(true)
90
+
91
+ # librsvg
92
+ ::Object.const_defined?(:RSVG).should eql(false)
93
+ pdf.load_librsvg
94
+ ::Object.const_defined?(:RSVG).should eql(true)
95
+
96
+ end
97
+
98
+ specify "should initilize with the correct default paper size and orientation" do
99
+ pdf = PDF::Wrapper.new
100
+ pdf.page_width.should eql(PDF::Wrapper::PAGE_SIZES[:A4].first)
101
+ pdf.page_height.should eql(PDF::Wrapper::PAGE_SIZES[:A4].last)
102
+ end
103
+
104
+ specify "should initilize with the correct custom paper size" do
105
+ pdf = PDF::Wrapper.new(:paper => :A0)
106
+ pdf.page_width.should eql(PDF::Wrapper::PAGE_SIZES[:A0].first)
107
+ pdf.page_height.should eql(PDF::Wrapper::PAGE_SIZES[:A0].last)
108
+ end
109
+
110
+ specify "should initilize with the correct custom orientation" do
111
+ pdf = PDF::Wrapper.new(:paper => :A4, :orientation => :landscape)
112
+ pdf.page_width.should eql(PDF::Wrapper::PAGE_SIZES[:A4].last)
113
+ pdf.page_height.should eql(PDF::Wrapper::PAGE_SIZES[:A4].first)
114
+ end
115
+
116
+ specify "should raise an exception if an invalid orientation is requested" do
117
+ lambda {pdf = PDF::Wrapper.new(:paper => :A4, :orientation => :fake)}.should raise_error(ArgumentError)
118
+ end
119
+
120
+ specify "should store sensible default text options" do
121
+ pdf = PDF::Wrapper.new
122
+ pdf.default_text_options.should be_a_kind_of(Hash)
123
+ end
124
+
125
+ specify "should initilize with the correct default margins (5% of the page)" do
126
+ pdf = PDF::Wrapper.new
127
+ pdf.margin_left.should eql((PDF::Wrapper::PAGE_SIZES[:A4].first * 0.05).ceil)
128
+ pdf.margin_right.should eql((PDF::Wrapper::PAGE_SIZES[:A4].first * 0.05).ceil)
129
+ pdf.margin_top.should eql((PDF::Wrapper::PAGE_SIZES[:A4].last * 0.05).ceil)
130
+ pdf.margin_bottom.should eql((PDF::Wrapper::PAGE_SIZES[:A4].last * 0.05).ceil)
131
+ end
132
+
133
+ specify "should initilize with the correct default text and colour settings" do
134
+ pdf = PDF::Wrapper.new
135
+ pdf.instance_variable_get("@default_color").should eql([0.0,0.0,0.0,1.0])
136
+ pdf.instance_variable_get("@default_font").should eql("Sans Serif")
137
+ pdf.instance_variable_get("@default_font_size").should eql(16)
138
+ end
139
+
140
+ specify "should initialize with the cursor at the top left of the body of the page" do
141
+ pdf = PDF::Wrapper.new
142
+ x,y = pdf.current_point
143
+ x.to_i.should eql(pdf.margin_left)
144
+ y.to_i.should eql(pdf.margin_top)
145
+ end
146
+
147
+ specify "should calculate the absolute coordinates for the margins correctly" do
148
+ pdf = PDF::Wrapper.new
149
+ pdf.absolute_left_margin.should eql(pdf.margin_left)
150
+ pdf.absolute_right_margin.should eql(pdf.page_width - pdf.margin_right)
151
+ pdf.absolute_top_margin.should eql(pdf.margin_top)
152
+ pdf.absolute_bottom_margin.should eql(pdf.page_height - pdf.margin_bottom)
153
+ end
154
+
155
+ specify "should calculate various useful page coordinates correctly" do
156
+ pdf = PDF::Wrapper.new
157
+ pdf.absolute_x_middle.should eql(PDF::Wrapper::PAGE_SIZES[:A4].first / 2)
158
+ pdf.absolute_y_middle.should eql(PDF::Wrapper::PAGE_SIZES[:A4].last / 2)
159
+ pdf.body_width.should eql(pdf.page_width - pdf.margin_left - pdf.margin_right)
160
+ pdf.body_height.should eql(pdf.page_height - pdf.margin_top - pdf.margin_bottom)
161
+ pdf.margin_x_middle.should eql(pdf.margin_left + (pdf.body_width/ 2))
162
+ pdf.margin_y_middle.should eql(pdf.margin_top + (pdf.body_height/ 2))
163
+ pdf.points_to_bottom_margin(300).should eql(pdf.absolute_bottom_margin - 300)
164
+ pdf.points_to_right_margin(300).should eql(pdf.absolute_right_margin - 300)
165
+ end
166
+
167
+ specify "should be able to move the cursor to any arbitary point on the canvas" do
168
+ pdf = PDF::Wrapper.new
169
+ pdf.move_to(100,100)
170
+ x,y = pdf.current_point
171
+ x.to_i.should eql(100)
172
+ y.to_i.should eql(100)
173
+ end
174
+
175
+ specify "should raise an exception if the user tries to move the cursor off the canvas" do
176
+ pdf = PDF::Wrapper.new
177
+ lambda {pdf.move_to(PDF::Wrapper::PAGE_SIZES[:A4].first + 10,100)}.should raise_error(ArgumentError)
178
+ lambda {pdf.move_to(100, PDF::Wrapper::PAGE_SIZES[:A4].last + 10)}.should raise_error(ArgumentError)
179
+ end
180
+
181
+ specify "should add additional pages at the users request" do
182
+ pdf = PDF::Wrapper.new
183
+ pdf.move_to(100,100)
184
+ pdf.start_new_page
185
+ x,y = pdf.current_point
186
+ x.to_i.should eql(pdf.margin_left)
187
+ y.to_i.should eql(pdf.margin_top)
188
+
189
+ # verify the output
190
+ receiver = PageReceiver.new
191
+ reader = PDF::Reader.string(pdf.render, receiver)
192
+ receiver.page_count.should eql(2)
193
+ end
194
+
195
+ specify "should be able to draw a single line onto the canvas" do
196
+ x0 = y0 = 100
197
+ x1 = y1 = 200
198
+ pdf = PDF::Wrapper.new
199
+ pdf.line(x0,y0,x1,y1)
200
+
201
+ receiver = PDF::Reader::RegisterReceiver.new
202
+ reader = PDF::Reader.string(pdf.render, receiver)
203
+
204
+ # the begin_new_subpath command specifies the start of the line, append line specifies the end
205
+ receiver.count(:begin_new_subpath).should eql(1)
206
+ receiver.count(:append_line).should eql(1)
207
+ receiver.first_occurance_of(:begin_new_subpath)[:args].should eql([x0.to_f, y0.to_f])
208
+ receiver.first_occurance_of(:append_line)[:args].should eql([x1.to_f, y1.to_f])
209
+ end
210
+
211
+ specify "should be able to draw an empty rectangle onto the canvas" do
212
+ x = y = 100
213
+ w = h = 200
214
+ pdf = PDF::Wrapper.new
215
+ pdf.rectangle(x,y,w,h)
216
+
217
+ receiver = PDF::Reader::RegisterReceiver.new
218
+ reader = PDF::Reader.string(pdf.render, receiver)
219
+
220
+ # the begin_new_subpath command specifies the start of the line, append line specifies the end
221
+ callbacks = receiver.series(:begin_new_subpath, :append_line,:append_line,:append_line, :close_subpath)
222
+ callbacks.shift[:args].should eql([x.to_f, y.to_f])
223
+ callbacks.shift[:args].should eql([(x+w).to_f, y.to_f])
224
+ callbacks.shift[:args].should eql([(x+w).to_f, (y+h).to_f])
225
+ callbacks.shift[:args].should eql([x.to_f, (y+h).to_f])
226
+ end
227
+
228
+ specify "should leave the cursor in the bottom left of a layout when new text is added" do
229
+ pdf = PDF::Wrapper.new
230
+ x, y = pdf.current_point
231
+ str = "Chunky Bacon!!"
232
+ opts = {:font_size => 16, :font => "Sans Serif", :alignment => :left, :justify => false }
233
+ height = pdf.text_height(str, pdf.page_width, opts)
234
+ pdf.text(str,opts)
235
+ newx, newy = pdf.current_point
236
+
237
+ newx.should eql(x)
238
+ # the top of our text box, plus its height
239
+ newy.should eql(y + height)
240
+ end
241
+
242
+ specify "should be able to draw a filled rectangle onto the canvas"
243
+ =begin
244
+ do
245
+ x = y = 100
246
+ w = h = 200
247
+ pdf = PDF::Wrapper.new
248
+ pdf.rectangle(x,y,w,h, :fill_color => :red)
249
+
250
+ receiver = PDF::Reader::RegisterReceiver.new
251
+ reader = PDF::Reader.string(pdf.render, receiver)
252
+
253
+ # TODO: test for the appropriate pattern of callbacks
254
+ end
255
+ =end
256
+
257
+ specify "should be able to draw an empty rounded rectangle onto the canvas"
258
+ =begin
259
+ do
260
+ x = y = 100
261
+ w = h = 200
262
+ r = 5
263
+ pdf = PDF::Wrapper.new
264
+ pdf.rounded_rectangle(x,y,w,h,r)
265
+
266
+ receiver = PDF::Reader::RegisterReceiver.new
267
+ reader = PDF::Reader.string(pdf.render, receiver)
268
+
269
+ # TODO: test for the appropriate pattern of callbacks
270
+ end
271
+ =end
272
+
273
+ specify "should be able to draw a filled rounded rectangle onto the canvas"
274
+ =begin
275
+ do
276
+ x = y = 100
277
+ w = h = 200
278
+ r = 5
279
+ pdf = PDF::Wrapper.new
280
+ pdf.rounded_rectangle(x,y,w,h,r, :fill_color => :red)
281
+
282
+ receiver = PDF::Reader::RegisterReceiver.new
283
+ reader = PDF::Reader.string(pdf.render, receiver)
284
+
285
+ # TODO: test for the appropriate pattern of callbacks
286
+ end
287
+ =end
288
+
289
+ specify "should be able to draw an empty circle onto the canvas"
290
+ =begin
291
+ do
292
+ x = 100
293
+ y = 200
294
+ r = 5
295
+ pdf = PDF::Wrapper.new
296
+ pdf.circle(x,y,r)
297
+
298
+ receiver = PDF::Reader::RegisterReceiver.new
299
+ reader = PDF::Reader.string(pdf.render, receiver)
300
+
301
+ # TODO: test for the appropriate pattern of callbacks
302
+ end
303
+ =end
304
+
305
+ specify "should be able to draw a filled circle onto the canvas"
306
+ =begin
307
+ do
308
+ x = 100
309
+ y = 200
310
+ r = 5
311
+ pdf = PDF::Wrapper.new
312
+ pdf.circle(x,y,r, :fill_color => :red)
313
+
314
+ receiver = PDF::Reader::RegisterReceiver.new
315
+ reader = PDF::Reader.string(pdf.render, receiver)
316
+
317
+ # TODO: test for the appropriate pattern of callbacks
318
+ end
319
+ =end
320
+
321
+ specify "should be able to add ascii text to the canvas"
322
+ =begin
323
+ do
324
+ msg = "Chunky Bacon"
325
+ pdf = PDF::Wrapper.new
326
+ pdf.text msg
327
+
328
+ receiver = PageTextReceiver.new
329
+ reader = PDF::Reader.string(pdf.render, receiver)
330
+
331
+ # TODO: test for the appropriate text on the page. Need to fix unicode spport in pdf-reader first
332
+ #puts receiver.content.inspect
333
+ end
334
+ =end
335
+
336
+ specify "should be able to add unicode text to the canvas"
337
+ =begin
338
+ do
339
+ msg = "メインページ"
340
+ pdf = PDF::Wrapper.new
341
+ pdf.text msg
342
+
343
+ receiver = PageTextReceiver.new
344
+ reader = PDF::Reader.string(pdf.render, receiver)
345
+
346
+ # TODO: test for the appropriate text on the page. Need to fix unicode spport in pdf-reader first
347
+ #puts receiver.content.inspect
348
+ end
349
+ =end
350
+
351
+ specify "should be able to add text to the canvas in a bounding box using the cell method"
352
+ =begin
353
+ do
354
+ msg = "メインページ"
355
+ pdf = PDF::Wrapper.new
356
+ pdf.text msg
357
+
358
+ receiver = PageTextReceiver.new
359
+ reader = PDF::Reader.string(pdf.render, receiver)
360
+
361
+ # TODO: test for the appropriate text on the page. Need to fix unicode spport in pdf-reader first
362
+ #puts receiver.content.inspect
363
+ end
364
+ =end
365
+
366
+ specify "should be able to render to a file" do
367
+ # generate a PDF
368
+ msg = "Chunky Bacon"
369
+ pdf = PDF::Wrapper.new
370
+ pdf.text msg
371
+
372
+ # write the PDF to a temp file
373
+ tmp = Tempfile.open("siftr")
374
+ tmp.close
375
+ pdf.render_to_file(tmp.path)
376
+
377
+ # ensure an actual PDF was written out
378
+ File.open(tmp.path, "r") do |f|
379
+ f.read(4).should eql("%PDF")
380
+ end
381
+
382
+ # remove our temp file
383
+ tmp.unlink
384
+ end
385
+
386
+ specify "should be able to detect the filetype of an image" do
387
+ pdf = PDF::Wrapper.new
388
+ pdf.detect_image_type(File.dirname(__FILE__) + "/data/google.png").should eql(:png)
389
+ pdf.detect_image_type(File.dirname(__FILE__) + "/data/graph.svg").should eql(:svg)
390
+ pdf.detect_image_type(File.dirname(__FILE__) + "/data/shipsail.jpg").should eql(nil)
391
+ end
392
+
393
+ specify "should be able to calculate the height of a string of text" do
394
+ pdf = PDF::Wrapper.new
395
+ opts = {:font_size => 16, :font => "Sans Serif", :alignment => :left, :justify => false }
396
+ pdf.text_height(@medstr, pdf.body_width, opts).should eql(49)
397
+ end
398
+
399
+ specify "should be able to draw a table on the canvas"
400
+
401
+ specify "should leave the cursor in the bottom left when adding a table" do
402
+ pdf = PDF::Wrapper.new
403
+ data = [%w{head1 head2},%w{data1 data2}]
404
+ pdf.table(data, :left => pdf.margin_left)
405
+ x,y = pdf.current_point
406
+ x.to_i.should eql(pdf.margin_left)
407
+ end
408
+
409
+ specify "should default to using as much available space when adding a table that isn't left aligned with the left margin" do
410
+ pdf = PDF::Wrapper.new
411
+ data = [%w{head1 head2},%w{data1 data2}]
412
+ pdf.table(data, :left => 100)
413
+ x,y = pdf.current_point
414
+ x.to_i.should eql(100)
415
+ end
416
+
417
+ specify "should raise an exception if build_pango_layout is passed anything other than a string" do
418
+ pdf = PDF::Wrapper.new
419
+ lambda { pdf.build_pango_layout(10) }.should raise_error(ArgumentError)
420
+
421
+ end
422
+
423
+ if RUBY_VERSION >= "1.9"
424
+ specify "should accept non UTF-8 strings to build_pango_layout and convert them on the fly" do
425
+ pdf = PDF::Wrapper.new
426
+
427
+ # all three of these files have the same content, but in different encodings
428
+ iso2022_str = File.open(File.dirname(__FILE__) + "/data/shift_jis.txt", "r:ISO-2022-JP") { |f| f.read }.strip!
429
+ shiftjis_str = File.open(File.dirname(__FILE__) + "/data/iso-2022-jp.txt", "r:Shift_JIS") { |f| f.read }.strip!
430
+ utf8_str = File.open(File.dirname(__FILE__) + "/data/utf8.txt", "r:UTF-8") { |f| f.read }.strip!
431
+
432
+ pdf.build_pango_layout(shiftjis_str)
433
+ pdf.build_pango_layout(iso2022_str)
434
+
435
+ # TODO: improve this spec using mocks. Atm, I'm assume that if build_pango_layout didn't raise an exception when
436
+ # passed in the non UTF-8 strings, then all worked fine. yuck.
437
+ end
438
+
439
+ specify "should raise an error when a string that isn't convertable to UTF-8 is passed into build_pango_layout()"
440
+ end
441
+
442
+ specify "should be able to determine if a requested colour is valid or not" do
443
+ pdf = PDF::Wrapper.new
444
+ pdf.validate_color(:black).should be_true
445
+ pdf.validate_color([1,0,0]).should be_true
446
+ pdf.validate_color([1,0,0,0.5]).should be_true
447
+ lambda { pdf.validate_color(:ponies)}.should raise_error(ArgumentError)
448
+ lambda { pdf.validate_color([1])}.should raise_error(ArgumentError)
449
+ lambda { pdf.validate_color([1000, 255, 0])}.should raise_error(ArgumentError)
450
+ end
451
+ end