pdf-wrapper 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +9 -0
- data/Rakefile +3 -2
- data/TODO +1 -0
- data/examples/utf8.rb +1 -1
- data/lib/pdf/wrapper.rb +107 -27
- data/specs/image_spec.rb +22 -0
- data/specs/load_spec.rb +31 -0
- data/specs/shapes_spec.rb +194 -0
- data/specs/spec_helper.rb +70 -0
- data/specs/text_spec.rb +153 -0
- data/specs/wrapper_spec.rb +12 -397
- metadata +16 -11
data/CHANGELOG
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
v0.0.5 (27th April 2008)
|
2
|
+
- Fix crash when inserting multiple images
|
3
|
+
- added PDF::Wrapper#pad
|
4
|
+
- added PDF::Wrapper#text_width
|
5
|
+
- added support for customisable page margins (thanks to Paweł Kondzior)
|
6
|
+
- added support for cubic Bezier spline paths (thanks to Paweł Kondzior)
|
7
|
+
- added support for specifying the width of a cell border (thanks to Paweł Kondzior)
|
8
|
+
- fixed alignment of text (thanks to Paweł Kondzior)
|
9
|
+
|
1
10
|
v0.0.4 (12th March 2008)
|
2
11
|
- added support for custom line widths on primitive drawing shapes (circles,
|
3
12
|
lines, etc). Thanks Paweł Kondzior
|
data/Rakefile
CHANGED
@@ -6,7 +6,7 @@ require 'rake/testtask'
|
|
6
6
|
require "rake/gempackagetask"
|
7
7
|
require 'spec/rake/spectask'
|
8
8
|
|
9
|
-
PKG_VERSION = "0.0.
|
9
|
+
PKG_VERSION = "0.0.5"
|
10
10
|
PKG_NAME = "pdf-wrapper"
|
11
11
|
PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
|
12
12
|
|
@@ -16,7 +16,8 @@ task :default => [ :spec ]
|
|
16
16
|
# run all rspecs
|
17
17
|
desc "Run all rspec files"
|
18
18
|
Spec::Rake::SpecTask.new("spec") do |t|
|
19
|
-
t.spec_files = FileList['specs
|
19
|
+
#t.spec_files = FileList['specs/**/*_spec.rb']
|
20
|
+
t.spec_files = ['specs/load_spec.rb','specs/image_spec.rb','specs/shapes_spec.rb','specs/text_spec.rb','specs/wrapper_spec.rb']
|
20
21
|
t.rcov = true
|
21
22
|
t.rcov_dir = (ENV['CC_BUILD_ARTIFACTS'] || 'doc') + "/rcov"
|
22
23
|
t.rcov_opts = ["--exclude","spec.*\.rb","--exclude",".*cairo.*","--exclude",".*rcov.*","--exclude",".*rspec.*","--exclude",".*pdf-reader.*"]
|
data/examples/utf8.rb
CHANGED
@@ -8,5 +8,5 @@ require 'pdf/wrapper'
|
|
8
8
|
pdf = PDF::Wrapper.new(:paper => :A4)
|
9
9
|
pdf.default_font("Sans Serif")
|
10
10
|
pdf.default_color(:black)
|
11
|
-
pdf.text File.read(File.dirname(__FILE__) + "/../specs/data/utf8.txt"), :font => "Monospace", :font_size => 8
|
11
|
+
pdf.text File.read(File.dirname(__FILE__) + "/../specs/data/utf8.txt"), :font => "Monospace", :font_size => 8, :alignment => :center
|
12
12
|
pdf.render_to_file("wrapper.pdf")
|
data/lib/pdf/wrapper.rb
CHANGED
@@ -83,7 +83,15 @@ module PDF
|
|
83
83
|
# <tt>:paper</tt>:: The paper size to use (default :A4)
|
84
84
|
# <tt>:orientation</tt>:: :portrait (default) or :landscape
|
85
85
|
# <tt>:background_color</tt>:: The background colour to use (default :white)
|
86
|
+
# <tt>:margin_top</tt>:: The size of the default top margin (default 5% of page)
|
87
|
+
# <tt>:margin_bottom</tt>:: The size of the default bottom margin (default 5% of page)
|
88
|
+
# <tt>:margin_left</tt>:: The size of the default left margin (default 5% of page)
|
89
|
+
# <tt>:margin_right</tt>:: The size of the default right margin (default 5% of page)
|
86
90
|
def initialize(opts={})
|
91
|
+
|
92
|
+
# ensure we have recentish cairo bindings
|
93
|
+
raise "Ruby Cairo bindings version #{Cairo::BINDINGS_VERSION.join(".")} is too low. At least 1.5 is required" if Cairo::BINDINGS_VERSION.to_s < "150"
|
94
|
+
|
87
95
|
options = {:paper => :A4,
|
88
96
|
:orientation => :portrait,
|
89
97
|
:background_color => :white
|
@@ -91,7 +99,8 @@ module PDF
|
|
91
99
|
options.merge!(opts)
|
92
100
|
|
93
101
|
# test for invalid options
|
94
|
-
options.assert_valid_keys(:paper, :orientation, :background_color)
|
102
|
+
options.assert_valid_keys(:paper, :orientation, :background_color, :margin_left, :margin_right, :margin_top, :margin_bottom)
|
103
|
+
options[:paper] = options[:paper].to_sym
|
95
104
|
raise ArgumentError, "Invalid paper option" unless PAGE_SIZES.include?(options[:paper])
|
96
105
|
|
97
106
|
# set page dimensions
|
@@ -106,11 +115,10 @@ module PDF
|
|
106
115
|
end
|
107
116
|
|
108
117
|
# set page margins and dimensions of usable canvas
|
109
|
-
|
110
|
-
@
|
111
|
-
@
|
112
|
-
@
|
113
|
-
@margin_bottom = (@page_height * 0.05).ceil
|
118
|
+
@margin_left = options[:margin_left] || (@page_width * 0.05).ceil
|
119
|
+
@margin_right = options[:margin_right] || (@page_width * 0.05).ceil
|
120
|
+
@margin_top = options[:margin_top] || (@page_height * 0.05).ceil
|
121
|
+
@margin_bottom = options[:margin_bottom] || (@page_height * 0.05).ceil
|
114
122
|
|
115
123
|
# initialize some cairo objects to draw on
|
116
124
|
@output = StringIO.new
|
@@ -265,7 +273,7 @@ module PDF
|
|
265
273
|
# <tt>:border</tt>:: Which sides of the cell should have a border? A string with any combination the letters tblr (top, bottom, left, right). Nil for no border, defaults to all sides.
|
266
274
|
# <tt>:border_width</tt>:: How wide should the border be?
|
267
275
|
# <tt>:border_color</tt>:: What color should the border be?
|
268
|
-
# <tt>:
|
276
|
+
# <tt>:fill_color</tt>:: A background color for the cell. Defaults to none.
|
269
277
|
# <tt>:padding</tt>:: The number of points to leave between the inside of the border and text. Defaults to 3.
|
270
278
|
def cell(str, x, y, w, h, opts={})
|
271
279
|
# TODO: add support for pango markup (see http://ruby-gnome2.sourceforge.jp/hiki.cgi?pango-markup)
|
@@ -274,12 +282,12 @@ module PDF
|
|
274
282
|
# TODO: add an option to draw a border with rounded corners
|
275
283
|
|
276
284
|
options = default_text_options
|
277
|
-
options.merge!({:border => "tblr", :border_width =>
|
285
|
+
options.merge!({:border => "tblr", :border_width => @default_line_width, :border_color => :black, :fill_color => nil, :padding => 3})
|
278
286
|
options.merge!(opts)
|
279
|
-
options.assert_valid_keys(default_text_options.keys + [:width, :border, :border_width, :border_color, :
|
287
|
+
options.assert_valid_keys(default_text_options.keys + [:width, :border, :border_width, :border_color, :fill_color, :padding])
|
280
288
|
|
281
289
|
# apply padding
|
282
|
-
textw =
|
290
|
+
textw = w - (options[:padding] * 2)
|
283
291
|
texth = h - (options[:padding] * 2)
|
284
292
|
textx = x + options[:padding]
|
285
293
|
texty = y + options[:padding]
|
@@ -291,7 +299,7 @@ module PDF
|
|
291
299
|
origx, origy = current_point
|
292
300
|
|
293
301
|
# TODO: raise an exception if the box coords or dimensions will place it off the canvas
|
294
|
-
rectangle(x,y,w,h, :color => options[:
|
302
|
+
rectangle(x,y,w,h, :color => options[:fill_color], :fill_color => options[:fill_color]) if options[:fill_color]
|
295
303
|
|
296
304
|
layout = build_pango_layout(str.to_s, textw, options)
|
297
305
|
|
@@ -301,11 +309,10 @@ module PDF
|
|
301
309
|
render_layout(layout, textx, texty, texth, :auto_new_page => false)
|
302
310
|
|
303
311
|
# draw a border around the cell
|
304
|
-
|
305
|
-
line(x,y,x+w,y, :color => options[:border_color])
|
306
|
-
line(x,y
|
307
|
-
line(x,y,x,y+h, :color => options[:border_color])
|
308
|
-
line(x+w,y,x+w,y+h, :color => options[:border_color]) if options[:border].include?("r")
|
312
|
+
line(x,y,x+w,y, :color => options[:border_color], :line_width => options[:border_width]) if options[:border].include?("t")
|
313
|
+
line(x,y+h,x+w,y+h, :color => options[:border_color], :line_width => options[:border_width]) if options[:border].include?("b")
|
314
|
+
line(x,y,x,y+h, :color => options[:border_color], :line_width => options[:border_width]) if options[:border].include?("l")
|
315
|
+
line(x+w,y,x+w,y+h, :color => options[:border_color], :line_width => options[:border_width]) if options[:border].include?("r")
|
309
316
|
|
310
317
|
# restore the cursor position
|
311
318
|
move_to(origx, origy)
|
@@ -421,6 +428,19 @@ module PDF
|
|
421
428
|
return height / Pango::SCALE
|
422
429
|
end
|
423
430
|
|
431
|
+
# Returns the amount of horizontal space needed to display the supplied text with the requested options
|
432
|
+
# opts is an options hash that specifies various attributes of the text. See the text function for more information.
|
433
|
+
# The text is assumed to not wrap.
|
434
|
+
def text_width(str, opts = {})
|
435
|
+
options = default_text_options.merge!(opts)
|
436
|
+
options.assert_valid_keys(default_text_options.keys)
|
437
|
+
|
438
|
+
layout = build_pango_layout(str.to_s, -1, options)
|
439
|
+
width, height = layout.size
|
440
|
+
|
441
|
+
return width / Pango::SCALE
|
442
|
+
end
|
443
|
+
|
424
444
|
#####################################################
|
425
445
|
# Functions relating to working with graphics
|
426
446
|
#####################################################
|
@@ -484,6 +504,27 @@ module PDF
|
|
484
504
|
move_to(origx, origy)
|
485
505
|
end
|
486
506
|
|
507
|
+
# Adds a cubic Bezier spline to the path from the (x0, y0) to position (x3, y3)
|
508
|
+
# in user-space coordinates, using (x1, y1) and (x2, y2) as the control points.
|
509
|
+
# Options:
|
510
|
+
# <tt>:color</tt>:: The colour of the line
|
511
|
+
# <tt>:line_width</tt>:: The width of line. Defaults to 2.0
|
512
|
+
def curve(x0, y0, x1, y1, x2, y2, x3, y3, opts = {})
|
513
|
+
options = {:color => @default_color, :line_width => @default_line_width }
|
514
|
+
options.merge!(opts)
|
515
|
+
options.assert_valid_keys(:color, :line_width)
|
516
|
+
origx, origy = current_point
|
517
|
+
|
518
|
+
set_color(options[:color])
|
519
|
+
@context.set_line_width(options[:line_width])
|
520
|
+
move_to(x0,y0)
|
521
|
+
@context.curve_to(x1, y1, x2, y2, x3, y3).stroke
|
522
|
+
|
523
|
+
# restore the cursor position
|
524
|
+
move_to(origx, origy)
|
525
|
+
end
|
526
|
+
|
527
|
+
|
487
528
|
# draw a rectangle starting at x,y with w,h dimensions.
|
488
529
|
# Parameters:
|
489
530
|
# <tt>:x</tt>:: The x co-ordinate of the top left of the rectangle.
|
@@ -630,6 +671,12 @@ module PDF
|
|
630
671
|
# Misc Functions
|
631
672
|
#####################################################
|
632
673
|
|
674
|
+
def pad(n)
|
675
|
+
x, y = current_point
|
676
|
+
move_to(x, y + n)
|
677
|
+
y + n
|
678
|
+
end
|
679
|
+
|
633
680
|
# move the cursor to an arbitary position on the current page
|
634
681
|
def move_to(x,y)
|
635
682
|
raise ArgumentError, 'x cannot be larger than the width of the page' if x > page_width
|
@@ -715,7 +762,11 @@ module PDF
|
|
715
762
|
# create a new Pango layout that our text will be added to
|
716
763
|
layout = @context.create_pango_layout
|
717
764
|
layout.text = str.to_s
|
718
|
-
|
765
|
+
if w == -1
|
766
|
+
layout.width = -1
|
767
|
+
else
|
768
|
+
layout.width = w * Pango::SCALE
|
769
|
+
end
|
719
770
|
layout.spacing = options[:spacing] * Pango::SCALE
|
720
771
|
|
721
772
|
# set the alignment of the text in the layout
|
@@ -830,7 +881,7 @@ module PDF
|
|
830
881
|
@context.scale(width / w, height / h)
|
831
882
|
@context.render_poppler_page(page)
|
832
883
|
end
|
833
|
-
move_to(x, y + height)
|
884
|
+
move_to(opts[:left] || x, (opts[:top] || y) + height)
|
834
885
|
end
|
835
886
|
|
836
887
|
def draw_pixbuf(filename, opts = {})
|
@@ -845,7 +896,7 @@ module PDF
|
|
845
896
|
@context.set_source_pixbuf(pixbuf, 0, 0)
|
846
897
|
@context.paint
|
847
898
|
end
|
848
|
-
move_to(x, y + height)
|
899
|
+
move_to(opts[:left] || x, (opts[:top] || y) + height)
|
849
900
|
end
|
850
901
|
|
851
902
|
def draw_png(filename, opts = {})
|
@@ -859,7 +910,7 @@ module PDF
|
|
859
910
|
@context.set_source(img_surface, 0, 0)
|
860
911
|
@context.paint
|
861
912
|
end
|
862
|
-
move_to(x, y + height)
|
913
|
+
move_to(opts[:left] || x, (opts[:top] || y) + height)
|
863
914
|
end
|
864
915
|
|
865
916
|
def draw_svg(filename, opts = {})
|
@@ -874,7 +925,7 @@ module PDF
|
|
874
925
|
@context.render_rsvg_handle(handle)
|
875
926
|
#@context.paint
|
876
927
|
end
|
877
|
-
move_to(x, y + height)
|
928
|
+
move_to(opts[:left] || x, (opts[:top] || y) + height)
|
878
929
|
end
|
879
930
|
|
880
931
|
# adds a single table row to the canvas. Top left of the row will be at the current x,y
|
@@ -990,11 +1041,35 @@ module PDF
|
|
990
1041
|
# adding text at the same co-ords
|
991
1042
|
orig_x = x
|
992
1043
|
orig_y = y
|
993
|
-
|
994
1044
|
# for each line in the layout
|
995
|
-
layout.
|
996
|
-
|
997
|
-
|
1045
|
+
# layout.alignment = Pango::Layout::ALIGN_RIGHT
|
1046
|
+
# layout.lines.each do |line|
|
1047
|
+
# #calculate where the next line starts
|
1048
|
+
# ink_rect, logical_rect = line.extents
|
1049
|
+
# y = y + (logical_rect.height / Pango::SCALE * (3.0/4.0)) + 1
|
1050
|
+
# if y >= (orig_y + h)
|
1051
|
+
# # our text is using the maximum amount of vertical space we want it to
|
1052
|
+
# if options[:auto_new_page]
|
1053
|
+
# # create a new page and we can continue adding text
|
1054
|
+
# start_new_page
|
1055
|
+
# x = orig_x
|
1056
|
+
# y = orig_y
|
1057
|
+
# else
|
1058
|
+
# # the user doesn't want us to continue on the next page, so
|
1059
|
+
# # stop adding lines to the canvas
|
1060
|
+
# break
|
1061
|
+
# end
|
1062
|
+
# end
|
1063
|
+
#
|
1064
|
+
# # move to the start of the next line
|
1065
|
+
# move_to(x, y)
|
1066
|
+
# # draw the line on the canvas
|
1067
|
+
# @context.show_pango_layout_line(line)
|
1068
|
+
# end
|
1069
|
+
iter = layout.iter
|
1070
|
+
loop do
|
1071
|
+
line = iter.line
|
1072
|
+
ink_rect, logical_rect = iter.line_extents
|
998
1073
|
y = y + (logical_rect.height / Pango::SCALE * (3.0/4.0)) + 1
|
999
1074
|
if y >= (orig_y + h)
|
1000
1075
|
# our text is using the maximum amount of vertical space we want it to
|
@@ -1011,10 +1086,15 @@ module PDF
|
|
1011
1086
|
end
|
1012
1087
|
|
1013
1088
|
# move to the start of the next line
|
1014
|
-
move_to(x, y)
|
1089
|
+
#move_to(x, y)
|
1090
|
+
baseline = iter.baseline / Pango::SCALE
|
1091
|
+
@context.move_to(x + logical_rect.x / Pango::SCALE, y + baseline)
|
1092
|
+
|
1015
1093
|
# draw the line on the canvas
|
1016
1094
|
@context.show_pango_layout_line(line)
|
1017
|
-
|
1095
|
+
|
1096
|
+
break unless iter.next_line!
|
1097
|
+
end
|
1018
1098
|
|
1019
1099
|
# return the y co-ord we finished on
|
1020
1100
|
return y
|
data/specs/image_spec.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
4
|
+
|
5
|
+
context "The PDF::Wrapper class" do
|
6
|
+
specify "should be able to detect the filetype of an image" do
|
7
|
+
pdf = PDF::Wrapper.new
|
8
|
+
pdf.detect_image_type(File.dirname(__FILE__) + "/data/google.png").should eql(:png)
|
9
|
+
pdf.detect_image_type(File.dirname(__FILE__) + "/data/zits.gif").should eql(:gif)
|
10
|
+
pdf.detect_image_type(File.dirname(__FILE__) + "/data/orc.svg").should eql(:svg)
|
11
|
+
pdf.detect_image_type(File.dirname(__FILE__) + "/data/utf8-long.pdf").should eql(:pdf)
|
12
|
+
pdf.detect_image_type(File.dirname(__FILE__) + "/data/shipsail.jpg").should eql(:jpg)
|
13
|
+
end
|
14
|
+
|
15
|
+
specify "should be able to calculate image dimensions correctly" do
|
16
|
+
pdf = PDF::Wrapper.new
|
17
|
+
pdf.calc_image_dimensions(100, 100, 200, 200).should eql([100.0,100.0])
|
18
|
+
pdf.calc_image_dimensions(nil, nil, 200, 200).should eql([200.0,200.0])
|
19
|
+
pdf.calc_image_dimensions(150, 200, 200, 200, true).should eql([150.0,150.0])
|
20
|
+
pdf.calc_image_dimensions(300, 250, 200, 200, true).should eql([250.0,250.0])
|
21
|
+
end
|
22
|
+
end
|
data/specs/load_spec.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
4
|
+
|
5
|
+
context "The PDF::Wrapper class" do
|
6
|
+
specify "should load external libs correctly" do
|
7
|
+
pdf = PDF::Wrapper.new
|
8
|
+
|
9
|
+
# lib gdkpixbuf
|
10
|
+
::Object.const_defined?(:Gdk).should eql(false)
|
11
|
+
pdf.load_libpixbuf
|
12
|
+
::Object.const_defined?(:Gdk).should eql(true)
|
13
|
+
::Gdk.const_defined?(:Pixbuf).should eql(true)
|
14
|
+
|
15
|
+
# pango
|
16
|
+
::Object.const_defined?(:Pango).should eql(false)
|
17
|
+
pdf.load_libpango
|
18
|
+
::Object.const_defined?(:Pango).should eql(true)
|
19
|
+
|
20
|
+
# libpoppler
|
21
|
+
::Object.const_defined?(:Poppler).should eql(false)
|
22
|
+
pdf.load_libpoppler
|
23
|
+
::Object.const_defined?(:Poppler).should eql(true)
|
24
|
+
|
25
|
+
# librsvg
|
26
|
+
::Object.const_defined?(:RSVG).should eql(false)
|
27
|
+
pdf.load_librsvg
|
28
|
+
::Object.const_defined?(:RSVG).should eql(true)
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,194 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
4
|
+
|
5
|
+
context "The PDF::Wrapper class" do
|
6
|
+
specify "should be able to draw a single line onto the canvas" do
|
7
|
+
x0 = y0 = 100
|
8
|
+
x1 = y1 = 200
|
9
|
+
pdf = PDF::Wrapper.new
|
10
|
+
pdf.line(x0,y0,x1,y1)
|
11
|
+
|
12
|
+
receiver = PDF::Reader::RegisterReceiver.new
|
13
|
+
reader = PDF::Reader.string(pdf.render, receiver)
|
14
|
+
|
15
|
+
# the begin_new_subpath command specifies the start of the line, append line specifies the end
|
16
|
+
receiver.count(:begin_new_subpath).should eql(1)
|
17
|
+
receiver.count(:append_line).should eql(1)
|
18
|
+
receiver.first_occurance_of(:begin_new_subpath)[:args].should eql([x0.to_f, 741.89])
|
19
|
+
receiver.first_occurance_of(:append_line)[:args].should eql([x1.to_f, 641.89])
|
20
|
+
end
|
21
|
+
|
22
|
+
specify "should be able to draw a single line onto the canvas with a width of 5" do
|
23
|
+
x0 = y0 = 100
|
24
|
+
x1 = y1 = 200
|
25
|
+
width = 5
|
26
|
+
pdf = PDF::Wrapper.new
|
27
|
+
pdf.line(x0,y0,x1,y1, :line_width => width)
|
28
|
+
|
29
|
+
receiver = PDF::Reader::RegisterReceiver.new
|
30
|
+
reader = PDF::Reader.string(pdf.render, receiver)
|
31
|
+
|
32
|
+
# the begin_new_subpath command specifies the start of the line, append line specifies the end
|
33
|
+
receiver.count(:set_line_width).should eql(1)
|
34
|
+
receiver.count(:begin_new_subpath).should eql(1)
|
35
|
+
receiver.count(:append_line).should eql(1)
|
36
|
+
receiver.first_occurance_of(:set_line_width)[:args].should eql([width.to_f])
|
37
|
+
receiver.first_occurance_of(:begin_new_subpath)[:args].should eql([x0.to_f, 741.89])
|
38
|
+
receiver.first_occurance_of(:append_line)[:args].should eql([x1.to_f, 641.89])
|
39
|
+
end
|
40
|
+
|
41
|
+
specify "should be able to draw a cubic bezier spline onto the canvas"
|
42
|
+
|
43
|
+
specify "should be able to draw an empty rectangle onto the canvas" do
|
44
|
+
x = y = 100
|
45
|
+
w = h = 200
|
46
|
+
pdf = PDF::Wrapper.new
|
47
|
+
pdf.rectangle(x,y,w,h)
|
48
|
+
|
49
|
+
receiver = PDF::Reader::RegisterReceiver.new
|
50
|
+
reader = PDF::Reader.string(pdf.render, receiver)
|
51
|
+
|
52
|
+
# the begin_new_subpath command specifies the start of the line, append line specifies the end
|
53
|
+
callbacks = receiver.all(:append_rectangle)
|
54
|
+
callbacks.size.should eql(2)
|
55
|
+
# don't care about the first rectangel, it just goes around the outside of the page
|
56
|
+
callbacks.shift
|
57
|
+
callbacks.shift[:args].should eql([100.0, 741.89, 200.0, -200.0])
|
58
|
+
end
|
59
|
+
|
60
|
+
specify "should be able to draw an empty rectangle onto the canvas with a line width of 5" do
|
61
|
+
x = y = 100
|
62
|
+
w = h = 200
|
63
|
+
width = 5
|
64
|
+
pdf = PDF::Wrapper.new
|
65
|
+
pdf.rectangle(x,y,w,h, :line_width => width)
|
66
|
+
|
67
|
+
receiver = PDF::Reader::RegisterReceiver.new
|
68
|
+
reader = PDF::Reader.string(pdf.render, receiver)
|
69
|
+
|
70
|
+
# ensure the line width was set correctly
|
71
|
+
receiver.count(:set_line_width).should eql(1)
|
72
|
+
receiver.first_occurance_of(:set_line_width)[:args].should eql([width.to_f])
|
73
|
+
|
74
|
+
# the begin_new_subpath command specifies the start of the line, append line specifies the end
|
75
|
+
callbacks = receiver.all(:append_rectangle)
|
76
|
+
callbacks.size.should eql(2)
|
77
|
+
# don't care about the first rectangel, it just goes around the outside of the page
|
78
|
+
callbacks.shift
|
79
|
+
callbacks.shift[:args].should eql([100.0, 741.89, 200.0, -200.0])
|
80
|
+
end
|
81
|
+
|
82
|
+
specify "should be able to draw a filled rectangle onto the canvas"
|
83
|
+
=begin
|
84
|
+
do
|
85
|
+
x = y = 100
|
86
|
+
w = h = 200
|
87
|
+
pdf = PDF::Wrapper.new
|
88
|
+
pdf.rectangle(x,y,w,h, :fill_color => :red)
|
89
|
+
|
90
|
+
receiver = PDF::Reader::RegisterReceiver.new
|
91
|
+
reader = PDF::Reader.string(pdf.render, receiver)
|
92
|
+
|
93
|
+
# TODO: test for the appropriate pattern of callbacks
|
94
|
+
end
|
95
|
+
=end
|
96
|
+
|
97
|
+
specify "should be able to draw an empty rounded rectangle onto the canvas"
|
98
|
+
=begin
|
99
|
+
do
|
100
|
+
x = y = 100
|
101
|
+
w = h = 200
|
102
|
+
r = 5
|
103
|
+
pdf = PDF::Wrapper.new
|
104
|
+
pdf.rounded_rectangle(x,y,w,h,r)
|
105
|
+
|
106
|
+
receiver = PDF::Reader::RegisterReceiver.new
|
107
|
+
reader = PDF::Reader.string(pdf.render, receiver)
|
108
|
+
|
109
|
+
# TODO: test for the appropriate pattern of callbacks
|
110
|
+
end
|
111
|
+
=end
|
112
|
+
|
113
|
+
specify "should be able to draw an empty rounded rectangle onto the canvas with a line width of 5"
|
114
|
+
=begin
|
115
|
+
do
|
116
|
+
x = y = 100
|
117
|
+
w = h = 200
|
118
|
+
r = 5
|
119
|
+
w = 5
|
120
|
+
pdf = PDF::Wrapper.new
|
121
|
+
pdf.rounded_rectangle(x,y,w,h,r, :line_width => w)
|
122
|
+
|
123
|
+
receiver = PDF::Reader::RegisterReceiver.new
|
124
|
+
reader = PDF::Reader.string(pdf.render, receiver)
|
125
|
+
|
126
|
+
# TODO: test for the appropriate pattern of callbacks
|
127
|
+
end
|
128
|
+
=end
|
129
|
+
|
130
|
+
specify "should be able to draw a filled rounded rectangle onto the canvas"
|
131
|
+
=begin
|
132
|
+
do
|
133
|
+
x = y = 100
|
134
|
+
w = h = 200
|
135
|
+
r = 5
|
136
|
+
pdf = PDF::Wrapper.new
|
137
|
+
pdf.rounded_rectangle(x,y,w,h,r, :fill_color => :red)
|
138
|
+
|
139
|
+
receiver = PDF::Reader::RegisterReceiver.new
|
140
|
+
reader = PDF::Reader.string(pdf.render, receiver)
|
141
|
+
|
142
|
+
# TODO: test for the appropriate pattern of callbacks
|
143
|
+
end
|
144
|
+
=end
|
145
|
+
|
146
|
+
specify "should be able to draw an empty circle onto the canvas"
|
147
|
+
=begin
|
148
|
+
do
|
149
|
+
x = 100
|
150
|
+
y = 200
|
151
|
+
r = 5
|
152
|
+
pdf = PDF::Wrapper.new
|
153
|
+
pdf.circle(x,y,r)
|
154
|
+
|
155
|
+
receiver = PDF::Reader::RegisterReceiver.new
|
156
|
+
reader = PDF::Reader.string(pdf.render, receiver)
|
157
|
+
|
158
|
+
# TODO: test for the appropriate pattern of callbacks
|
159
|
+
end
|
160
|
+
=end
|
161
|
+
|
162
|
+
specify "should be able to draw an empty circle onto the canvas with a line width of 5"
|
163
|
+
=begin
|
164
|
+
do
|
165
|
+
x = 100
|
166
|
+
y = 200
|
167
|
+
r = 5
|
168
|
+
w = 5
|
169
|
+
pdf = PDF::Wrapper.new
|
170
|
+
pdf.circle(x,y,r, :line_width => w)
|
171
|
+
|
172
|
+
receiver = PDF::Reader::RegisterReceiver.new
|
173
|
+
reader = PDF::Reader.string(pdf.render, receiver)
|
174
|
+
|
175
|
+
# TODO: test for the appropriate pattern of callbacks
|
176
|
+
end
|
177
|
+
=end
|
178
|
+
|
179
|
+
specify "should be able to draw a filled circle onto the canvas"
|
180
|
+
=begin
|
181
|
+
do
|
182
|
+
x = 100
|
183
|
+
y = 200
|
184
|
+
r = 5
|
185
|
+
pdf = PDF::Wrapper.new
|
186
|
+
pdf.circle(x,y,r, :fill_color => :red)
|
187
|
+
|
188
|
+
receiver = PDF::Reader::RegisterReceiver.new
|
189
|
+
reader = PDF::Reader.string(pdf.render, receiver)
|
190
|
+
|
191
|
+
# TODO: test for the appropriate pattern of callbacks
|
192
|
+
end
|
193
|
+
=end
|
194
|
+
end
|
@@ -0,0 +1,70 @@
|
|
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
|
+
|
9
|
+
gem "pdf-reader", ">=0.6.1"
|
10
|
+
|
11
|
+
require 'pdf/reader'
|
12
|
+
|
13
|
+
# make some private methods of PDF::Wrapper public for testing
|
14
|
+
class PDF::Wrapper
|
15
|
+
public :build_pango_layout
|
16
|
+
public :calc_image_dimensions
|
17
|
+
public :load_librsvg
|
18
|
+
public :load_libpixbuf
|
19
|
+
public :load_libpango
|
20
|
+
public :load_libpoppler
|
21
|
+
public :default_text_options
|
22
|
+
public :detect_image_type
|
23
|
+
public :draw_pdf
|
24
|
+
public :draw_pixbuf
|
25
|
+
public :draw_png
|
26
|
+
public :draw_svg
|
27
|
+
public :validate_color
|
28
|
+
end
|
29
|
+
|
30
|
+
# a helper class for couting the number of pages in a PDF
|
31
|
+
class PageReceiver
|
32
|
+
attr_accessor :page_count
|
33
|
+
|
34
|
+
def initialize
|
35
|
+
@page_count = 0
|
36
|
+
end
|
37
|
+
|
38
|
+
# Called when page parsing ends
|
39
|
+
def end_page
|
40
|
+
@page_count += 1
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class PageTextReceiver
|
45
|
+
attr_accessor :content
|
46
|
+
|
47
|
+
def initialize
|
48
|
+
@content = []
|
49
|
+
end
|
50
|
+
|
51
|
+
# Called when page parsing starts
|
52
|
+
def begin_page(arg = nil)
|
53
|
+
@content << ""
|
54
|
+
end
|
55
|
+
|
56
|
+
def show_text(string, *params)
|
57
|
+
@content.last << string.strip
|
58
|
+
end
|
59
|
+
|
60
|
+
# there's a few text callbacks, so make sure we process them all
|
61
|
+
alias :super_show_text :show_text
|
62
|
+
alias :move_to_next_line_and_show_text :show_text
|
63
|
+
alias :set_spacing_next_line_show_text :show_text
|
64
|
+
|
65
|
+
def show_text_with_positioning(*params)
|
66
|
+
params = params.first
|
67
|
+
params.each { |str| show_text(str) if str.kind_of?(String) }
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
data/specs/text_spec.rb
ADDED
@@ -0,0 +1,153 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
4
|
+
|
5
|
+
context "The PDF::Wrapper class" do
|
6
|
+
specify "should be able to add ascii text to the canvas" do
|
7
|
+
msg = "Chunky Bacon"
|
8
|
+
pdf = PDF::Wrapper.new
|
9
|
+
pdf.text msg
|
10
|
+
|
11
|
+
receiver = PageTextReceiver.new
|
12
|
+
reader = PDF::Reader.string(pdf.render, receiver)
|
13
|
+
|
14
|
+
# TODO: test for the text is in the appropriate location on the page
|
15
|
+
receiver.content.first.should eql(msg)
|
16
|
+
end
|
17
|
+
|
18
|
+
specify "should be able to add unicode text to the canvas" do
|
19
|
+
msg = "メインページ"
|
20
|
+
pdf = PDF::Wrapper.new
|
21
|
+
pdf.text msg
|
22
|
+
|
23
|
+
receiver = PageTextReceiver.new
|
24
|
+
reader = PDF::Reader.string(pdf.render, receiver)
|
25
|
+
|
26
|
+
# TODO: test for the text is in the appropriate location on the page
|
27
|
+
receiver.content.first.should eql(msg)
|
28
|
+
end
|
29
|
+
|
30
|
+
specify "should be align text on the left when using the text method" do
|
31
|
+
msg = "Chunky Bacon"
|
32
|
+
pdf = PDF::Wrapper.new
|
33
|
+
pdf.text msg, :alignment => :left
|
34
|
+
|
35
|
+
receiver = PDF::Reader::RegisterReceiver.new
|
36
|
+
reader = PDF::Reader.string(pdf.render, receiver)
|
37
|
+
|
38
|
+
# set_text_matrix_and_text_line_matrix - [10.666992, 0.0, 0.0, 10.666992, 265.0, 788.89]
|
39
|
+
|
40
|
+
# ensure the text is placed in the right location
|
41
|
+
params = receiver.first_occurance_of(:set_text_matrix_and_text_line_matrix)[:args]
|
42
|
+
params[4].should eql(pdf.margin_left.to_f)
|
43
|
+
end
|
44
|
+
|
45
|
+
specify "should be align text in the centre when using the text method" do
|
46
|
+
msg = "Chunky Bacon"
|
47
|
+
pdf = PDF::Wrapper.new
|
48
|
+
pdf.text msg, :alignment => :center
|
49
|
+
|
50
|
+
receiver = PDF::Reader::RegisterReceiver.new
|
51
|
+
reader = PDF::Reader.string(pdf.render, receiver)
|
52
|
+
|
53
|
+
# ensure the text is placed in the right location - the left
|
54
|
+
# egde should be less than half way across the page, but not on the left margin
|
55
|
+
params = receiver.first_occurance_of(:set_text_matrix_and_text_line_matrix)[:args]
|
56
|
+
(params[4] < pdf.absolute_x_middle).should be_true
|
57
|
+
(params[4] > pdf.absolute_x_middle - 100).should be_true
|
58
|
+
end
|
59
|
+
|
60
|
+
specify "should be align text on the right when using the text method" do
|
61
|
+
msg = "Chunky Bacon"
|
62
|
+
pdf = PDF::Wrapper.new
|
63
|
+
pdf.text msg, :alignment => :right
|
64
|
+
|
65
|
+
receiver = PDF::Reader::RegisterReceiver.new
|
66
|
+
reader = PDF::Reader.string(pdf.render, receiver)
|
67
|
+
|
68
|
+
# ensure the text is placed in the right location - the left
|
69
|
+
# egde should be more than half way across the page, but not on the right margin
|
70
|
+
params = receiver.first_occurance_of(:set_text_matrix_and_text_line_matrix)[:args]
|
71
|
+
(params[4] > pdf.absolute_x_middle).should be_true
|
72
|
+
(params[4] < pdf.absolute_right_margin).should be_true
|
73
|
+
end
|
74
|
+
|
75
|
+
specify "should be able to add text to the canvas in a bounding box using the cell method" do
|
76
|
+
msg = "メインページ"
|
77
|
+
pdf = PDF::Wrapper.new
|
78
|
+
pdf.cell msg, 100, 100, 200, 200
|
79
|
+
|
80
|
+
receiver = PageTextReceiver.new
|
81
|
+
reader = PDF::Reader.string(pdf.render, receiver)
|
82
|
+
|
83
|
+
# TODO: test for the text is in the appropriate location on the page
|
84
|
+
receiver.content.first.should eql(msg)
|
85
|
+
end
|
86
|
+
|
87
|
+
specify "should keep all text for a cell inside the cell boundaries" do
|
88
|
+
msg = "This is a text cell, added by James"
|
89
|
+
pdf = PDF::Wrapper.new
|
90
|
+
x = y = 100
|
91
|
+
w = h = 200
|
92
|
+
pdf.cell msg, x, y, w, h
|
93
|
+
|
94
|
+
receiver = PDF::Reader::RegisterReceiver.new
|
95
|
+
reader = PDF::Reader.string(pdf.render, receiver)
|
96
|
+
|
97
|
+
receiver.all(:set_text_matrix_and_text_line_matrix).each do |cb|
|
98
|
+
# horizontal location
|
99
|
+
# TODO: we're only testing the it doesn't start past the right boundary of the cell
|
100
|
+
# should also test that it doesn't start in the cell but overrun it
|
101
|
+
(cb[:args][4] >= x).should be_true
|
102
|
+
(cb[:args][4] <= x + w).should be_true
|
103
|
+
|
104
|
+
# vertical location
|
105
|
+
# TODO: we're only testing the it doesn't start past the bottom boundary of the cell
|
106
|
+
# should also test that it doesn't start in the cell but overrun it
|
107
|
+
cell_top_bound = pdf.page_height - y
|
108
|
+
(cb[:args][5] <= cell_top_bound).should be_true
|
109
|
+
(cb[:args][5] >= cell_top_bound - h).should be_true
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
specify "should be able to calculate the height of a string of text" do
|
114
|
+
str = "This is a medium length string\nthat is also multi line. one two three four."
|
115
|
+
pdf = PDF::Wrapper.new
|
116
|
+
opts = {:font_size => 16, :font => "Sans Serif", :alignment => :left, :justify => false }
|
117
|
+
pdf.text_height(str, pdf.body_width, opts).should eql(49)
|
118
|
+
end
|
119
|
+
|
120
|
+
specify "should be able to calculate the width of a string of text" do
|
121
|
+
str = "James Healy"
|
122
|
+
str2 = "James Healy is a Ruby dev that lives in Melbourne, Australia. His day job mostly involved Ruby on Rails."
|
123
|
+
pdf = PDF::Wrapper.new
|
124
|
+
opts = {:font_size => 16, :font => "Sans Serif"}
|
125
|
+
pdf.text(str, opts)
|
126
|
+
pdf.text_width(str, opts).should eql(131)
|
127
|
+
pdf.text_width(str2, opts).should eql(1107)
|
128
|
+
end
|
129
|
+
|
130
|
+
specify "should raise an exception if build_pango_layout is passed anything other than a string" do
|
131
|
+
pdf = PDF::Wrapper.new
|
132
|
+
lambda { pdf.build_pango_layout(10) }.should raise_error(ArgumentError)
|
133
|
+
end
|
134
|
+
|
135
|
+
if RUBY_VERSION >= "1.9"
|
136
|
+
specify "should accept non UTF-8 strings to build_pango_layout and convert them on the fly" do
|
137
|
+
pdf = PDF::Wrapper.new
|
138
|
+
|
139
|
+
# all three of these files have the same content, but in different encodings
|
140
|
+
iso2022_str = File.open(File.dirname(__FILE__) + "/data/shift_jis.txt", "r:ISO-2022-JP") { |f| f.read }.strip!
|
141
|
+
shiftjis_str = File.open(File.dirname(__FILE__) + "/data/iso-2022-jp.txt", "r:Shift_JIS") { |f| f.read }.strip!
|
142
|
+
utf8_str = File.open(File.dirname(__FILE__) + "/data/utf8.txt", "r:UTF-8") { |f| f.read }.strip!
|
143
|
+
|
144
|
+
pdf.build_pango_layout(shiftjis_str)
|
145
|
+
pdf.build_pango_layout(iso2022_str)
|
146
|
+
|
147
|
+
# TODO: improve this spec using mocks. Atm, I'm assume that if build_pango_layout didn't raise an exception when
|
148
|
+
# passed in the non UTF-8 strings, then all worked fine. yuck.
|
149
|
+
end
|
150
|
+
|
151
|
+
specify "should raise an error when a string that isn't convertable to UTF-8 is passed into build_pango_layout()"
|
152
|
+
end
|
153
|
+
end
|
data/specs/wrapper_spec.rb
CHANGED
@@ -1,108 +1,9 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
require 'pdf/wrapper'
|
6
|
-
require 'tempfile'
|
7
|
-
require 'rubygems'
|
8
|
-
|
9
|
-
gem "pdf-reader", ">=0.6.1"
|
10
|
-
|
11
|
-
require 'pdf/reader'
|
12
|
-
|
13
|
-
# make some private methods of PDF::Wrapper public for testing
|
14
|
-
class PDF::Wrapper
|
15
|
-
public :build_pango_layout
|
16
|
-
public :calc_image_dimensions
|
17
|
-
public :load_librsvg
|
18
|
-
public :load_libpixbuf
|
19
|
-
public :load_libpango
|
20
|
-
public :load_libpoppler
|
21
|
-
public :default_text_options
|
22
|
-
public :detect_image_type
|
23
|
-
public :draw_pdf
|
24
|
-
public :draw_pixbuf
|
25
|
-
public :draw_png
|
26
|
-
public :draw_svg
|
27
|
-
public :validate_color
|
28
|
-
end
|
29
|
-
|
30
|
-
# a helper class for couting the number of pages in a PDF
|
31
|
-
class PageReceiver
|
32
|
-
attr_accessor :page_count
|
33
|
-
|
34
|
-
def initialize
|
35
|
-
@page_count = 0
|
36
|
-
end
|
37
|
-
|
38
|
-
# Called when page parsing ends
|
39
|
-
def end_page
|
40
|
-
@page_count += 1
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
class PageTextReceiver
|
45
|
-
attr_accessor :content
|
46
|
-
|
47
|
-
def initialize
|
48
|
-
@content = []
|
49
|
-
end
|
50
|
-
|
51
|
-
# Called when page parsing starts
|
52
|
-
def begin_page(arg = nil)
|
53
|
-
@content << ""
|
54
|
-
end
|
55
|
-
|
56
|
-
def show_text(string, *params)
|
57
|
-
@content.last << string.strip
|
58
|
-
end
|
59
|
-
|
60
|
-
# there's a few text callbacks, so make sure we process them all
|
61
|
-
alias :super_show_text :show_text
|
62
|
-
alias :move_to_next_line_and_show_text :show_text
|
63
|
-
alias :set_spacing_next_line_show_text :show_text
|
64
|
-
|
65
|
-
def show_text_with_positioning(*params)
|
66
|
-
params = params.first
|
67
|
-
params.each { |str| show_text(str) if str.kind_of?(String) }
|
68
|
-
end
|
69
|
-
|
70
|
-
end
|
3
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
71
4
|
|
72
5
|
context "The PDF::Wrapper class" do
|
73
6
|
|
74
|
-
setup do
|
75
|
-
#@file = File.new(File.dirname(__FILE__) + "/data/cairo-basic.pdf")
|
76
|
-
@shortstr = "Chunky Bacon"
|
77
|
-
@medstr = "This is a medium length string\nthat is also multi line. one two three four."
|
78
|
-
end
|
79
|
-
|
80
|
-
specify "should load external libs correctly" do
|
81
|
-
pdf = PDF::Wrapper.new
|
82
|
-
|
83
|
-
# lib gdkpixbuf
|
84
|
-
::Object.const_defined?(:Gdk).should eql(false)
|
85
|
-
pdf.load_libpixbuf
|
86
|
-
::Object.const_defined?(:Gdk).should eql(true)
|
87
|
-
::Gdk.const_defined?(:Pixbuf).should eql(true)
|
88
|
-
|
89
|
-
# pango
|
90
|
-
::Object.const_defined?(:Pango).should eql(false)
|
91
|
-
pdf.load_libpango
|
92
|
-
::Object.const_defined?(:Pango).should eql(true)
|
93
|
-
|
94
|
-
# libpoppler
|
95
|
-
::Object.const_defined?(:Poppler).should eql(false)
|
96
|
-
pdf.load_libpoppler
|
97
|
-
::Object.const_defined?(:Poppler).should eql(true)
|
98
|
-
|
99
|
-
# librsvg
|
100
|
-
::Object.const_defined?(:RSVG).should eql(false)
|
101
|
-
pdf.load_librsvg
|
102
|
-
::Object.const_defined?(:RSVG).should eql(true)
|
103
|
-
|
104
|
-
end
|
105
|
-
|
106
7
|
specify "should initilize with the correct default paper size and orientation" do
|
107
8
|
pdf = PDF::Wrapper.new
|
108
9
|
pdf.page_width.should eql(PDF::Wrapper::PAGE_SIZES[:A4].first)
|
@@ -211,6 +112,16 @@ context "The PDF::Wrapper class" do
|
|
211
112
|
lambda {pdf.move_to(100, PDF::Wrapper::PAGE_SIZES[:A4].last + 10)}.should raise_error(ArgumentError)
|
212
113
|
end
|
213
114
|
|
115
|
+
specify "should be able to shift the y position of the cursor using pad" do
|
116
|
+
pdf = PDF::Wrapper.new
|
117
|
+
pdf.move_to(100,100)
|
118
|
+
newy = pdf.pad(25)
|
119
|
+
x,y = pdf.current_point
|
120
|
+
x.to_i.should eql(100)
|
121
|
+
y.to_i.should eql(125)
|
122
|
+
newy.should eql(125.0)
|
123
|
+
end
|
124
|
+
|
214
125
|
specify "should add additional pages at the users request" do
|
215
126
|
pdf = PDF::Wrapper.new
|
216
127
|
pdf.move_to(100,100)
|
@@ -225,79 +136,6 @@ context "The PDF::Wrapper class" do
|
|
225
136
|
receiver.page_count.should eql(2)
|
226
137
|
end
|
227
138
|
|
228
|
-
specify "should be able to draw a single line onto the canvas" do
|
229
|
-
x0 = y0 = 100
|
230
|
-
x1 = y1 = 200
|
231
|
-
pdf = PDF::Wrapper.new
|
232
|
-
pdf.line(x0,y0,x1,y1)
|
233
|
-
|
234
|
-
receiver = PDF::Reader::RegisterReceiver.new
|
235
|
-
reader = PDF::Reader.string(pdf.render, receiver)
|
236
|
-
|
237
|
-
# the begin_new_subpath command specifies the start of the line, append line specifies the end
|
238
|
-
receiver.count(:begin_new_subpath).should eql(1)
|
239
|
-
receiver.count(:append_line).should eql(1)
|
240
|
-
receiver.first_occurance_of(:begin_new_subpath)[:args].should eql([x0.to_f, y0.to_f])
|
241
|
-
receiver.first_occurance_of(:append_line)[:args].should eql([x1.to_f, y1.to_f])
|
242
|
-
end
|
243
|
-
|
244
|
-
specify "should be able to draw a single line onto the canvas with a width of 5" do
|
245
|
-
x0 = y0 = 100
|
246
|
-
x1 = y1 = 200
|
247
|
-
width = 5
|
248
|
-
pdf = PDF::Wrapper.new
|
249
|
-
pdf.line(x0,y0,x1,y1, :line_width => width)
|
250
|
-
|
251
|
-
receiver = PDF::Reader::RegisterReceiver.new
|
252
|
-
reader = PDF::Reader.string(pdf.render, receiver)
|
253
|
-
|
254
|
-
# the begin_new_subpath command specifies the start of the line, append line specifies the end
|
255
|
-
receiver.count(:set_line_width).should eql(1)
|
256
|
-
receiver.count(:begin_new_subpath).should eql(1)
|
257
|
-
receiver.count(:append_line).should eql(1)
|
258
|
-
receiver.first_occurance_of(:set_line_width)[:args].should eql([width.to_f])
|
259
|
-
receiver.first_occurance_of(:begin_new_subpath)[:args].should eql([x0.to_f, y0.to_f])
|
260
|
-
receiver.first_occurance_of(:append_line)[:args].should eql([x1.to_f, y1.to_f])
|
261
|
-
end
|
262
|
-
|
263
|
-
specify "should be able to draw an empty rectangle onto the canvas" do
|
264
|
-
x = y = 100
|
265
|
-
w = h = 200
|
266
|
-
pdf = PDF::Wrapper.new
|
267
|
-
pdf.rectangle(x,y,w,h)
|
268
|
-
|
269
|
-
receiver = PDF::Reader::RegisterReceiver.new
|
270
|
-
reader = PDF::Reader.string(pdf.render, receiver)
|
271
|
-
|
272
|
-
# the begin_new_subpath command specifies the start of the line, append line specifies the end
|
273
|
-
callbacks = receiver.series(:begin_new_subpath, :append_line,:append_line,:append_line, :close_subpath)
|
274
|
-
callbacks.shift[:args].should eql([x.to_f, y.to_f])
|
275
|
-
callbacks.shift[:args].should eql([(x+w).to_f, y.to_f])
|
276
|
-
callbacks.shift[:args].should eql([(x+w).to_f, (y+h).to_f])
|
277
|
-
callbacks.shift[:args].should eql([x.to_f, (y+h).to_f])
|
278
|
-
end
|
279
|
-
|
280
|
-
specify "should be able to draw an empty rectangle onto the canvas with a line width of 5" do
|
281
|
-
x = y = 100
|
282
|
-
w = h = 200
|
283
|
-
width = 5
|
284
|
-
pdf = PDF::Wrapper.new
|
285
|
-
pdf.rectangle(x,y,w,h, :line_width => width)
|
286
|
-
|
287
|
-
receiver = PDF::Reader::RegisterReceiver.new
|
288
|
-
reader = PDF::Reader.string(pdf.render, receiver)
|
289
|
-
|
290
|
-
# ensure the line width was set correctly
|
291
|
-
receiver.count(:set_line_width).should eql(1)
|
292
|
-
receiver.first_occurance_of(:set_line_width)[:args].should eql([width.to_f])
|
293
|
-
|
294
|
-
# the begin_new_subpath command specifies the start of the line, append line specifies the end
|
295
|
-
callbacks = receiver.series(:begin_new_subpath, :append_line,:append_line,:append_line, :close_subpath)
|
296
|
-
callbacks.shift[:args].should eql([x.to_f, y.to_f])
|
297
|
-
callbacks.shift[:args].should eql([(x+w).to_f, y.to_f])
|
298
|
-
callbacks.shift[:args].should eql([(x+w).to_f, (y+h).to_f])
|
299
|
-
callbacks.shift[:args].should eql([x.to_f, (y+h).to_f])
|
300
|
-
end
|
301
139
|
|
302
140
|
specify "should leave the cursor in the bottom left of a layout when new text is added" do
|
303
141
|
pdf = PDF::Wrapper.new
|
@@ -309,185 +147,10 @@ context "The PDF::Wrapper class" do
|
|
309
147
|
newx, newy = pdf.current_point
|
310
148
|
|
311
149
|
newx.should eql(x)
|
312
|
-
|
150
|
+
# the top of our text box, plus its height
|
313
151
|
newy.should eql(y + height)
|
314
152
|
end
|
315
153
|
|
316
|
-
specify "should be able to draw a filled rectangle onto the canvas"
|
317
|
-
=begin
|
318
|
-
do
|
319
|
-
x = y = 100
|
320
|
-
w = h = 200
|
321
|
-
pdf = PDF::Wrapper.new
|
322
|
-
pdf.rectangle(x,y,w,h, :fill_color => :red)
|
323
|
-
|
324
|
-
receiver = PDF::Reader::RegisterReceiver.new
|
325
|
-
reader = PDF::Reader.string(pdf.render, receiver)
|
326
|
-
|
327
|
-
# TODO: test for the appropriate pattern of callbacks
|
328
|
-
end
|
329
|
-
=end
|
330
|
-
|
331
|
-
specify "should be able to draw an empty rounded rectangle onto the canvas"
|
332
|
-
=begin
|
333
|
-
do
|
334
|
-
x = y = 100
|
335
|
-
w = h = 200
|
336
|
-
r = 5
|
337
|
-
pdf = PDF::Wrapper.new
|
338
|
-
pdf.rounded_rectangle(x,y,w,h,r)
|
339
|
-
|
340
|
-
receiver = PDF::Reader::RegisterReceiver.new
|
341
|
-
reader = PDF::Reader.string(pdf.render, receiver)
|
342
|
-
|
343
|
-
# TODO: test for the appropriate pattern of callbacks
|
344
|
-
end
|
345
|
-
=end
|
346
|
-
|
347
|
-
specify "should be able to draw an empty rounded rectangle onto the canvas with a line width of 5"
|
348
|
-
=begin
|
349
|
-
do
|
350
|
-
x = y = 100
|
351
|
-
w = h = 200
|
352
|
-
r = 5
|
353
|
-
w = 5
|
354
|
-
pdf = PDF::Wrapper.new
|
355
|
-
pdf.rounded_rectangle(x,y,w,h,r, :line_width => w)
|
356
|
-
|
357
|
-
receiver = PDF::Reader::RegisterReceiver.new
|
358
|
-
reader = PDF::Reader.string(pdf.render, receiver)
|
359
|
-
|
360
|
-
# TODO: test for the appropriate pattern of callbacks
|
361
|
-
end
|
362
|
-
=end
|
363
|
-
|
364
|
-
specify "should be able to draw a filled rounded rectangle onto the canvas"
|
365
|
-
=begin
|
366
|
-
do
|
367
|
-
x = y = 100
|
368
|
-
w = h = 200
|
369
|
-
r = 5
|
370
|
-
pdf = PDF::Wrapper.new
|
371
|
-
pdf.rounded_rectangle(x,y,w,h,r, :fill_color => :red)
|
372
|
-
|
373
|
-
receiver = PDF::Reader::RegisterReceiver.new
|
374
|
-
reader = PDF::Reader.string(pdf.render, receiver)
|
375
|
-
|
376
|
-
# TODO: test for the appropriate pattern of callbacks
|
377
|
-
end
|
378
|
-
=end
|
379
|
-
|
380
|
-
specify "should be able to draw an empty circle onto the canvas"
|
381
|
-
=begin
|
382
|
-
do
|
383
|
-
x = 100
|
384
|
-
y = 200
|
385
|
-
r = 5
|
386
|
-
pdf = PDF::Wrapper.new
|
387
|
-
pdf.circle(x,y,r)
|
388
|
-
|
389
|
-
receiver = PDF::Reader::RegisterReceiver.new
|
390
|
-
reader = PDF::Reader.string(pdf.render, receiver)
|
391
|
-
|
392
|
-
# TODO: test for the appropriate pattern of callbacks
|
393
|
-
end
|
394
|
-
=end
|
395
|
-
|
396
|
-
specify "should be able to draw an empty circle onto the canvas with a line width of 5"
|
397
|
-
=begin
|
398
|
-
do
|
399
|
-
x = 100
|
400
|
-
y = 200
|
401
|
-
r = 5
|
402
|
-
w = 5
|
403
|
-
pdf = PDF::Wrapper.new
|
404
|
-
pdf.circle(x,y,r, :line_width => w)
|
405
|
-
|
406
|
-
receiver = PDF::Reader::RegisterReceiver.new
|
407
|
-
reader = PDF::Reader.string(pdf.render, receiver)
|
408
|
-
|
409
|
-
# TODO: test for the appropriate pattern of callbacks
|
410
|
-
end
|
411
|
-
=end
|
412
|
-
|
413
|
-
specify "should be able to draw a filled circle onto the canvas"
|
414
|
-
=begin
|
415
|
-
do
|
416
|
-
x = 100
|
417
|
-
y = 200
|
418
|
-
r = 5
|
419
|
-
pdf = PDF::Wrapper.new
|
420
|
-
pdf.circle(x,y,r, :fill_color => :red)
|
421
|
-
|
422
|
-
receiver = PDF::Reader::RegisterReceiver.new
|
423
|
-
reader = PDF::Reader.string(pdf.render, receiver)
|
424
|
-
|
425
|
-
# TODO: test for the appropriate pattern of callbacks
|
426
|
-
end
|
427
|
-
=end
|
428
|
-
|
429
|
-
specify "should be able to add ascii text to the canvas" do
|
430
|
-
msg = "Chunky Bacon"
|
431
|
-
pdf = PDF::Wrapper.new
|
432
|
-
pdf.text msg
|
433
|
-
|
434
|
-
receiver = PageTextReceiver.new
|
435
|
-
reader = PDF::Reader.string(pdf.render, receiver)
|
436
|
-
|
437
|
-
# TODO: test for the text is in the appropriate location on the page
|
438
|
-
receiver.content.first.should eql(msg)
|
439
|
-
end
|
440
|
-
|
441
|
-
specify "should be able to add unicode text to the canvas" do
|
442
|
-
msg = "メインページ"
|
443
|
-
pdf = PDF::Wrapper.new
|
444
|
-
pdf.text msg
|
445
|
-
|
446
|
-
receiver = PageTextReceiver.new
|
447
|
-
reader = PDF::Reader.string(pdf.render, receiver)
|
448
|
-
|
449
|
-
# TODO: test for the text is in the appropriate location on the page
|
450
|
-
receiver.content.first.should eql(msg)
|
451
|
-
end
|
452
|
-
|
453
|
-
specify "should be able to add text to the canvas in a bounding box using the cell method" do
|
454
|
-
msg = "メインページ"
|
455
|
-
pdf = PDF::Wrapper.new
|
456
|
-
pdf.cell msg, 100, 100, 200, 200
|
457
|
-
|
458
|
-
receiver = PageTextReceiver.new
|
459
|
-
reader = PDF::Reader.string(pdf.render, receiver)
|
460
|
-
|
461
|
-
# TODO: test for the text is in the appropriate location on the page
|
462
|
-
receiver.content.first.should eql(msg)
|
463
|
-
end
|
464
|
-
|
465
|
-
specify "should keep all text for a cell inside the cell boundaries" do
|
466
|
-
msg = "This is a text cell, added by James"
|
467
|
-
pdf = PDF::Wrapper.new
|
468
|
-
x = y = 100
|
469
|
-
w = h = 200
|
470
|
-
pdf.cell msg, x, y, w, h
|
471
|
-
|
472
|
-
receiver = PDF::Reader::RegisterReceiver.new
|
473
|
-
reader = PDF::Reader.string(pdf.render, receiver)
|
474
|
-
|
475
|
-
receiver.all(:set_text_matrix_and_text_line_matrix).each do |cb|
|
476
|
-
# horizontal location
|
477
|
-
# TODO: we're only testing the it doesn't start past the right boundary of the cell
|
478
|
-
# should also test that it doesn't start in the cell but overrun it
|
479
|
-
(cb[:args][4] >= x).should be_true
|
480
|
-
(cb[:args][4] <= x + w).should be_true
|
481
|
-
|
482
|
-
# vertical location
|
483
|
-
# TODO: we're only testing the it doesn't start past the bottom boundary of the cell
|
484
|
-
# should also test that it doesn't start in the cell but overrun it
|
485
|
-
cell_top_bound = pdf.page_height - y
|
486
|
-
(cb[:args][5] <= cell_top_bound).should be_true
|
487
|
-
(cb[:args][5] >= cell_top_bound - h).should be_true
|
488
|
-
end
|
489
|
-
end
|
490
|
-
|
491
154
|
specify "should be able to render to a file" do
|
492
155
|
# generate a PDF
|
493
156
|
msg = "Chunky Bacon"
|
@@ -508,21 +171,6 @@ context "The PDF::Wrapper class" do
|
|
508
171
|
tmp.unlink
|
509
172
|
end
|
510
173
|
|
511
|
-
specify "should be able to detect the filetype of an image" do
|
512
|
-
pdf = PDF::Wrapper.new
|
513
|
-
pdf.detect_image_type(File.dirname(__FILE__) + "/data/google.png").should eql(:png)
|
514
|
-
pdf.detect_image_type(File.dirname(__FILE__) + "/data/zits.gif").should eql(:gif)
|
515
|
-
pdf.detect_image_type(File.dirname(__FILE__) + "/data/orc.svg").should eql(:svg)
|
516
|
-
pdf.detect_image_type(File.dirname(__FILE__) + "/data/utf8-long.pdf").should eql(:pdf)
|
517
|
-
pdf.detect_image_type(File.dirname(__FILE__) + "/data/shipsail.jpg").should eql(:jpg)
|
518
|
-
end
|
519
|
-
|
520
|
-
specify "should be able to calculate the height of a string of text" do
|
521
|
-
pdf = PDF::Wrapper.new
|
522
|
-
opts = {:font_size => 16, :font => "Sans Serif", :alignment => :left, :justify => false }
|
523
|
-
pdf.text_height(@medstr, pdf.body_width, opts).should eql(49)
|
524
|
-
end
|
525
|
-
|
526
174
|
specify "should be able to draw a table on the canvas"
|
527
175
|
|
528
176
|
specify "should leave the cursor in the bottom left when adding a table" do
|
@@ -541,31 +189,6 @@ context "The PDF::Wrapper class" do
|
|
541
189
|
x.to_i.should eql(100)
|
542
190
|
end
|
543
191
|
|
544
|
-
specify "should raise an exception if build_pango_layout is passed anything other than a string" do
|
545
|
-
pdf = PDF::Wrapper.new
|
546
|
-
lambda { pdf.build_pango_layout(10) }.should raise_error(ArgumentError)
|
547
|
-
|
548
|
-
end
|
549
|
-
|
550
|
-
if RUBY_VERSION >= "1.9"
|
551
|
-
specify "should accept non UTF-8 strings to build_pango_layout and convert them on the fly" do
|
552
|
-
pdf = PDF::Wrapper.new
|
553
|
-
|
554
|
-
# all three of these files have the same content, but in different encodings
|
555
|
-
iso2022_str = File.open(File.dirname(__FILE__) + "/data/shift_jis.txt", "r:ISO-2022-JP") { |f| f.read }.strip!
|
556
|
-
shiftjis_str = File.open(File.dirname(__FILE__) + "/data/iso-2022-jp.txt", "r:Shift_JIS") { |f| f.read }.strip!
|
557
|
-
utf8_str = File.open(File.dirname(__FILE__) + "/data/utf8.txt", "r:UTF-8") { |f| f.read }.strip!
|
558
|
-
|
559
|
-
pdf.build_pango_layout(shiftjis_str)
|
560
|
-
pdf.build_pango_layout(iso2022_str)
|
561
|
-
|
562
|
-
# TODO: improve this spec using mocks. Atm, I'm assume that if build_pango_layout didn't raise an exception when
|
563
|
-
# passed in the non UTF-8 strings, then all worked fine. yuck.
|
564
|
-
end
|
565
|
-
|
566
|
-
specify "should raise an error when a string that isn't convertable to UTF-8 is passed into build_pango_layout()"
|
567
|
-
end
|
568
|
-
|
569
192
|
specify "should be able to determine if a requested colour is valid or not" do
|
570
193
|
pdf = PDF::Wrapper.new
|
571
194
|
pdf.validate_color(:black).should be_true
|
@@ -794,12 +417,4 @@ context "The PDF::Wrapper class" do
|
|
794
417
|
lambda { pdf.rounded_rectangle(100,100,100,100,10, :ponies => true)}.should raise_error(ArgumentError)
|
795
418
|
lambda { pdf.image(File.dirname(__FILE__) + "/data/orc.svg", :ponies => true)}.should raise_error(ArgumentError)
|
796
419
|
end
|
797
|
-
|
798
|
-
specify "should be able to calculate image dimensions correctly" do
|
799
|
-
pdf = PDF::Wrapper.new
|
800
|
-
pdf.calc_image_dimensions(100, 100, 200, 200).should eql([100.0,100.0])
|
801
|
-
pdf.calc_image_dimensions(nil, nil, 200, 200).should eql([200.0,200.0])
|
802
|
-
pdf.calc_image_dimensions(150, 200, 200, 200, true).should eql([150.0,150.0])
|
803
|
-
pdf.calc_image_dimensions(300, 250, 200, 200, true).should eql([250.0,250.0])
|
804
|
-
end
|
805
420
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pdf-wrapper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- James Healy
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-
|
12
|
+
date: 2008-04-27 00:00:00 +10:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -24,28 +24,33 @@ extra_rdoc_files:
|
|
24
24
|
- CHANGELOG
|
25
25
|
- TODO
|
26
26
|
files:
|
27
|
-
- examples/repeating.rb
|
28
27
|
- examples/cell.rb
|
29
28
|
- examples/image.rb
|
30
|
-
- examples/
|
31
|
-
- examples/table.rb
|
29
|
+
- examples/repeating.rb
|
32
30
|
- examples/shapes.rb
|
31
|
+
- examples/table.rb
|
32
|
+
- examples/utf8-long.rb
|
33
33
|
- examples/utf8.rb
|
34
34
|
- lib/pdf
|
35
|
-
- lib/pdf/wrapper.rb
|
36
35
|
- lib/pdf/core.rb
|
36
|
+
- lib/pdf/wrapper.rb
|
37
37
|
- specs/data
|
38
|
-
- specs/data/shift_jis.txt
|
39
38
|
- specs/data/google.png
|
40
|
-
- specs/data/utf8-long.txt
|
41
39
|
- specs/data/iso-2022-jp.txt
|
42
|
-
- specs/data/utf8.txt
|
43
|
-
- specs/data/shipsail.jpg
|
44
|
-
- specs/data/zits.gif
|
45
40
|
- specs/data/orc.svg
|
41
|
+
- specs/data/shift_jis.txt
|
42
|
+
- specs/data/shipsail.jpg
|
46
43
|
- specs/data/stef.jpg
|
47
44
|
- specs/data/utf8-long.pdf
|
45
|
+
- specs/data/utf8-long.txt
|
46
|
+
- specs/data/utf8.txt
|
47
|
+
- specs/data/zits.gif
|
48
48
|
- specs/wrapper_spec.rb
|
49
|
+
- specs/load_spec.rb
|
50
|
+
- specs/shapes_spec.rb
|
51
|
+
- specs/text_spec.rb
|
52
|
+
- specs/spec_helper.rb
|
53
|
+
- specs/image_spec.rb
|
49
54
|
- Rakefile
|
50
55
|
- README
|
51
56
|
- CHANGELOG
|