pdf_gen 0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +19 -0
- data/README.rdoc +189 -0
- data/lib/base_region.rb +95 -0
- data/lib/caption.rb +78 -0
- data/lib/containers/caption_container.rb +15 -0
- data/lib/containers/div_container.rb +14 -0
- data/lib/containers/image_container.rb +15 -0
- data/lib/containers/span_container.rb +14 -0
- data/lib/containers/table_container.rb +14 -0
- data/lib/data/ds_ar.rb +31 -0
- data/lib/data/ds_base.rb +24 -0
- data/lib/data/ds_hash.rb +24 -0
- data/lib/div.rb +148 -0
- data/lib/document.rb +50 -0
- data/lib/fixnum.rb +18 -0
- data/lib/float.rb +18 -0
- data/lib/image.rb +46 -0
- data/lib/modules/base_attributes.rb +86 -0
- data/lib/modules/canvas.rb +15 -0
- data/lib/modules/composite.rb +54 -0
- data/lib/pdf_gen.rb +30 -0
- data/lib/smart_table.rb +155 -0
- data/lib/span.rb +69 -0
- data/lib/table.rb +116 -0
- data/lib/writer.rb +30 -0
- data/samples/border.rb +15 -0
- data/samples/div.rb +23 -0
- data/samples/div_illustration.rb +64 -0
- data/samples/headerfooter.rb +94 -0
- data/samples/image.rb +9 -0
- data/samples/ruby_logo.jpg +0 -0
- data/samples/sampl1_1.png +0 -0
- data/samples/sampl1_2.png +0 -0
- data/samples/sampl1_3.png +0 -0
- data/samples/simple.rb +7 -0
- data/samples/smart_table.rb +98 -0
- data/samples/span.rb +12 -0
- data/samples/span_illustration.rb +41 -0
- data/samples/spanindiv_ill.rb +53 -0
- data/samples/table.rb +37 -0
- data/samples/table_illustration.rb +177 -0
- data/samples/tableindiv_ill.rb +99 -0
- data/test/caption_test.rb +99 -0
- data/test/container_test.rb +29 -0
- data/test/div_test.rb +39 -0
- data/test/helpers_for_testing.rb +19 -0
- data/test/image_test.rb +54 -0
- data/test/shared_examples.rb +68 -0
- data/test/span_test.rb +83 -0
- data/test/table_test.rb +27 -0
- metadata +139 -0
data/LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2010, Sphere Consutling Inc.
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,189 @@
|
|
1
|
+
== Pdf_gen
|
2
|
+
pdf_gen is a high-level wrapper around {PDF::Writer}[https://github.com/sandal/pdf-writer] library which allows to create PDF documents in an easy way with a layout similar to HTML.
|
3
|
+
|
4
|
+
== Install
|
5
|
+
gem install pdf_gen
|
6
|
+
|
7
|
+
== Usage
|
8
|
+
All package entities are located within the PDFGen module.
|
9
|
+
PDF file generation can be made in the following way:
|
10
|
+
|
11
|
+
require "pdf_gen"
|
12
|
+
|
13
|
+
PDFGen::document PDF::Writer.new, 0.cm do
|
14
|
+
# pdf generation code here
|
15
|
+
end.save("#{File.basename(__FILE__, ".rb")}.pdf")
|
16
|
+
|
17
|
+
== Construction Elements
|
18
|
+
|
19
|
+
=== Caption
|
20
|
+
An object which allows to represent some parts of the text in PDF file. This object has such properties as width, justification, pad_top (indent from the left side of the page), pad_bottom, pad_left, pad_right, text_color, font_size and border.
|
21
|
+
The Border, in its turn, can be characterized by border_color, border_style (solid or dotted) and border_width (in cm or pixels).
|
22
|
+
Support Properties:
|
23
|
+
pad_top - integer
|
24
|
+
pad_bottom - integer
|
25
|
+
pad_left - integer
|
26
|
+
pad_right - integer
|
27
|
+
paddings - integer
|
28
|
+
border - true|false
|
29
|
+
border_top - true|false
|
30
|
+
border_bottom - true|false
|
31
|
+
border_left - true|false
|
32
|
+
border_right - true|false
|
33
|
+
border_style - :solid | :dotted
|
34
|
+
border_widht - integer
|
35
|
+
border_color - object of color-tools*. Color::RGB::Red|Color::RGB.from_html("#ccc")| other
|
36
|
+
background_color - object of color-tools*. Color::RGB::Red|Color::RGB.from_html("#ccc")| other
|
37
|
+
width - integer
|
38
|
+
height - integer
|
39
|
+
|
40
|
+
*color-tools http://ruby-pdf.rubyforge.org/color-tools/
|
41
|
+
|
42
|
+
=== Image
|
43
|
+
An object which allows to add images with filename extensions *.jpg and *.png in PDF file. This object has such properties as width, pad_top, pad_bottom, pad_left, pad_right and border.
|
44
|
+
|
45
|
+
require "pdf_gen"
|
46
|
+
|
47
|
+
PDFGen::document PDF::Writer.new, 2.cm do
|
48
|
+
image_data = open(File.expand_path('ruby_logo.jpg'), "rb") { |file| file.read }
|
49
|
+
image image_data, :width => 250
|
50
|
+
end.save("#{File.basename(__FILE__, ".rb")}.pdf")
|
51
|
+
|
52
|
+
Support Properties:
|
53
|
+
*the same as caption`s properties
|
54
|
+
|
55
|
+
=== Span
|
56
|
+
An object which allows setting several objects across the page. This object has such properties as width, pad_top, pad_bottom, pad_left, pad_right, border and background_color.
|
57
|
+
|
58
|
+
PDFGen::document PDF::Writer.new, 2.cm do
|
59
|
+
span :width => 10.cm, :pad_left => 2.cm do
|
60
|
+
caption ' first '*50, :width => 4.cm
|
61
|
+
caption ' second '*50, :width => 4.cm
|
62
|
+
elements :border => true #group set params
|
63
|
+
end
|
64
|
+
end.save("#{File.basename(__FILE__, ".rb")}.pdf")
|
65
|
+
|
66
|
+
Support Properties:
|
67
|
+
*the same as caption`s properties
|
68
|
+
vertical_interval - integer
|
69
|
+
vartical_align - true | false
|
70
|
+
|
71
|
+
=== Div
|
72
|
+
An object which allows setting several elements in the vertical format. This object has such properties as width, horizontal_interval, pad_top, pad_bottom, pad_left, pad_right, border and background_color.
|
73
|
+
|
74
|
+
PDFGen::document PDF::Writer.new, 2.cm do
|
75
|
+
div :width => 10.cm do
|
76
|
+
caption ' first '*50, :width => 4.cm
|
77
|
+
caption ' second '*50, :width => 4.cm
|
78
|
+
elements :border => true #group set params
|
79
|
+
end
|
80
|
+
end.save("#{File.basename(__FILE__, ".rb")}.pdf")
|
81
|
+
|
82
|
+
Support Properties:
|
83
|
+
*the same as caption`s properties
|
84
|
+
horizontal_interval - integer
|
85
|
+
horizontal_align - true | false
|
86
|
+
|
87
|
+
=== Table
|
88
|
+
An object which allows creating tables in PDF file. This object has such elements as title, header, body and footer. The columns can be made be adding “spans” inside the body of the table. The table can have borders from specific sides, for example: “:border_right => true” or “:border_right => false”.
|
89
|
+
|
90
|
+
require "pdf_gen"
|
91
|
+
|
92
|
+
PDFGen::document PDF::Writer.new, 0.cm do
|
93
|
+
table do
|
94
|
+
title do
|
95
|
+
caption "Transactions and Triggers",
|
96
|
+
:text_color => Color::RGB::Red, :border => true, :justification => :center, :pad_bottom => 0.25.cm
|
97
|
+
end
|
98
|
+
header do
|
99
|
+
span do
|
100
|
+
caption "Number",
|
101
|
+
:width => av_width / 2, :justification => :center, :border => true
|
102
|
+
caption "Discription",
|
103
|
+
:width => av_width / 2, :justification => :center, :border => true
|
104
|
+
end
|
105
|
+
end
|
106
|
+
body do
|
107
|
+
span do
|
108
|
+
caption " Trigger ", :width => av_width / 2,
|
109
|
+
:border_right => true, :border_left => true, :text_color => Color::RGB::Grey
|
110
|
+
caption " - is a ... ", :width => av_width / 2,
|
111
|
+
:border_right => true, :border_left => true, :text_color => Color::RGB::Grey
|
112
|
+
end
|
113
|
+
end
|
114
|
+
footer do
|
115
|
+
span do
|
116
|
+
caption "1", :width => av_width / 2, :justification => :center, :border => true
|
117
|
+
caption "2", :width => av_width / 2, :justification => :center, :border => true
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end.save("#{File.basename(__FILE__, ".rb")}.pdf")
|
122
|
+
|
123
|
+
=== Smart Table
|
124
|
+
An object which allows creating tables from Hash and ActiveRecord. If necessary, you can define the blocks of the title and footer independently.
|
125
|
+
For example:
|
126
|
+
|
127
|
+
table_data = {:columns =>['id','name','email'],
|
128
|
+
:body => [[1,'Valeriy','valeriy@example.com'],
|
129
|
+
[2,'Dmitriy','dmitriy@example.com']]}
|
130
|
+
PDFGen::document PDF::Writer.new, 0.cm do
|
131
|
+
div :paddings => 2 do
|
132
|
+
table :data_source => table_data
|
133
|
+
end
|
134
|
+
end.save("#{File.basename(__FILE__, ".rb")}.pdf")
|
135
|
+
|
136
|
+
Building a table from ActiveRecord (ROR)
|
137
|
+
|
138
|
+
table_data = User.all
|
139
|
+
PDFGen::document PDF::Writer.new, 0.cm do
|
140
|
+
div :paddings => 2 do
|
141
|
+
table :data_source => table_data
|
142
|
+
end
|
143
|
+
end.save("#{File.basename(__FILE__, ".rb")}.pdf")
|
144
|
+
|
145
|
+
Custom view
|
146
|
+
|
147
|
+
table_data = {:columns =>['id','name','email'],
|
148
|
+
:body => [[1,'Valeriy','valeriy@example.com'],
|
149
|
+
[2,'Dmitriy','dmitriy@example.com']]}
|
150
|
+
PDFGen::document PDF::Writer.new, 0.cm do
|
151
|
+
div :paddings => 2 do
|
152
|
+
table :data_source => table_data do
|
153
|
+
header do
|
154
|
+
row do
|
155
|
+
cell "<b>#{ds.columns[0]}</b>", :justification => :center, :text_color => Color::RGB::Green
|
156
|
+
cell ds.columns[1], :justification => :center, :text_color => Color::RGB::Green
|
157
|
+
cell ds.columns[2], :justification => :center, :text_color => Color::RGB::Green
|
158
|
+
end
|
159
|
+
end
|
160
|
+
body do
|
161
|
+
ds.each do |datarow|
|
162
|
+
row do
|
163
|
+
cell datarow[0]
|
164
|
+
cell "<i>#{datarow[1]}</i>"
|
165
|
+
cell datarow[2]
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end.save("#{File.basename(__FILE__, ".rb")}.pdf")
|
172
|
+
|
173
|
+
We can set the width of each column
|
174
|
+
|
175
|
+
row do
|
176
|
+
cell data[0], :width => av_width * 2/4
|
177
|
+
cell data[1], :width => av_width * 1/4
|
178
|
+
cell data[2], :width => av_width * 1/4
|
179
|
+
end
|
180
|
+
|
181
|
+
|
182
|
+
== Credits
|
183
|
+
|
184
|
+
=== Team's line-up
|
185
|
+
* Mykhaylo Sorochan, Valeriy Prokopchuk - Project Managers
|
186
|
+
* Valeriy Sizov, Dmitriy Landberg - Software Developers
|
187
|
+
* Nataliya Shatokhina - Tester
|
188
|
+
|
189
|
+
Copyright (c) 2010 {Sphere Consulting Inc.}[http://www.sphereinc.com], released under the MIT license (see LICENSE).
|
data/lib/base_region.rb
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
require "lib/modules/base_attributes"
|
2
|
+
|
3
|
+
module PDFGen
|
4
|
+
|
5
|
+
class BaseRegion
|
6
|
+
include BaseAttributes
|
7
|
+
|
8
|
+
def initialize(parent)
|
9
|
+
self.var_init
|
10
|
+
@parent = parent
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_reader :parent
|
14
|
+
|
15
|
+
#gets region's document
|
16
|
+
def document
|
17
|
+
parent ? parent.document : self
|
18
|
+
end
|
19
|
+
|
20
|
+
#gets minimal height that current caption can be written to
|
21
|
+
def minimal_height
|
22
|
+
@minimal_height ||= calculate_minimal_height
|
23
|
+
end
|
24
|
+
|
25
|
+
def clear_minimal_height
|
26
|
+
@minimal_height = nil
|
27
|
+
end
|
28
|
+
|
29
|
+
protected :clear_minimal_height
|
30
|
+
|
31
|
+
def calculate_minimal_height
|
32
|
+
0
|
33
|
+
end
|
34
|
+
|
35
|
+
protected :calculate_minimal_height
|
36
|
+
|
37
|
+
def add_border(pos)
|
38
|
+
x,y = pos
|
39
|
+
if border_top || border_bottom || border_left || border_right
|
40
|
+
document.pdf.save_state
|
41
|
+
|
42
|
+
document.pdf.stroke_color! border_color
|
43
|
+
document.pdf.stroke_style! border_params
|
44
|
+
|
45
|
+
document.pdf.line(x, y, x, y - height).stroke if border_left
|
46
|
+
document.pdf.line(x + width, y, x + width, y - height).stroke if border_right
|
47
|
+
document.pdf.line(x, y, x + width, y).stroke if border_top
|
48
|
+
document.pdf.line(x, y - height, x + width, y - height).stroke if border_bottom
|
49
|
+
|
50
|
+
document.pdf.restore_state
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
private :add_border
|
55
|
+
|
56
|
+
#fills caption area with background color
|
57
|
+
def fill(pos)
|
58
|
+
unless background_color.nil?
|
59
|
+
document.pdf.save_state
|
60
|
+
|
61
|
+
document.pdf.stroke_color! background_color
|
62
|
+
document.pdf.stroke_style! PDF::Writer::StrokeStyle::SOLID
|
63
|
+
document.pdf.fill_color! background_color
|
64
|
+
document.pdf.rectangle(pos[0], pos[1] - height, width, height).fill.stroke
|
65
|
+
|
66
|
+
document.pdf.restore_state
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
private :fill
|
71
|
+
|
72
|
+
def render(pos,av_height, test=false)
|
73
|
+
fill(pos) unless test
|
74
|
+
add_border(pos) unless test
|
75
|
+
[pos,true]
|
76
|
+
end
|
77
|
+
|
78
|
+
def check_fit_in_height
|
79
|
+
if (self.height >= document.pdf.page_height-document.page_pad_top)
|
80
|
+
raise "region`s height is bigger then parent region`s height"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def value val
|
85
|
+
"<!#{val.to_s}!>"
|
86
|
+
end
|
87
|
+
|
88
|
+
#sets region properties specified as array
|
89
|
+
def set_properties(props = {})
|
90
|
+
props.each_pair {|name, value| self.send("#{name}=", value)}
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
data/lib/caption.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
require "lib/base_region"
|
2
|
+
|
3
|
+
|
4
|
+
module PDFGen
|
5
|
+
|
6
|
+
class Caption < BaseRegion
|
7
|
+
|
8
|
+
def initialize(parent)
|
9
|
+
super
|
10
|
+
|
11
|
+
@text = ""
|
12
|
+
@template = @text
|
13
|
+
@justification = :left
|
14
|
+
@bold = false
|
15
|
+
@font_size = document.pdf.font_size
|
16
|
+
self.paddings = 0.2.cm
|
17
|
+
end
|
18
|
+
|
19
|
+
attr_reader :text
|
20
|
+
|
21
|
+
def text=(value)
|
22
|
+
value = value.to_s unless value.is_a?(String)
|
23
|
+
if value && @text != value
|
24
|
+
@text = value
|
25
|
+
@template = value
|
26
|
+
clear_minimal_height
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
attr_reader :text_color, :justification, :bold, :font_size
|
31
|
+
|
32
|
+
common_setter :text_color, :justification, :bold, :font_size
|
33
|
+
|
34
|
+
def calculate_minimal_height
|
35
|
+
add_text_wrap
|
36
|
+
end
|
37
|
+
|
38
|
+
#writes text. return actual text height
|
39
|
+
def add_text_wrap(pos=[], test = true)
|
40
|
+
x = pos[0] || 0
|
41
|
+
y = pos[1] || document.pdf.y
|
42
|
+
|
43
|
+
res = document.pdf.font_height + pad_top
|
44
|
+
txt = bold ? "<b>#{text}</b>" : text
|
45
|
+
|
46
|
+
document.pdf.save_state
|
47
|
+
document.pdf.fill_color text_color if text_color
|
48
|
+
document.pdf.stroke_color! text_color if text_color
|
49
|
+
until (txt_remain = document.pdf.add_text_wrap(x + pad_left, y - res, width - pad_left - pad_right, txt, font_size,
|
50
|
+
justification, 0, test)).empty?
|
51
|
+
txt_remain == txt ? raise("text very long for this caption") : txt = txt_remain
|
52
|
+
res += document.pdf.font_height(font_size)
|
53
|
+
end
|
54
|
+
document.pdf.restore_state
|
55
|
+
|
56
|
+
res + pad_bottom
|
57
|
+
end
|
58
|
+
|
59
|
+
private :add_text_wrap
|
60
|
+
|
61
|
+
#renders specified text at the specified position
|
62
|
+
#returns real position that caption was generated on
|
63
|
+
def render(pos, av_height, test=false)
|
64
|
+
self.check_fit_in_height
|
65
|
+
if av_height >= self.height
|
66
|
+
super
|
67
|
+
add_text_wrap(pos,test)
|
68
|
+
used_height = [add_text_wrap(pos),self.height].max
|
69
|
+
[used_height, true]
|
70
|
+
else
|
71
|
+
[0, false]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module PDFGen
|
2
|
+
|
3
|
+
module CaptionContainer
|
4
|
+
|
5
|
+
def caption(text = nil, style = nil)
|
6
|
+
caption = Caption.new self
|
7
|
+
caption.text = text if text
|
8
|
+
caption.width = self.width - self.pad_left - self.pad_right
|
9
|
+
caption.set_properties style unless style.nil?
|
10
|
+
self.add_region(caption)
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module PDFGen
|
2
|
+
|
3
|
+
module DivContainer
|
4
|
+
|
5
|
+
def div(style = nil, &initialization_block)
|
6
|
+
div = Div.new(self)
|
7
|
+
div.width = self.width - self.pad_left - self.pad_right
|
8
|
+
div.set_properties style unless style.nil?
|
9
|
+
div.instance_eval(&initialization_block) if initialization_block
|
10
|
+
self.add_region(div)
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module PDFGen
|
2
|
+
|
3
|
+
module SpanContainer
|
4
|
+
|
5
|
+
def span(style = nil, &initialization_block)
|
6
|
+
span = Span.new self
|
7
|
+
span.width = self.width - self.pad_left - self.pad_right
|
8
|
+
span.set_properties style unless style.nil?
|
9
|
+
span.instance_eval(&initialization_block) if initialization_block
|
10
|
+
self.add_region(span)
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module PDFGen
|
2
|
+
|
3
|
+
module TableContainer
|
4
|
+
|
5
|
+
def table(style = nil, &initialization_block)
|
6
|
+
table = (style.is_a?(Hash) and style.has_key?(:data_source)) ?
|
7
|
+
SmartTable.new(self) : Table.new(self)
|
8
|
+
table.set_properties style unless style.nil?
|
9
|
+
table.instance_eval(&initialization_block) if initialization_block
|
10
|
+
self.add_region(table)
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
data/lib/data/ds_ar.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require "lib/data/ds_base"
|
2
|
+
|
3
|
+
module PDFGen
|
4
|
+
|
5
|
+
class DsActiveRecord < DsBase
|
6
|
+
def initialize(data)
|
7
|
+
@data = data
|
8
|
+
end
|
9
|
+
|
10
|
+
def columns
|
11
|
+
@data.first.class.columns.map(&:name)
|
12
|
+
end
|
13
|
+
|
14
|
+
def body
|
15
|
+
@fields = []
|
16
|
+
@data.each do |row|
|
17
|
+
@mas = []
|
18
|
+
columns.each do |title|
|
19
|
+
@mas << row.send(title)
|
20
|
+
end
|
21
|
+
@fields << @mas
|
22
|
+
end
|
23
|
+
@fields
|
24
|
+
end
|
25
|
+
|
26
|
+
def each
|
27
|
+
self.body.each {|item| yield item}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
data/lib/data/ds_base.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
module PDFGen
|
2
|
+
|
3
|
+
class DsBase
|
4
|
+
|
5
|
+
include Enumerable
|
6
|
+
|
7
|
+
def initialize(data)
|
8
|
+
raise "Not Implemented"
|
9
|
+
end
|
10
|
+
|
11
|
+
def columns
|
12
|
+
raise "Not Implemented"
|
13
|
+
end
|
14
|
+
|
15
|
+
def body
|
16
|
+
raise "Not Implemented"
|
17
|
+
end
|
18
|
+
|
19
|
+
def each
|
20
|
+
raise "Not Implemented"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
data/lib/data/ds_hash.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require "lib/data/ds_base"
|
2
|
+
|
3
|
+
|
4
|
+
module PDFGen
|
5
|
+
|
6
|
+
class DsHash < DsBase
|
7
|
+
def initialize(data)
|
8
|
+
@data = data
|
9
|
+
end
|
10
|
+
|
11
|
+
def columns
|
12
|
+
@data[:columns]
|
13
|
+
end
|
14
|
+
|
15
|
+
def body
|
16
|
+
@data[:body]
|
17
|
+
end
|
18
|
+
|
19
|
+
def each
|
20
|
+
self.body.each {|item| yield item}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
data/lib/div.rb
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
require "lib/base_region"
|
2
|
+
require "lib/modules/composite"
|
3
|
+
require "lib/containers/div_container"
|
4
|
+
require "lib/containers/span_container"
|
5
|
+
require "lib/containers/caption_container"
|
6
|
+
require "lib/containers/image_container"
|
7
|
+
require "lib/containers/table_container"
|
8
|
+
|
9
|
+
|
10
|
+
module PDFGen
|
11
|
+
|
12
|
+
class Div < BaseRegion
|
13
|
+
|
14
|
+
include Composite, CaptionContainer, SpanContainer, DivContainer,
|
15
|
+
ImageContainer, TableContainer
|
16
|
+
|
17
|
+
def initialize parent
|
18
|
+
super
|
19
|
+
|
20
|
+
@horizontal_interval = 0
|
21
|
+
@horizontal_align = false
|
22
|
+
@optional_border = false
|
23
|
+
@is_breakable = true
|
24
|
+
@count_rendered_region = 0
|
25
|
+
@rendered_height = 0
|
26
|
+
end
|
27
|
+
|
28
|
+
attr_accessor :horizontal_interval, :horizontal_align, :optional_border
|
29
|
+
attr_accessor :count_rendered_region
|
30
|
+
|
31
|
+
def add_border_top(x, y)
|
32
|
+
add_border(x, y, x + width, y) if border_top
|
33
|
+
end
|
34
|
+
|
35
|
+
def add_border_bottom(x, y)
|
36
|
+
add_border(x, y, x + width, y) if border_bottom
|
37
|
+
end
|
38
|
+
|
39
|
+
#border left and right
|
40
|
+
def add_border_sides(x, y, y_new)
|
41
|
+
add_border(x, y, x, y_new) if border_left
|
42
|
+
add_border(x + width, y, x + width, y_new) if border_right
|
43
|
+
end
|
44
|
+
|
45
|
+
def add_border(x, y, x1, y1)
|
46
|
+
document.pdf.save_state
|
47
|
+
document.pdf.stroke_color! border_color
|
48
|
+
document.pdf.stroke_style! border_params
|
49
|
+
document.pdf.line(x, y, x1, y1).stroke
|
50
|
+
document.pdf.restore_state
|
51
|
+
end
|
52
|
+
|
53
|
+
def add_optional_border(x, y)
|
54
|
+
add_border(x, y, x + width, y)
|
55
|
+
end
|
56
|
+
|
57
|
+
def calculate_minimal_height
|
58
|
+
height = 0
|
59
|
+
regions.each do |region|
|
60
|
+
height += region.height
|
61
|
+
height += horizontal_interval unless region == regions.last
|
62
|
+
end
|
63
|
+
height + pad_top + pad_bottom
|
64
|
+
end
|
65
|
+
|
66
|
+
def render_regions(pos, av_height, test=false)
|
67
|
+
pos_x, pos_y = pos
|
68
|
+
remain_regions = regions.slice(@count_rendered_region..regions.size)
|
69
|
+
if @count_rendered_region.zero? && @rendered_height.zero?
|
70
|
+
@rendered_height += pad_top
|
71
|
+
pos_y -= pad_top
|
72
|
+
end
|
73
|
+
pos_x += pad_left
|
74
|
+
|
75
|
+
remain_regions.each do |region|
|
76
|
+
self.fit_width(region)
|
77
|
+
if pos_y >= region.height
|
78
|
+
@count_rendered_region += 1 unless test
|
79
|
+
|
80
|
+
region_height = region.render([pos_x, pos_y], pos_y, test)[0]
|
81
|
+
|
82
|
+
@rendered_height += region_height
|
83
|
+
pos_y -= region_height
|
84
|
+
|
85
|
+
@rendered_height += horizontal_interval unless region == regions.last
|
86
|
+
pos_y -= horizontal_interval unless region == regions.last
|
87
|
+
|
88
|
+
if region == regions.last
|
89
|
+
pos_y -= pad_bottom
|
90
|
+
@rendered_height += pad_bottom
|
91
|
+
end
|
92
|
+
else
|
93
|
+
if region.breakable?
|
94
|
+
status = region.render([pos_x, pos_y], pos_y, test)
|
95
|
+
|
96
|
+
@rendered_height += status[0]
|
97
|
+
pos_y -= status[0]
|
98
|
+
|
99
|
+
@rendered_height += horizontal_interval unless region == regions.last
|
100
|
+
pos_y -= horizontal_interval unless region == regions.last
|
101
|
+
|
102
|
+
if region == regions.last and status[1]
|
103
|
+
pos_y -= pad_bottom
|
104
|
+
@rendered_height += pad_bottom
|
105
|
+
end
|
106
|
+
|
107
|
+
return [av_height - pos_y, status[1]]
|
108
|
+
else
|
109
|
+
region.check_fit_in_height
|
110
|
+
return [av_height - pos_y, false]
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
[av_height - pos_y, true]
|
116
|
+
end
|
117
|
+
|
118
|
+
def render(pos, av_height, test=false)
|
119
|
+
pos_x, pos_y = pos
|
120
|
+
fill(pos)
|
121
|
+
add_border_top(pos_x, pos_y) if @rendered_height.zero?
|
122
|
+
status = render_regions([pos_x, pos_y], av_height, test)
|
123
|
+
pos_y -= status[0]
|
124
|
+
|
125
|
+
if (status[1])
|
126
|
+
add_border_bottom(pos_x, pos_y)
|
127
|
+
add_border_sides(pos_x, av_height, pos_y)
|
128
|
+
else
|
129
|
+
add_border_sides(pos_x, av_height, 0)
|
130
|
+
end
|
131
|
+
|
132
|
+
status
|
133
|
+
end
|
134
|
+
|
135
|
+
def fit_width(region)
|
136
|
+
if (region.width > (width - pad_left - pad_right)) or horizontal_align
|
137
|
+
region.width = width - pad_left - pad_right
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
protected :fit_width
|
142
|
+
|
143
|
+
def reset_count_rendered_regions
|
144
|
+
@count_rendered_region = 0
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
end
|