prawn 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. data/Rakefile +3 -1
  2. data/data/fonts/Action Man.dfont +0 -0
  3. data/examples/general/measurement_units.rb +2 -2
  4. data/examples/graphics/image_flow.rb +2 -2
  5. data/examples/graphics/stroke_bounds.rb +1 -1
  6. data/examples/m17n/win_ansi_charset.rb +3 -3
  7. data/examples/text/dfont.rb +49 -0
  8. data/examples/text/flowing_text_with_header_and_footer.rb +2 -48
  9. data/examples/text/font_calculations.rb +7 -6
  10. data/examples/text/font_size.rb +4 -4
  11. data/examples/text/text_flow.rb +1 -1
  12. data/lib/prawn.rb +6 -3
  13. data/lib/prawn/compatibility.rb +12 -17
  14. data/lib/prawn/document.rb +10 -10
  15. data/lib/prawn/document/internals.rb +8 -3
  16. data/lib/prawn/document/text.rb +39 -57
  17. data/lib/prawn/document/text/box.rb +1 -2
  18. data/lib/prawn/document/text/wrapping.rb +59 -0
  19. data/lib/prawn/errors.rb +0 -8
  20. data/lib/prawn/font.rb +192 -277
  21. data/lib/prawn/font/afm.rb +199 -0
  22. data/lib/prawn/font/dfont.rb +31 -0
  23. data/lib/prawn/font/ttf.rb +318 -0
  24. data/lib/prawn/graphics.rb +7 -2
  25. data/lib/prawn/images/png.rb +1 -1
  26. data/lib/prawn/reference.rb +7 -4
  27. data/spec/font_spec.rb +154 -61
  28. data/spec/text_spec.rb +47 -6
  29. data/vendor/pdf-inspector/lib/pdf/inspector.rb +1 -1
  30. data/vendor/ttfunk/example.rb +42 -2
  31. data/vendor/ttfunk/lib/ttfunk.rb +96 -42
  32. data/vendor/ttfunk/lib/ttfunk/directory.rb +17 -0
  33. data/vendor/ttfunk/lib/ttfunk/encoding/mac_roman.rb +88 -0
  34. data/vendor/ttfunk/lib/ttfunk/encoding/windows_1252.rb +69 -0
  35. data/vendor/ttfunk/lib/ttfunk/reader.rb +44 -0
  36. data/vendor/ttfunk/lib/ttfunk/resource_file.rb +78 -0
  37. data/vendor/ttfunk/lib/ttfunk/subset.rb +18 -0
  38. data/vendor/ttfunk/lib/ttfunk/subset/base.rb +141 -0
  39. data/vendor/ttfunk/lib/ttfunk/subset/mac_roman.rb +46 -0
  40. data/vendor/ttfunk/lib/ttfunk/subset/unicode.rb +48 -0
  41. data/vendor/ttfunk/lib/ttfunk/subset/unicode_8bit.rb +63 -0
  42. data/vendor/ttfunk/lib/ttfunk/subset/windows_1252.rb +51 -0
  43. data/vendor/ttfunk/lib/ttfunk/subset_collection.rb +72 -0
  44. data/vendor/ttfunk/lib/ttfunk/table.rb +37 -18
  45. data/vendor/ttfunk/lib/ttfunk/table/cmap.rb +24 -84
  46. data/vendor/ttfunk/lib/ttfunk/table/cmap/format00.rb +54 -0
  47. data/vendor/ttfunk/lib/ttfunk/table/cmap/format04.rb +126 -0
  48. data/vendor/ttfunk/lib/ttfunk/table/cmap/subtable.rb +79 -0
  49. data/vendor/ttfunk/lib/ttfunk/table/glyf.rb +64 -0
  50. data/vendor/ttfunk/lib/ttfunk/table/glyf/compound.rb +81 -0
  51. data/vendor/ttfunk/lib/ttfunk/table/glyf/simple.rb +37 -0
  52. data/vendor/ttfunk/lib/ttfunk/table/head.rb +38 -19
  53. data/vendor/ttfunk/lib/ttfunk/table/hhea.rb +35 -21
  54. data/vendor/ttfunk/lib/ttfunk/table/hmtx.rb +40 -13
  55. data/vendor/ttfunk/lib/ttfunk/table/kern.rb +69 -38
  56. data/vendor/ttfunk/lib/ttfunk/table/kern/format0.rb +62 -0
  57. data/vendor/ttfunk/lib/ttfunk/table/loca.rb +43 -0
  58. data/vendor/ttfunk/lib/ttfunk/table/maxp.rb +34 -11
  59. data/vendor/ttfunk/lib/ttfunk/table/name.rb +109 -42
  60. data/vendor/ttfunk/lib/ttfunk/table/os2.rb +78 -0
  61. data/vendor/ttfunk/lib/ttfunk/table/post.rb +91 -0
  62. data/vendor/ttfunk/lib/ttfunk/table/post/format10.rb +43 -0
  63. data/vendor/ttfunk/lib/ttfunk/table/post/format20.rb +35 -0
  64. data/vendor/ttfunk/lib/ttfunk/table/post/format25.rb +23 -0
  65. data/vendor/ttfunk/lib/ttfunk/table/post/format30.rb +17 -0
  66. data/vendor/ttfunk/lib/ttfunk/table/post/format40.rb +17 -0
  67. data/vendor/ttfunk/lib/ttfunk/table/simple.rb +14 -0
  68. metadata +54 -25
  69. data/examples/table/addressbook.csv +0 -6
  70. data/examples/table/cell.rb +0 -40
  71. data/examples/table/currency.csv +0 -1834
  72. data/examples/table/fancy_table.rb +0 -62
  73. data/examples/table/ruport_formatter.rb +0 -53
  74. data/examples/table/table.rb +0 -51
  75. data/examples/table/table_alignment.rb +0 -18
  76. data/examples/table/table_border_color.rb +0 -17
  77. data/examples/table/table_colspan.rb +0 -19
  78. data/examples/table/table_header_color.rb +0 -19
  79. data/examples/table/table_header_underline.rb +0 -15
  80. data/lib/prawn/document/table.rb +0 -338
  81. data/lib/prawn/font/cmap.rb +0 -59
  82. data/lib/prawn/font/metrics.rb +0 -378
  83. data/lib/prawn/font/wrapping.rb +0 -47
  84. data/lib/prawn/graphics/cell.rb +0 -264
  85. data/spec/metrics_spec.rb +0 -62
  86. data/spec/table_spec.rb +0 -179
  87. data/vendor/ttfunk/lib/ttfunk/table/directory.rb +0 -25
@@ -1,264 +0,0 @@
1
- # encoding: utf-8
2
-
3
- # cell.rb : Table support functions
4
- #
5
- # Copyright June 2008, Gregory Brown. All Rights Reserved.
6
- #
7
- # This is free software. Please see the LICENSE and COPYING files for details.
8
- module Prawn
9
-
10
- class Document
11
- # Builds and renders a Graphics::Cell. A cell is essentially a
12
- # special-purpose bounding box designed for flowing text within a bordered
13
- # area. For available options, see Graphics::Cell#new.
14
- #
15
- # Prawn::Document.generate("cell.pdf") do
16
- # cell [100,500],
17
- # :width => 200,
18
- # :text => "The rain in Spain falls mainly on the plains"
19
- # end
20
- #
21
- def cell(point, options={})
22
- Prawn::Graphics::Cell.new(
23
- options.merge(:document => self, :point => point)).draw
24
- end
25
- end
26
-
27
- module Graphics
28
- # A cell is a special-purpose bounding box designed to flow text within a
29
- # bordered area. This is used by Prawn's Document::Table implementation but
30
- # can also be used standalone for drawing text boxes via Document#cell
31
- #
32
- class Cell
33
-
34
- # Creates a new cell object. Generally used indirectly via Document#cell
35
- #
36
- # Of the available options listed below, <tt>:point</tt>, <tt>:width</tt>,
37
- # and <tt>:text</tt> must be provided. If you are not using the
38
- # Document#cell shortcut, the <tt>:document</tt> must also be provided.
39
- #
40
- # <tt>:point</tt>:: Absolute [x,y] coordinate of the top-left corner of the cell.
41
- # <tt>:document</tt>:: The Prawn::Document object to render on.
42
- # <tt>:text</tt>:: The text to be flowed within the cell
43
- # <tt>:text_color</tt>:: The color of the text to be displayed
44
- # <tt>:width</tt>:: The width in PDF points of the cell.
45
- # <tt>:height</tt>:: The height in PDF points of the cell.
46
- # <tt>:horizontal_padding</tt>:: The horizontal padding in PDF points
47
- # <tt>:vertical_padding</tt>:: The vertical padding in PDF points
48
- # <tt>:padding</tt>:: Overrides both horizontal and vertical padding
49
- # <tt>:align</tt>:: One of <tt>:left</tt>, <tt>:right</tt>, <tt>:center</tt>
50
- # <tt>:borders</tt>:: An array of sides which should have a border. Any of <tt>:top</tt>, <tt>:left</tt>, <tt>:right</tt>, <tt>:bottom</tt>
51
- # <tt>:border_width</tt>:: The border line width. Defaults to 1.
52
- # <tt>:border_style</tt>:: One of <tt>:all</tt>, <tt>:no_top</tt>, <tt>:no_bottom</tt>, <tt>:sides</tt>, <tt>:none</tt>, <tt>:bottom_only</tt>. Defaults to :all.
53
- # <tt>:border_color</tt>:: The color of the cell border.
54
- # <tt>:font_size</tt>:: The font size for the cell text.
55
- #
56
- def initialize(options={})
57
- @point = options[:point]
58
- @document = options[:document]
59
- @text = options[:text].to_s
60
- @text_color = options[:text_color]
61
- @width = options[:width]
62
- @height = options[:height]
63
- @borders = options[:borders]
64
- @border_width = options[:border_width] || 1
65
- @border_style = options[:border_style] || :all
66
- @border_color = options[:border_color]
67
- @background_color = options[:background_color]
68
- @align = options[:align] || :left
69
- @font_size = options[:font_size]
70
-
71
- @horizontal_padding = options[:horizontal_padding] || 0
72
- @vertical_padding = options[:vertical_padding] || 0
73
-
74
- if options[:padding]
75
- @horizontal_padding = @vertical_padding = options[:padding]
76
- end
77
- end
78
-
79
- attr_accessor :point, :border_style, :border_width, :background_color,
80
- :document, :horizontal_padding, :vertical_padding, :align,
81
- :borders, :text_color, :border_color
82
-
83
- attr_writer :height, :width #:nodoc:
84
-
85
- # Returns the cell's text as a string.
86
- #
87
- def to_s
88
- @text
89
- end
90
-
91
- # The width of the text area excluding the horizonal padding
92
- #
93
- def text_area_width
94
- width - 2*@horizontal_padding
95
- end
96
-
97
- # The width of the cell in PDF points
98
- #
99
- def width
100
- @width || (@document.font.metrics.string_width(@text,
101
- @font_size || @document.font.size)) + 2*@horizontal_padding
102
- end
103
-
104
- # The height of the cell in PDF points
105
- #
106
- def height
107
- @height || text_area_height + 2*@vertical_padding
108
- end
109
-
110
- # The height of the text area excluding the vertical padding
111
- #
112
- def text_area_height
113
- @document.font.height_of(@text, :line_width => text_area_width)
114
- end
115
-
116
- # Draws the cell onto the PDF document
117
- #
118
- def draw
119
- rel_point = @point
120
-
121
- if @background_color
122
- @document.mask(:fill_color) do
123
- @document.fill_color @background_color
124
- h = borders.include?(:bottom) ?
125
- height - border_width : height + border_width / 2.0
126
- @document.fill_rectangle [rel_point[0] + border_width / 2.0,
127
- rel_point[1] - border_width / 2.0 ],
128
- width - border_width, h
129
- end
130
- end
131
-
132
- if @border_width > 0
133
- @document.mask(:line_width) do
134
- @document.line_width = @border_width
135
-
136
- @document.mask(:stroke_color) do
137
- @document.stroke_color @border_color if @border_color
138
-
139
- if borders.include?(:left)
140
- @document.stroke_line [rel_point[0], rel_point[1] + (@border_width / 2.0)],
141
- [rel_point[0], rel_point[1] - height - @border_width / 2.0 ]
142
- end
143
-
144
- if borders.include?(:right)
145
- @document.stroke_line(
146
- [rel_point[0] + width, rel_point[1] + (@border_width / 2.0)],
147
- [rel_point[0] + width, rel_point[1] - height - @border_width / 2.0] )
148
- end
149
-
150
- if borders.include?(:top)
151
- @document.stroke_line(
152
- [ rel_point[0] + @border_width / 2.0, rel_point[1] ],
153
- [ rel_point[0] - @border_width / 2.0 + width, rel_point[1] ])
154
- end
155
-
156
- if borders.include?(:bottom)
157
- @document.stroke_line [rel_point[0], rel_point[1] - height ],
158
- [rel_point[0] + width, rel_point[1] - height]
159
- end
160
- end
161
-
162
- end
163
-
164
- borders
165
-
166
- end
167
-
168
- @document.bounding_box( [@point[0] + @horizontal_padding,
169
- @point[1] - @vertical_padding],
170
- :width => text_area_width,
171
- :height => height - @vertical_padding) do
172
- @document.move_up @document.font.line_gap
173
-
174
- options = {:align => @align}
175
-
176
- options[:size] = @font_size if @font_size
177
-
178
- @document.mask(:fill_color) do
179
- @document.fill_color @text_color if @text_color
180
- @document.text @text, options
181
- end
182
- end
183
- end
184
-
185
- private
186
-
187
- def borders
188
- @borders ||= case @border_style
189
- when :all
190
- [:top,:left,:right,:bottom]
191
- when :sides
192
- [:left,:right]
193
- when :no_top
194
- [:left,:right,:bottom]
195
- when :no_bottom
196
- [:left,:right,:top]
197
- when :bottom_only
198
- [:bottom]
199
- when :none
200
- []
201
- end
202
- end
203
-
204
- end
205
-
206
- class CellBlock #:nodoc:
207
-
208
- # Not sure if this class is something I want to expose in the public API.
209
-
210
- def initialize(document)
211
- @document = document
212
- @cells = []
213
- @width = 0
214
- @height = 0
215
- end
216
-
217
- attr_reader :width, :height, :cells
218
- attr_accessor :background_color, :text_color, :border_color
219
-
220
- def <<(cell)
221
- @cells << cell
222
- @height = cell.height if cell.height > @height
223
- @width += cell.width
224
- self
225
- end
226
-
227
- def draw
228
- y = @document.y
229
- x = @document.bounds.absolute_left
230
-
231
- @cells.each do |e|
232
- e.point = [x - @document.bounds.absolute_left,
233
- y - @document.bounds.absolute_bottom]
234
- e.height = @height
235
- e.background_color ||= @background_color
236
- e.text_color ||= @text_color
237
- e.border_color ||= @border_color
238
- e.draw
239
- x += e.width
240
- end
241
-
242
- @document.y = y - @height
243
- end
244
-
245
- def border_width
246
- @cells[0].border_width
247
- end
248
-
249
- def border_style=(s)
250
- @cells.each { |e| e.border_style = s }
251
- end
252
-
253
- def align=(align)
254
- @cells.each { |e| e.align = align }
255
- end
256
-
257
- def border_style
258
- @cells[0].border_style
259
- end
260
-
261
- end
262
- end
263
-
264
- end
data/spec/metrics_spec.rb DELETED
@@ -1,62 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
4
- require "iconv"
5
-
6
- describe "adobe font metrics" do
7
-
8
- setup do
9
- @times = Prawn::Font::Metrics["Times-Roman"]
10
- @iconv = ::Iconv.new('ISO-8859-1', 'utf-8')
11
- end
12
-
13
- it "should calculate string width taking into account accented characters" do
14
- @times.string_width(@iconv.iconv("é"), 12).should == @times.string_width("e", 12)
15
- end
16
-
17
- it "should calculate string width taking into account kerning pairs" do
18
- @times.string_width(@iconv.iconv("To"), 12).should == 13.332
19
- @times.string_width(@iconv.iconv("To"), 12, :kerning => true).should == 12.372
20
- @times.string_width(@iconv.iconv("Tö"), 12, :kerning => true).should == 12.372
21
- end
22
-
23
- it "should kern a string" do
24
- @times.kern(@iconv.iconv("To")).should == ["T", 80, "o"]
25
- @times.kern(@iconv.iconv("Télé")).should == ["T", 70, @iconv.iconv("élé")]
26
- @times.kern(@iconv.iconv("Technology")).should == ["T", 70, "echnology"]
27
- @times.kern(@iconv.iconv("Technology...")).should == ["T", 70, "echnology", 65, "..."]
28
- end
29
-
30
- end
31
-
32
- describe "ttf font metrics" do
33
-
34
- setup do
35
- @activa = Prawn::Font::Metrics["#{Prawn::BASEDIR}/data/fonts/Activa.ttf"]
36
- end
37
-
38
- it "should calculate string width taking into account accented characters" do
39
- @activa.string_width("é", 12).should == @activa.string_width("e", 12)
40
- end
41
-
42
- it "should calculate string width taking into account kerning pairs" do
43
- @activa.string_width("To", 12).should == 15.228
44
- @activa.string_width("To", 12, :kerning => true).should.to_s == 12.996.to_s
45
- end
46
-
47
- it "should kern a string" do
48
- @activa.kern("To").should == ["\0007", 186.0, "\000R"]
49
-
50
- # Does activa use kerning classes here? Ruby/TTF doesn't support
51
- # format 2 kerning tables, so don't bother for now.
52
-
53
- # @activa.kern("Télé").should == ["T", -186, "élé"]
54
-
55
- @activa.kern("Technology").should == ["\0007", 186.0,
56
- "\000H\000F\000K\000Q\000R\000O\000R\000J\000\\"]
57
- @activa.kern("Technology...").should == ["\0007", 186.0,
58
- "\000H\000F\000K\000Q\000R\000O\000R\000J\000\\", 88.0,
59
- "\000\021\000\021\000\021"]
60
- end
61
-
62
- end
data/spec/table_spec.rb DELETED
@@ -1,179 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
4
-
5
- describe "A table's width" do
6
- it "should equal sum(col_widths)" do
7
- pdf = Prawn::Document.new
8
- table = Prawn::Document::Table.new( [%w[ a b c ], %w[d e f]], pdf,
9
- :widths => { 0 => 50, 1 => 100, 2 => 150 })
10
-
11
- table.width.should == 300
12
- end
13
-
14
- it "should calculate unspecified column widths as "+
15
- "(max(string_width).ceil + 2*horizontal_padding)" do
16
- pdf = Prawn::Document.new
17
- hpad, fs = 3, 12
18
- columns = 2
19
- table = Prawn::Document::Table.new( [%w[ foo b ], %w[d foobar]], pdf,
20
- :horizontal_padding => hpad, :font_size => fs)
21
-
22
- col0_width = pdf.font.metrics.string_width("foo",fs)
23
- col1_width = pdf.font.metrics.string_width("foobar",fs)
24
-
25
- table.width.should == col0_width.ceil + col1_width.ceil + 2*columns*hpad
26
- end
27
-
28
- it "should allow mixing autocalculated and preset"+
29
- "column widths within a single table" do
30
-
31
- pdf = Prawn::Document.new
32
- hpad, fs = 10, 6
33
- stretchy_columns = 2
34
-
35
- col0_width = 50
36
- col1_width = pdf.font.metrics.string_width("foo",fs)
37
- col2_width = pdf.font.metrics.string_width("foobar",fs)
38
- col3_width = 150
39
-
40
- table = Prawn::Document::Table.new( [%w[snake foo b apple],
41
- %w[kitten d foobar banana]], pdf,
42
- :horizontal_padding => hpad, :font_size => fs,
43
- :widths => { 0 => col0_width, 3 => col3_width } )
44
-
45
- table.width.should == col1_width.ceil + col2_width.ceil +
46
- 2*stretchy_columns*hpad +
47
- col0_width.ceil + col3_width.ceil
48
-
49
- end
50
-
51
- end
52
-
53
- describe "A table's height" do
54
-
55
- before :each do
56
- data = [["foo"],["bar"],["baaaz"]]
57
- pdf = Prawn::Document.new
58
- @num_rows = data.length
59
-
60
- @vpad = 4
61
- origin = pdf.y
62
- pdf.table data, :vertical_padding => @vpad
63
-
64
- @table_height = origin - pdf.y
65
-
66
- @font_height = pdf.font.height
67
- end
68
-
69
- it "should have a height of n rows" do
70
- @table_height.should.be.close(
71
- @num_rows*@font_height + 2*@vpad*@num_rows, 0.001 )
72
- end
73
-
74
- end
75
-
76
- describe "A table's content" do
77
-
78
- it "should not cause an error if rendering the very first row causes a page break" do
79
- Prawn::Document.new( :page_layout => :portrait ) do
80
- arr = Array(1..5).collect{|i| ["cell #{i}"] }
81
-
82
- move_down( y - (bounds.absolute_bottom + 3) )
83
-
84
- lambda {
85
- table( arr,
86
- :font_size => 9,
87
- :horizontal_padding => 3,
88
- :vertical_padding => 3,
89
- :border_width => 0.05,
90
- :border_style => :none,
91
- :row_colors => %w{ffffff eeeeee},
92
- :widths => {0 =>110},
93
- :position => :left,
94
- :headers => ["exploding header"],
95
- :align => :left,
96
- :align_headers => :center)
97
- }.should.not.raise
98
- end
99
- end
100
-
101
- it "should output content cell by cell, row by row" do
102
- data = [["foo","bar"],["baz","bang"]]
103
- @pdf = Prawn::Document.new
104
- @pdf.table(data)
105
- output = PDF::Inspector::Text.analyze(@pdf.render)
106
- output.strings.should == data.flatten
107
- end
108
-
109
- it "should add headers to output when specified" do
110
- data = [["foo","bar"],["baz","bang"]]
111
- headers = %w[a b]
112
- @pdf = Prawn::Document.new
113
- @pdf.table(data, :headers => headers)
114
- output = PDF::Inspector::Text.analyze(@pdf.render)
115
- output.strings.should == headers + data.flatten
116
- end
117
-
118
- it "should repeat headers across pages" do
119
- data = [["foo","bar"]]*30
120
- headers = ["baz","foobar"]
121
- @pdf = Prawn::Document.new
122
- @pdf.table(data, :headers => headers)
123
- output = PDF::Inspector::Text.analyze(@pdf.render)
124
- output.strings.should == headers + data.flatten[0..-3] + headers +
125
- data.flatten[-2..-1]
126
- end
127
-
128
- it "should allow empty fields" do
129
- lambda {
130
- data = [["foo","bar"],["baz",""]]
131
- @pdf = Prawn::Document.new
132
- @pdf.table(data)
133
- }.should.not.raise
134
- end
135
-
136
- it "should paginate for large tables" do
137
- # 30 rows fit on the table with default setting, 31 exceed.
138
- data = [["foo"]] * 31
139
- pdf = Prawn::Document.new
140
-
141
- pdf.table data
142
- pdf.page_count.should == 2
143
-
144
- pdf.table data
145
- pdf.page_count.should == 3
146
- end
147
-
148
- end
149
-
150
- describe "An invalid table" do
151
-
152
- before(:each) do
153
- @pdf = Prawn::Document.new
154
- @bad_data = ["Single Nested Array"]
155
- end
156
-
157
- it "should raise error when invalid table data is given" do
158
- assert_raises(Prawn::Errors::InvalidTableData) do
159
- @pdf.table(@bad_data)
160
- end
161
- end
162
-
163
- it "should raise an EmptyTableError with empty table data" do
164
- lambda {
165
- data = []
166
- @pdf = Prawn::Document.new
167
- @pdf.table(data)
168
- }.should.raise( Prawn::Errors::EmptyTable )
169
- end
170
-
171
- it "should raise an EmptyTableError with nil table data" do
172
- lambda {
173
- data = nil
174
- @pdf = Prawn::Document.new
175
- @pdf.table(data)
176
- }.should.raise( Prawn::Errors::EmptyTable )
177
- end
178
-
179
- end