pdf-wrapper 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +6 -1
- data/Rakefile +1 -1
- data/examples/padded_image.rb +12 -0
- data/examples/template.rb +13 -0
- data/lib/pdf/wrapper.rb +69 -17
- data/specs/image_spec.rb +12 -1
- data/specs/spec_helper.rb +20 -5
- data/specs/wrapper_spec.rb +24 -1
- metadata +4 -2
data/CHANGELOG
CHANGED
@@ -1,4 +1,9 @@
|
|
1
|
-
v0.0.
|
1
|
+
v0.0.7 (30th April 2008)
|
2
|
+
- Added support for creating new pages from a template file (pdf/png/jpg/gif/svg/probably more)
|
3
|
+
- Convert the params to start_new_page to be an options hash
|
4
|
+
- Added a :padding option to PDF::Wrapper#image
|
5
|
+
|
6
|
+
v0.0.6 (28th April 2008)
|
2
7
|
- Fix a nasty bug in text layout code
|
3
8
|
|
4
9
|
v0.0.5 (27th April 2008)
|
data/Rakefile
CHANGED
@@ -0,0 +1,12 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# coding: utf-8
|
3
|
+
|
4
|
+
$:.unshift(File.dirname(__FILE__) + "/../lib")
|
5
|
+
|
6
|
+
require 'pdf/wrapper'
|
7
|
+
|
8
|
+
pdf = PDF::Wrapper.new(:paper => :A4)
|
9
|
+
pdf.rectangle(100, 100, 200, 200)
|
10
|
+
pdf.image(File.dirname(__FILE__) + "/../specs/data/zits.gif", :left => 100, :top => 100, :width => 200, :height => 200, :padding => 25, :proportional => true)
|
11
|
+
|
12
|
+
pdf.render_to_file("image.pdf")
|
@@ -0,0 +1,13 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# coding: utf-8
|
3
|
+
|
4
|
+
$:.unshift(File.dirname(__FILE__) + "/../lib")
|
5
|
+
|
6
|
+
require 'pdf/wrapper'
|
7
|
+
|
8
|
+
pdf = PDF::Wrapper.new(:paper => :A4)
|
9
|
+
pdf.default_font("Sans Serif")
|
10
|
+
pdf.default_color(:black)
|
11
|
+
pdf.text "James", :font => "Monospace", :font_size => 8, :alignment => :left
|
12
|
+
#pdf.start_new_page()
|
13
|
+
pdf.render_to_file("template.pdf")
|
data/lib/pdf/wrapper.rb
CHANGED
@@ -87,6 +87,9 @@ module PDF
|
|
87
87
|
# <tt>:margin_bottom</tt>:: The size of the default bottom margin (default 5% of page)
|
88
88
|
# <tt>:margin_left</tt>:: The size of the default left margin (default 5% of page)
|
89
89
|
# <tt>:margin_right</tt>:: The size of the default right margin (default 5% of page)
|
90
|
+
# <tt>:template</tt>:: The path to an image file. If specified, the first page of the document will use the specified image as a template.
|
91
|
+
# The page will be sized to match the template size. The use templates on subsequent pages, see the options for
|
92
|
+
# start_new_page.
|
90
93
|
def initialize(opts={})
|
91
94
|
|
92
95
|
# ensure we have recentish cairo bindings
|
@@ -99,7 +102,7 @@ module PDF
|
|
99
102
|
options.merge!(opts)
|
100
103
|
|
101
104
|
# test for invalid options
|
102
|
-
options.assert_valid_keys(:paper, :orientation, :background_color, :margin_left, :margin_right, :margin_top, :margin_bottom)
|
105
|
+
options.assert_valid_keys(:paper, :orientation, :background_color, :margin_left, :margin_right, :margin_top, :margin_bottom, :template)
|
103
106
|
options[:paper] = options[:paper].to_sym
|
104
107
|
raise ArgumentError, "Invalid paper option" unless PAGE_SIZES.include?(options[:paper])
|
105
108
|
|
@@ -139,6 +142,13 @@ module PDF
|
|
139
142
|
@page = 1
|
140
143
|
@repeating = []
|
141
144
|
|
145
|
+
# build the first page from a template if required
|
146
|
+
if opts[:template]
|
147
|
+
w, h = image_dimensions(opts[:template])
|
148
|
+
@surface.set_size(w, h)
|
149
|
+
image(opts[:template], :left => 0, :top => 0)
|
150
|
+
end
|
151
|
+
|
142
152
|
# move the cursor to the top left of the usable canvas
|
143
153
|
reset_cursor
|
144
154
|
end
|
@@ -503,8 +513,8 @@ module PDF
|
|
503
513
|
move_to(origx, origy)
|
504
514
|
end
|
505
515
|
|
506
|
-
# Adds a cubic Bezier spline to the path from the (x0, y0) to position (x3, y3)
|
507
|
-
# in user-space coordinates, using (x1, y1) and (x2, y2) as the control points.
|
516
|
+
# Adds a cubic Bezier spline to the path from the (x0, y0) to position (x3, y3)
|
517
|
+
# in user-space coordinates, using (x1, y1) and (x2, y2) as the control points.
|
508
518
|
# Options:
|
509
519
|
# <tt>:color</tt>:: The colour of the line
|
510
520
|
# <tt>:line_width</tt>:: The width of line. Defaults to 2.0
|
@@ -522,7 +532,7 @@ module PDF
|
|
522
532
|
# restore the cursor position
|
523
533
|
move_to(origx, origy)
|
524
534
|
end
|
525
|
-
|
535
|
+
|
526
536
|
|
527
537
|
# draw a rectangle starting at x,y with w,h dimensions.
|
528
538
|
# Parameters:
|
@@ -614,17 +624,22 @@ module PDF
|
|
614
624
|
# <tt>:height</tt>:: The height of the image
|
615
625
|
# <tt>:width</tt>:: The width of the image
|
616
626
|
# <tt>:proportional</tt>:: Boolean. Maintain image proportions when scaling. Defaults to false.
|
627
|
+
# <tt>:padding</tt>:: Add some padding between the image and the specified box.
|
617
628
|
#
|
618
629
|
# left and top default to the current cursor location
|
619
630
|
# width and height default to the size of the imported image
|
631
|
+
# padding defaults to 0
|
620
632
|
def image(filename, opts = {})
|
621
633
|
# TODO: add some options for justification and padding
|
622
|
-
# TODO: add a seperate method for adding arbitary pages from a PDF file to this one. Good for
|
623
|
-
# templating, etc. Save a letterhead as a PDF file, then open it and add it to the page
|
624
|
-
# as a starting point. Until we call start_new_page, we can add stuff over the top of the
|
625
|
-
# imported content
|
626
634
|
raise ArgumentError, "file #{filename} not found" unless File.file?(filename)
|
627
|
-
opts.assert_valid_keys(default_positioning_options.keys + [:proportional])
|
635
|
+
opts.assert_valid_keys(default_positioning_options.keys + [:padding, :proportional])
|
636
|
+
|
637
|
+
if opts[:padding]
|
638
|
+
opts[:left] += opts[:padding].to_i if opts[:left]
|
639
|
+
opts[:top] += opts[:padding].to_i if opts[:top]
|
640
|
+
opts[:width] -= opts[:padding].to_i * 2 if opts[:width]
|
641
|
+
opts[:height] -= opts[:padding].to_i * 2 if opts[:height]
|
642
|
+
end
|
628
643
|
|
629
644
|
case detect_image_type(filename)
|
630
645
|
when :pdf then draw_pdf filename, opts
|
@@ -712,14 +727,25 @@ module PDF
|
|
712
727
|
|
713
728
|
# move to the next page
|
714
729
|
#
|
715
|
-
#
|
716
|
-
# <tt
|
717
|
-
|
730
|
+
# options:
|
731
|
+
# <tt>:pageno</tt>:: If specified, the current page number will be set to that. By default, the page number will just increment.
|
732
|
+
# <tt>:template</tt>:: The path to an image file. If specified, the new page will use the specified image as a template. The page will be sized to match the template size
|
733
|
+
def start_new_page(opts = {})
|
734
|
+
opts.assert_valid_keys(:pageno, :template)
|
735
|
+
|
718
736
|
@context.show_page
|
719
737
|
|
738
|
+
if opts[:template]
|
739
|
+
w, h = image_dimensions(opts[:template])
|
740
|
+
@surface.set_size(w, h)
|
741
|
+
image(opts[:template], :left => 0, :top => 0)
|
742
|
+
else
|
743
|
+
@surface.set_size(@page_width, @page_height)
|
744
|
+
end
|
745
|
+
|
720
746
|
# reset or increment the page counter
|
721
|
-
if pageno
|
722
|
-
@page = pageno.to_i
|
747
|
+
if opts[:pageno]
|
748
|
+
@page = opts[:pageno].to_i
|
723
749
|
else
|
724
750
|
@page += 1
|
725
751
|
end
|
@@ -977,6 +1003,32 @@ module PDF
|
|
977
1003
|
return y + row_height
|
978
1004
|
end
|
979
1005
|
|
1006
|
+
def image_dimensions(filename)
|
1007
|
+
raise ArgumentError, "file #{filename} not found" unless File.file?(filename)
|
1008
|
+
|
1009
|
+
case detect_image_type(filename)
|
1010
|
+
when :pdf then
|
1011
|
+
load_libpoppler
|
1012
|
+
page = Poppler::Document.new(filename).get_page(1)
|
1013
|
+
return page.size
|
1014
|
+
when :png then
|
1015
|
+
img_surface = Cairo::ImageSurface.from_png(filename)
|
1016
|
+
return img_surface.width, img_surface.height
|
1017
|
+
when :svg then
|
1018
|
+
load_librsvg
|
1019
|
+
handle = RSVG::Handle.new_from_file(filename)
|
1020
|
+
return handle.width, handle.height
|
1021
|
+
else
|
1022
|
+
load_libpixbuf
|
1023
|
+
begin
|
1024
|
+
pixbuf = Gdk::Pixbuf.new(filename)
|
1025
|
+
return pixbuf.width, pixbuf.height
|
1026
|
+
rescue Gdk::PixbufError
|
1027
|
+
raise ArgumentError, "Unrecognised image format (#{filename})"
|
1028
|
+
end
|
1029
|
+
end
|
1030
|
+
end
|
1031
|
+
|
980
1032
|
# load libpango if it isn't already loaded.
|
981
1033
|
# This will add some methods to the cairo Context class in addition to providing
|
982
1034
|
# its own classes and constants. A small amount of documentation is available at
|
@@ -1038,9 +1090,9 @@ module PDF
|
|
1038
1090
|
|
1039
1091
|
offset = 0
|
1040
1092
|
baseline = 0
|
1041
|
-
|
1093
|
+
|
1042
1094
|
iter = layout.iter
|
1043
|
-
loop do
|
1095
|
+
loop do
|
1044
1096
|
line = iter.line
|
1045
1097
|
ink_rect, logical_rect = iter.line_extents
|
1046
1098
|
if y + (baseline - offset) >= (y + h)
|
@@ -1065,7 +1117,7 @@ module PDF
|
|
1065
1117
|
@context.show_pango_layout_line(line)
|
1066
1118
|
|
1067
1119
|
break unless iter.next_line!
|
1068
|
-
end
|
1120
|
+
end
|
1069
1121
|
|
1070
1122
|
# return the y co-ord we finished on
|
1071
1123
|
return y + baseline - offset
|
data/specs/image_spec.rb
CHANGED
@@ -12,11 +12,22 @@ context "The PDF::Wrapper class" do
|
|
12
12
|
pdf.detect_image_type(File.dirname(__FILE__) + "/data/shipsail.jpg").should eql(:jpg)
|
13
13
|
end
|
14
14
|
|
15
|
-
specify "should be able to
|
15
|
+
specify "should be able to determine image dimensions correctly" do
|
16
|
+
pdf = PDF::Wrapper.new
|
17
|
+
pdf.image_dimensions(File.dirname(__FILE__) + "/data/google.png").should eql([166,55])
|
18
|
+
pdf.image_dimensions(File.dirname(__FILE__) + "/data/zits.gif").should eql([525,167])
|
19
|
+
pdf.image_dimensions(File.dirname(__FILE__) + "/data/orc.svg").should eql([734, 772])
|
20
|
+
pdf.image_dimensions(File.dirname(__FILE__) + "/data/utf8-long.pdf").map{ |d| d.to_i}.should eql([595,841])
|
21
|
+
pdf.image_dimensions(File.dirname(__FILE__) + "/data/shipsail.jpg").should eql([192,128])
|
22
|
+
end
|
23
|
+
|
24
|
+
specify "should be able to calculate scaled image dimensions correctly" do
|
16
25
|
pdf = PDF::Wrapper.new
|
17
26
|
pdf.calc_image_dimensions(100, 100, 200, 200).should eql([100.0,100.0])
|
18
27
|
pdf.calc_image_dimensions(nil, nil, 200, 200).should eql([200.0,200.0])
|
19
28
|
pdf.calc_image_dimensions(150, 200, 200, 200, true).should eql([150.0,150.0])
|
20
29
|
pdf.calc_image_dimensions(300, 250, 200, 200, true).should eql([250.0,250.0])
|
21
30
|
end
|
31
|
+
|
32
|
+
specify "should be able to draw an image with padding correctly"
|
22
33
|
end
|
data/specs/spec_helper.rb
CHANGED
@@ -14,20 +14,21 @@ require 'pdf/reader'
|
|
14
14
|
class PDF::Wrapper
|
15
15
|
public :build_pango_layout
|
16
16
|
public :calc_image_dimensions
|
17
|
-
public :load_librsvg
|
18
|
-
public :load_libpixbuf
|
19
|
-
public :load_libpango
|
20
|
-
public :load_libpoppler
|
21
17
|
public :default_text_options
|
22
18
|
public :detect_image_type
|
23
19
|
public :draw_pdf
|
24
20
|
public :draw_pixbuf
|
25
21
|
public :draw_png
|
26
22
|
public :draw_svg
|
23
|
+
public :image_dimensions
|
24
|
+
public :load_librsvg
|
25
|
+
public :load_libpixbuf
|
26
|
+
public :load_libpango
|
27
|
+
public :load_libpoppler
|
27
28
|
public :validate_color
|
28
29
|
end
|
29
30
|
|
30
|
-
# a helper class for
|
31
|
+
# a helper class for counting the number of pages in a PDF
|
31
32
|
class PageReceiver
|
32
33
|
attr_accessor :page_count
|
33
34
|
|
@@ -41,6 +42,20 @@ class PageReceiver
|
|
41
42
|
end
|
42
43
|
end
|
43
44
|
|
45
|
+
# a helper class for recording the dimensions of pages in a PDF
|
46
|
+
class PageSizeReceiver
|
47
|
+
attr_accessor :pages
|
48
|
+
|
49
|
+
def initialize
|
50
|
+
@pages = []
|
51
|
+
end
|
52
|
+
|
53
|
+
# Called when page parsing ends
|
54
|
+
def begin_page(args)
|
55
|
+
pages << args["MediaBox"] || args[:MediaBox]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
44
59
|
class PageTextReceiver
|
45
60
|
attr_accessor :content
|
46
61
|
|
data/specs/wrapper_spec.rb
CHANGED
@@ -399,7 +399,7 @@ context "The PDF::Wrapper class" do
|
|
399
399
|
pdf.page.should eql(1)
|
400
400
|
pdf.start_new_page
|
401
401
|
pdf.page.should eql(2)
|
402
|
-
pdf.start_new_page(50)
|
402
|
+
pdf.start_new_page(:pageno => 50)
|
403
403
|
pdf.page.should eql(50)
|
404
404
|
end
|
405
405
|
|
@@ -414,7 +414,30 @@ context "The PDF::Wrapper class" do
|
|
414
414
|
lambda { pdf.circle(100,100,100, :ponies => true)}.should raise_error(ArgumentError)
|
415
415
|
lambda { pdf.line(100,100,200,200, :ponies => true)}.should raise_error(ArgumentError)
|
416
416
|
lambda { pdf.rectangle(100,100,100,100, :ponies => true)}.should raise_error(ArgumentError)
|
417
|
+
lambda { pdf.start_new_page(:ponies => true)}.should raise_error(ArgumentError)
|
417
418
|
lambda { pdf.rounded_rectangle(100,100,100,100,10, :ponies => true)}.should raise_error(ArgumentError)
|
418
419
|
lambda { pdf.image(File.dirname(__FILE__) + "/data/orc.svg", :ponies => true)}.should raise_error(ArgumentError)
|
419
420
|
end
|
421
|
+
|
422
|
+
specify "should allow an existing file to be used as a template for page 1" do
|
423
|
+
pdf = PDF::Wrapper.new(:paper => :A4, :template => File.dirname(__FILE__) + "/data/orc.svg")
|
424
|
+
pdf.start_new_page
|
425
|
+
|
426
|
+
receiver = PageSizeReceiver.new
|
427
|
+
reader = PDF::Reader.string(pdf.render, receiver)
|
428
|
+
|
429
|
+
receiver.pages[0].should eql([0.0, 0.0, 734.0, 772.0])
|
430
|
+
receiver.pages[1].should eql([0.0, 0.0, 595.28, 841.89])
|
431
|
+
end
|
432
|
+
|
433
|
+
specify "should allow an existing file to be used as a template for page 2" do
|
434
|
+
pdf = PDF::Wrapper.new(:paper => :A4)
|
435
|
+
pdf.start_new_page(:template => File.dirname(__FILE__) + "/data/orc.svg")
|
436
|
+
|
437
|
+
receiver = PageSizeReceiver.new
|
438
|
+
reader = PDF::Reader.string(pdf.render, receiver)
|
439
|
+
|
440
|
+
receiver.pages[0].should eql([0.0, 0.0, 595.28, 841.89])
|
441
|
+
receiver.pages[1].should eql([0.0, 0.0, 734.0, 772.0])
|
442
|
+
end
|
420
443
|
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.7
|
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-04-
|
12
|
+
date: 2008-04-30 00:00:00 +10:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -31,6 +31,8 @@ files:
|
|
31
31
|
- examples/table.rb
|
32
32
|
- examples/utf8-long.rb
|
33
33
|
- examples/utf8.rb
|
34
|
+
- examples/template.rb
|
35
|
+
- examples/padded_image.rb
|
34
36
|
- lib/pdf
|
35
37
|
- lib/pdf/core.rb
|
36
38
|
- lib/pdf/wrapper.rb
|