thinreports 0.6.0.pre3
Sign up to get free protection for your applications and to get access to all the features.
- data/.yardopts +1 -0
- data/README.rdoc +100 -0
- data/Rakefile +10 -0
- data/doc/yardoc_templates/default/layout/html/footer.erb +10 -0
- data/lib/thinreports.rb +11 -0
- data/lib/thinreports/core.rb +20 -0
- data/lib/thinreports/core/errors.rb +58 -0
- data/lib/thinreports/core/events.rb +71 -0
- data/lib/thinreports/core/ext.rb +5 -0
- data/lib/thinreports/core/ext/array.rb +19 -0
- data/lib/thinreports/core/ext/hash.rb +19 -0
- data/lib/thinreports/core/ext/object.rb +25 -0
- data/lib/thinreports/core/format.rb +14 -0
- data/lib/thinreports/core/format/base.rb +93 -0
- data/lib/thinreports/core/format/builder.rb +65 -0
- data/lib/thinreports/core/ordered_hash.rb +39 -0
- data/lib/thinreports/core/page.rb +91 -0
- data/lib/thinreports/core/shape.rb +53 -0
- data/lib/thinreports/core/shape/base.rb +16 -0
- data/lib/thinreports/core/shape/base/interface.rb +38 -0
- data/lib/thinreports/core/shape/base/internal.rb +60 -0
- data/lib/thinreports/core/shape/basic.rb +15 -0
- data/lib/thinreports/core/shape/basic/format.rb +26 -0
- data/lib/thinreports/core/shape/basic/interface.rb +57 -0
- data/lib/thinreports/core/shape/basic/internal.rb +29 -0
- data/lib/thinreports/core/shape/list.rb +25 -0
- data/lib/thinreports/core/shape/list/configuration.rb +33 -0
- data/lib/thinreports/core/shape/list/events.rb +30 -0
- data/lib/thinreports/core/shape/list/format.rb +72 -0
- data/lib/thinreports/core/shape/list/manager.rb +209 -0
- data/lib/thinreports/core/shape/list/page.rb +118 -0
- data/lib/thinreports/core/shape/list/page_state.rb +40 -0
- data/lib/thinreports/core/shape/list/section_format.rb +32 -0
- data/lib/thinreports/core/shape/list/section_interface.rb +48 -0
- data/lib/thinreports/core/shape/list/section_internal.rb +29 -0
- data/lib/thinreports/core/shape/list/store.rb +34 -0
- data/lib/thinreports/core/shape/manager.rb +14 -0
- data/lib/thinreports/core/shape/manager/format.rb +28 -0
- data/lib/thinreports/core/shape/manager/internal.rb +87 -0
- data/lib/thinreports/core/shape/manager/target.rb +85 -0
- data/lib/thinreports/core/shape/tblock.rb +16 -0
- data/lib/thinreports/core/shape/tblock/format.rb +36 -0
- data/lib/thinreports/core/shape/tblock/formatter.rb +32 -0
- data/lib/thinreports/core/shape/tblock/formatter/basic.rb +38 -0
- data/lib/thinreports/core/shape/tblock/formatter/datetime.rb +21 -0
- data/lib/thinreports/core/shape/tblock/formatter/number.rb +49 -0
- data/lib/thinreports/core/shape/tblock/formatter/padding.rb +43 -0
- data/lib/thinreports/core/shape/tblock/interface.rb +52 -0
- data/lib/thinreports/core/shape/tblock/internal.rb +70 -0
- data/lib/thinreports/core/shape/text.rb +15 -0
- data/lib/thinreports/core/shape/text/format.rb +25 -0
- data/lib/thinreports/core/shape/text/interface.rb +16 -0
- data/lib/thinreports/core/shape/text/internal.rb +17 -0
- data/lib/thinreports/core/utils.rb +48 -0
- data/lib/thinreports/generator.rb +30 -0
- data/lib/thinreports/generator/base.rb +49 -0
- data/lib/thinreports/generator/pdf.rb +63 -0
- data/lib/thinreports/generator/pdf/document.rb +171 -0
- data/lib/thinreports/generator/pdf/document/draw_shape.rb +74 -0
- data/lib/thinreports/generator/pdf/document/font.rb +59 -0
- data/lib/thinreports/generator/pdf/document/graphics.rb +42 -0
- data/lib/thinreports/generator/pdf/document/graphics/attributes.rb +92 -0
- data/lib/thinreports/generator/pdf/document/graphics/basic.rb +132 -0
- data/lib/thinreports/generator/pdf/document/graphics/image.rb +51 -0
- data/lib/thinreports/generator/pdf/document/graphics/text.rb +130 -0
- data/lib/thinreports/generator/pdf/document/parse_color.rb +51 -0
- data/lib/thinreports/generator/pdf/document/parse_svg.rb +102 -0
- data/lib/thinreports/generator/pdf/drawer.rb +16 -0
- data/lib/thinreports/generator/pdf/drawer/base.rb +56 -0
- data/lib/thinreports/generator/pdf/drawer/list.rb +39 -0
- data/lib/thinreports/generator/pdf/drawer/list_section.rb +46 -0
- data/lib/thinreports/generator/pdf/drawer/page.rb +101 -0
- data/lib/thinreports/generator/pdf/prawn_ext.rb +36 -0
- data/lib/thinreports/generator/pxd.rb +75 -0
- data/lib/thinreports/generator/pxd/helper.rb +33 -0
- data/lib/thinreports/generator/pxd/list_renderer.rb +58 -0
- data/lib/thinreports/generator/pxd/page_renderer.rb +75 -0
- data/lib/thinreports/layout.rb +17 -0
- data/lib/thinreports/layout/base.rb +78 -0
- data/lib/thinreports/layout/configuration.rb +27 -0
- data/lib/thinreports/layout/format.rb +77 -0
- data/lib/thinreports/layout/version.rb +43 -0
- data/lib/thinreports/report.rb +31 -0
- data/lib/thinreports/report/base.rb +160 -0
- data/lib/thinreports/report/events.rb +32 -0
- data/lib/thinreports/report/internal.rb +131 -0
- data/resources/fonts/IPA_Font_License_Agreement_v1.0.txt +117 -0
- data/resources/fonts/ipag.ttf +0 -0
- data/resources/fonts/ipagp.ttf +0 -0
- data/resources/fonts/ipam.ttf +0 -0
- data/resources/fonts/ipamp.ttf +0 -0
- data/tasks/clean.rake +6 -0
- data/tasks/doc.rake +13 -0
- data/tasks/test.rake +18 -0
- data/test/unit/core/ext/array_spec.rb +29 -0
- data/test/unit/core/ext/hash_spec.rb +29 -0
- data/test/unit/core/ext/object_spec.rb +30 -0
- data/test/unit/core/format/test_base.rb +148 -0
- data/test/unit/core/format/test_builder.rb +114 -0
- data/test/unit/core/ordered_hash_spec.rb +51 -0
- data/test/unit/core/shape/base/test_interface.rb +52 -0
- data/test/unit/core/shape/base/test_internal.rb +109 -0
- data/test/unit/core/shape/basic/test_format.rb +59 -0
- data/test/unit/core/shape/basic/test_interface.rb +70 -0
- data/test/unit/core/shape/basic/test_internal.rb +42 -0
- data/test/unit/core/shape/list/test_configuration.rb +52 -0
- data/test/unit/core/shape/list/test_events.rb +28 -0
- data/test/unit/core/shape/list/test_format.rb +71 -0
- data/test/unit/core/shape/list/test_page.rb +10 -0
- data/test/unit/core/shape/list/test_page_state.rb +31 -0
- data/test/unit/core/shape/list/test_section_format.rb +46 -0
- data/test/unit/core/shape/list/test_section_interface.rb +52 -0
- data/test/unit/core/shape/list/test_section_internal.rb +30 -0
- data/test/unit/core/shape/list/test_store.rb +41 -0
- data/test/unit/core/shape/manager/test_format.rb +40 -0
- data/test/unit/core/shape/manager/test_internal.rb +137 -0
- data/test/unit/core/shape/manager/test_target.rb +109 -0
- data/test/unit/core/shape/tblock/formatter/test_basic.rb +24 -0
- data/test/unit/core/shape/tblock/formatter/test_datetime.rb +47 -0
- data/test/unit/core/shape/tblock/formatter/test_number.rb +76 -0
- data/test/unit/core/shape/tblock/formatter/test_padding.rb +72 -0
- data/test/unit/core/shape/tblock/test_format.rb +125 -0
- data/test/unit/core/shape/tblock/test_formatter.rb +28 -0
- data/test/unit/core/shape/tblock/test_interface.rb +40 -0
- data/test/unit/core/shape/tblock/test_internal.rb +139 -0
- data/test/unit/core/shape/text/test_format.rb +73 -0
- data/test/unit/core/shape/text/test_internal.rb +21 -0
- data/test/unit/core/test_events.rb +91 -0
- data/test/unit/core/test_shape.rb +35 -0
- data/test/unit/core/utils_spec.rb +56 -0
- data/test/unit/generator/pdf/document/graphics/test_attributes.rb +103 -0
- data/test/unit/generator/pdf/document/test_font.rb +54 -0
- data/test/unit/generator/pdf/document/test_graphics.rb +43 -0
- data/test/unit/generator/pdf/document/test_parse_color.rb +30 -0
- data/test/unit/generator/test_base.rb +51 -0
- data/test/unit/helper.rb +37 -0
- data/test/unit/layout/test_base.rb +92 -0
- data/test/unit/layout/test_configuration.rb +46 -0
- data/test/unit/layout/test_format.rb +104 -0
- data/test/unit/layout/test_version.rb +62 -0
- data/test/unit/report/test_base.rb +187 -0
- data/test/unit/report/test_events.rb +22 -0
- data/test/unit/report/test_internal.rb +234 -0
- data/test/unit/test_layout.rb +12 -0
- data/test/unit/test_report.rb +30 -0
- metadata +218 -0
@@ -0,0 +1,42 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
module ThinReports
|
4
|
+
module Generator
|
5
|
+
|
6
|
+
# @private
|
7
|
+
module Pdf::Graphics
|
8
|
+
|
9
|
+
BASE_LINE_WIDTH = 0.9
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
# Change the default graphic states defined by Prawn.
|
14
|
+
def setup_custom_graphic_states
|
15
|
+
pdf.line_width(BASE_LINE_WIDTH)
|
16
|
+
end
|
17
|
+
|
18
|
+
# @param [Numeric] width
|
19
|
+
def line_width(width)
|
20
|
+
pdf.line_width(width * BASE_LINE_WIDTH)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Delegate to Prawn::Document#save_graphic_state
|
24
|
+
# @see Prawn::Document#save_graphics_state
|
25
|
+
def save_graphics_state
|
26
|
+
pdf.save_graphics_state
|
27
|
+
end
|
28
|
+
|
29
|
+
# Delegate to Prawn::Document#restore_graphic_state
|
30
|
+
# @see Prawn::Document#restore_graphics_state
|
31
|
+
def restore_graphics_state
|
32
|
+
pdf.restore_graphics_state
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
require 'thinreports/generator/pdf/document/graphics/attributes'
|
40
|
+
require 'thinreports/generator/pdf/document/graphics/basic'
|
41
|
+
require 'thinreports/generator/pdf/document/graphics/image'
|
42
|
+
require 'thinreports/generator/pdf/document/graphics/text'
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
module ThinReports
|
4
|
+
module Generator
|
5
|
+
|
6
|
+
module Pdf::Graphics
|
7
|
+
# @param [Hash] svg_attrs
|
8
|
+
# @yield [attrs]
|
9
|
+
# @yieldparam [Hash] attrs
|
10
|
+
# @return [Hash]
|
11
|
+
def common_graphic_attrs(svg_attrs, &block)
|
12
|
+
attrs = {:stroke => svg_attrs['stroke'],
|
13
|
+
:stroke_width => svg_attrs['stroke-width'],
|
14
|
+
:fill => svg_attrs['fill']}
|
15
|
+
|
16
|
+
# Set 0 to stroke_width if stroke_opacity is '0'.
|
17
|
+
if svg_attrs['stroke-opacity'] == '0'
|
18
|
+
attrs[:stroke_width] = 0
|
19
|
+
end
|
20
|
+
|
21
|
+
# Setting for stroke dash.
|
22
|
+
if (dash = svg_attrs['stroke-dasharray']) && dash != 'none'
|
23
|
+
attrs[:stroke_dash] = dash.split(',')
|
24
|
+
end
|
25
|
+
block.call(attrs) if block_given?
|
26
|
+
attrs
|
27
|
+
end
|
28
|
+
|
29
|
+
# @param [Hash] svg_attrs
|
30
|
+
# @yield [attrs]
|
31
|
+
# @yieldparam [Hash] attrs
|
32
|
+
# @return [Hash]
|
33
|
+
def common_text_attrs(svg_attrs, &block)
|
34
|
+
attrs = {:font => default_family_if_missing(svg_attrs['font-family']),
|
35
|
+
:size => svg_attrs['font-size'],
|
36
|
+
:color => svg_attrs['fill'],
|
37
|
+
:align => text_align(svg_attrs['text-anchor']),
|
38
|
+
:styles => font_styles(svg_attrs)}
|
39
|
+
# Letter Spacing.
|
40
|
+
if space = svg_attrs['letter-spacing']
|
41
|
+
attrs[:letter_spacing] = space unless space == 'normal'
|
42
|
+
end
|
43
|
+
block.call(attrs) if block_given?
|
44
|
+
attrs
|
45
|
+
end
|
46
|
+
|
47
|
+
# @param [Hash] svg_attrs
|
48
|
+
# @return [Array<Symbol>]
|
49
|
+
def font_styles(svg_attrs)
|
50
|
+
styles = []
|
51
|
+
styles << :bold if svg_attrs['font-weight'] == 'bold'
|
52
|
+
styles << :italic if svg_attrs['font-style'] == 'italic'
|
53
|
+
|
54
|
+
if (deco = svg_attrs['text-decoration']) && deco != 'none'
|
55
|
+
deco = deco.split(' ')
|
56
|
+
styles << :underline if deco.include?('underline')
|
57
|
+
styles << :strikethrough if deco.include?('line-through')
|
58
|
+
end
|
59
|
+
styles
|
60
|
+
end
|
61
|
+
|
62
|
+
# @param [String] svg_align
|
63
|
+
# @return [Symbol]
|
64
|
+
def text_align(svg_align)
|
65
|
+
case svg_align
|
66
|
+
when 'start' then :left
|
67
|
+
when 'middle' then :center
|
68
|
+
when 'end' then :right
|
69
|
+
else :left
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# @param [String] svg_valign
|
74
|
+
# @return [Symbol]
|
75
|
+
def text_valign(svg_valign)
|
76
|
+
case svg_valign
|
77
|
+
when 'top' then :top
|
78
|
+
when 'center' then :center
|
79
|
+
when 'bottom' then :bottom
|
80
|
+
else :top
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# @param [String] xlink
|
85
|
+
# @return [String]
|
86
|
+
def extract_base64_string(xlink)
|
87
|
+
xlink.sub(%r{^data:image/[a-z]+?;base64,}, '')
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
module ThinReports
|
4
|
+
module Generator
|
5
|
+
|
6
|
+
module Pdf::Graphics
|
7
|
+
# @param [Numeric, String] x1
|
8
|
+
# @param [Numeric, String] y1
|
9
|
+
# @param [Numeric, String] x2
|
10
|
+
# @param [Numeric, String] y2
|
11
|
+
# @param [Hash] attrs ({})
|
12
|
+
# @option attrs [String] :stroke
|
13
|
+
# @option attrs [Numeric, String] :stroke_width
|
14
|
+
# @option attrs [Array<Integer, String>] :stroke_dash
|
15
|
+
def line(x1, y1, x2, y2, attrs = {})
|
16
|
+
with_graphic_styles(attrs) do
|
17
|
+
pdf.line(pos(x1, y1), pos(x2, y2))
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# @param [Numeric, String] x
|
22
|
+
# @param [Numeric, String] y
|
23
|
+
# @param [Numeric, String] w width
|
24
|
+
# @param [Numeric, String] h height
|
25
|
+
# @param [Hash] attrs ({})
|
26
|
+
# @option attrs [Integer, String] :radius
|
27
|
+
# @option attrs [String] :stroke
|
28
|
+
# @option attrs [Numeric, String] :stroke_width
|
29
|
+
# @option attrs [Array<Integer, String>] :stroke_dash
|
30
|
+
# @option attrs [String] :fill
|
31
|
+
def rect(x, y, w, h, attrs = {})
|
32
|
+
w, h = s2f(w, h)
|
33
|
+
radius = s2f(attrs[:radius])
|
34
|
+
|
35
|
+
with_graphic_styles(attrs) do
|
36
|
+
if radius && !radius.zero?
|
37
|
+
pdf.rounded_rectangle(pos(x, y), w, h, radius)
|
38
|
+
else
|
39
|
+
pdf.rectangle(pos(x, y), w, h)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# @param [Numeric, String] x center-x
|
45
|
+
# @param [Numeric, String] y center-y
|
46
|
+
# @param [Numeric, String] rx
|
47
|
+
# @param [Numeric, String] ry
|
48
|
+
# @param [Hash] attrs ({})
|
49
|
+
# @option attrs [String] :stroke
|
50
|
+
# @option attrs [Numeric, String] :stroke_width
|
51
|
+
# @option attrs [Array<Integer, String>] :stroke_dash
|
52
|
+
# @option attrs [String] :fill
|
53
|
+
def ellipse(x, y, rx, ry, attrs = {})
|
54
|
+
rx, ry = s2f(rx, ry)
|
55
|
+
|
56
|
+
with_graphic_styles(attrs) do
|
57
|
+
pdf.ellipse(pos(x, y), rx, ry)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
# @param [Hash] attrs
|
64
|
+
def with_graphic_styles(attrs, &block)
|
65
|
+
stroke = build_stroke_styles(attrs)
|
66
|
+
fill = build_fill_styles(attrs)
|
67
|
+
|
68
|
+
# Do not draw if no colors given.
|
69
|
+
return unless fill || stroke
|
70
|
+
|
71
|
+
save_graphics_state
|
72
|
+
|
73
|
+
# Apply stroke-dashed.
|
74
|
+
if stroke && stroke[:dash]
|
75
|
+
length, space = stroke[:dash]
|
76
|
+
pdf.dash(length, :space => space)
|
77
|
+
end
|
78
|
+
|
79
|
+
case
|
80
|
+
# Draw with fill and stroke.
|
81
|
+
when fill && stroke
|
82
|
+
pdf.fill_and_stroke {
|
83
|
+
line_width(stroke[:width])
|
84
|
+
pdf.fill_color(fill[:color])
|
85
|
+
pdf.stroke_color(stroke[:color])
|
86
|
+
block.call
|
87
|
+
}
|
88
|
+
# Draw only with fill.
|
89
|
+
when fill
|
90
|
+
pdf.fill {
|
91
|
+
pdf.fill_color(fill[:color])
|
92
|
+
block.call
|
93
|
+
}
|
94
|
+
# Draw only with stroke.
|
95
|
+
when stroke
|
96
|
+
pdf.stroke {
|
97
|
+
line_width(stroke[:width])
|
98
|
+
pdf.stroke_color(stroke[:color])
|
99
|
+
block.call
|
100
|
+
}
|
101
|
+
end
|
102
|
+
|
103
|
+
restore_graphics_state
|
104
|
+
end
|
105
|
+
|
106
|
+
# @param [Hash] styles
|
107
|
+
# @return [Hash, nil]
|
108
|
+
def build_stroke_styles(styles)
|
109
|
+
color = styles[:stroke]
|
110
|
+
width = styles[:stroke_width]
|
111
|
+
|
112
|
+
if color && color != 'none' && width && width != 0
|
113
|
+
{:color => parse_color(color),
|
114
|
+
:width => s2f(width),
|
115
|
+
:dash => s2f(*styles[:stroke_dash])}
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# @param [Hash] styles
|
120
|
+
# @return [Hash, nil]
|
121
|
+
def build_fill_styles(styles)
|
122
|
+
color = styles[:fill]
|
123
|
+
|
124
|
+
if color && color != 'none'
|
125
|
+
{:color => parse_color(color)}
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'tempfile'
|
4
|
+
require 'base64'
|
5
|
+
|
6
|
+
module ThinReports
|
7
|
+
module Generator
|
8
|
+
|
9
|
+
module Pdf::Graphics
|
10
|
+
# @param [String] filename
|
11
|
+
# @param [Numeric, Strng] x
|
12
|
+
# @param [Numeric, Strng] y
|
13
|
+
# @param [Numeric, Strng] w
|
14
|
+
# @param [Numeric, Strng] h
|
15
|
+
def image(filename, x, y, w, h)
|
16
|
+
w, h = s2f(w, h)
|
17
|
+
pdf.image(filename, :at => pos(x, y), :width => w, :height => h)
|
18
|
+
end
|
19
|
+
|
20
|
+
# @param [String] base64
|
21
|
+
# @param x, y, w, h (see #image)
|
22
|
+
def base64image(base64, x, y, w, h)
|
23
|
+
image = create_temp_imagefile(base64)
|
24
|
+
image(image.path, x, y, w, h)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def clean_temp_images
|
30
|
+
temp_image_registry.each {|tmp| tmp.unlink }
|
31
|
+
end
|
32
|
+
|
33
|
+
def temp_image_registry
|
34
|
+
@temp_image_registry ||= []
|
35
|
+
end
|
36
|
+
|
37
|
+
# @param [String] base64
|
38
|
+
# @return [Tempfile]
|
39
|
+
def create_temp_imagefile(base64)
|
40
|
+
file = Tempfile.new('trg-tmp-img')
|
41
|
+
file.binmode
|
42
|
+
file.write(Base64.decode64(base64))
|
43
|
+
temp_image_registry << file
|
44
|
+
file
|
45
|
+
ensure
|
46
|
+
file.close
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
module ThinReports
|
4
|
+
module Generator
|
5
|
+
|
6
|
+
module Pdf::Graphics
|
7
|
+
# @param [String] content
|
8
|
+
# @param [Numeric, String] x
|
9
|
+
# @param [Numeric, String] y
|
10
|
+
# @param [Numeric, String] w
|
11
|
+
# @param [Numeric, String] h
|
12
|
+
# @param [Hash] attrs ({})
|
13
|
+
# @option attrs [String] :font
|
14
|
+
# @option attrs [Numeric, String] :size
|
15
|
+
# @option attrs [String] :color
|
16
|
+
# @option attrs [Array<:bold, :italic, :underline, :strikethrough>]
|
17
|
+
# :styles (nil)
|
18
|
+
# @option attrs [:left, :center, :right] :align (:left)
|
19
|
+
# @option attrs [:top, :center, :bottom] :valign (:top)
|
20
|
+
# @option attrs [Numeric, String] :line_height The total height of an text line.
|
21
|
+
# @option attrs [Numeric, String] :letter_spacing
|
22
|
+
def text_box(content, x, y, w, h, attrs = {})
|
23
|
+
w, h = s2f(w, h)
|
24
|
+
with_text_styles(attrs) do |built_attrs, font_styles|
|
25
|
+
pdf.formatted_text_box([{:text => text_without_line_wrap(content),
|
26
|
+
:styles => font_styles}],
|
27
|
+
built_attrs.merge(:at => pos(x, y),
|
28
|
+
:width => w,
|
29
|
+
:height => h))
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# @see #text_box
|
34
|
+
def text(content, x, y, w, h, attrs = {})
|
35
|
+
# Set the :overflow property to :shirink_to_fit.
|
36
|
+
text_box(content, x, y, w, h, attrs.merge(:overflow => :shrink_to_fit))
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
# @param attrs (see #text)
|
42
|
+
# @yield [built_attrs, font_styles]
|
43
|
+
# @yieldparam [Hash] built_attrs The finalized attributes.
|
44
|
+
# @yieldparam [Array] font_styles The finalized styles.
|
45
|
+
def with_text_styles(attrs, &block)
|
46
|
+
# When no color is given, do not draw.
|
47
|
+
return unless attrs.key?(:color) && attrs[:color] != 'none'
|
48
|
+
|
49
|
+
save_graphics_state
|
50
|
+
|
51
|
+
fontinfo = {:name => attrs.delete(:font).to_s,
|
52
|
+
:color => parse_color(attrs.delete(:color)),
|
53
|
+
:size => s2f(attrs.delete(:size))}
|
54
|
+
|
55
|
+
# Add the specified value to :leading option.
|
56
|
+
if line_height = attrs.delete(:line_height)
|
57
|
+
attrs[:leading] = text_line_leading(s2f(line_height),
|
58
|
+
:name => fontinfo[:name],
|
59
|
+
:size => fontinfo[:size])
|
60
|
+
end
|
61
|
+
|
62
|
+
# Set the :character_spacing option.
|
63
|
+
if space = attrs.delete(:letter_spacing)
|
64
|
+
attrs[:character_spacing] = s2f(space)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Or... with_font_styles(attrs, fontinfo, &block)
|
68
|
+
with_font_styles(attrs, fontinfo) do |modified_attrs, styles|
|
69
|
+
block.call(modified_attrs, styles)
|
70
|
+
end
|
71
|
+
|
72
|
+
restore_graphics_state
|
73
|
+
end
|
74
|
+
|
75
|
+
# @param [Numeric] line_height
|
76
|
+
# @param [Hash] font
|
77
|
+
# @option font [String] :name Name of font.
|
78
|
+
# @option font [Numeric] :size Size of font.
|
79
|
+
# @return [Numeric]
|
80
|
+
def text_line_leading(line_height, font)
|
81
|
+
line_height - pdf.font(font[:name], :size => font[:size]).height
|
82
|
+
end
|
83
|
+
|
84
|
+
# @param [String] content
|
85
|
+
# @return [String]
|
86
|
+
def text_without_line_wrap(content)
|
87
|
+
content.gsub(/ /, Prawn::Text::NBSP)
|
88
|
+
end
|
89
|
+
|
90
|
+
# @param [Hash] attrs
|
91
|
+
# @param [Hash] font
|
92
|
+
# @option font [String] :color
|
93
|
+
# @option font [Numeric] :size
|
94
|
+
# @option font [String] :name
|
95
|
+
# @yield [attributes, styles]
|
96
|
+
# @yieldparam [Hash] modified_attrs
|
97
|
+
# @yieldparam [Array] styles
|
98
|
+
def with_font_styles(attrs, font, &block)
|
99
|
+
# Building font styles.
|
100
|
+
if styles = attrs.delete(:styles)
|
101
|
+
manual, styles = styles.partition do |style|
|
102
|
+
[:bold, :italic].include?(style) && !font_has_style?(font[:name], style)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# Emulate bold style.
|
107
|
+
if manual.include?(:bold)
|
108
|
+
pdf.stroke_color(font[:color])
|
109
|
+
pdf.line_width(font[:size] * 0.025)
|
110
|
+
|
111
|
+
# Change rendering mode to :fill_stroke.
|
112
|
+
attrs[:mode] = :fill_stroke
|
113
|
+
end
|
114
|
+
|
115
|
+
# Emulate italic style.
|
116
|
+
if manual.include?(:italic)
|
117
|
+
# FIXME
|
118
|
+
# pdf.transformation_matrix(1, 0, 0.26, 1, 0, 0)
|
119
|
+
end
|
120
|
+
|
121
|
+
pdf.font(font[:name], :size => font[:size]) do
|
122
|
+
pdf.fill_color(font[:color])
|
123
|
+
block.call(attrs, styles || [])
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
end
|