prawn 0.2.3 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (144) hide show
  1. data/README +6 -10
  2. data/Rakefile +4 -13
  3. data/data/encodings/win_ansi.txt +29 -0
  4. data/data/images/fractal.jpg +0 -0
  5. data/data/images/letterhead.jpg +0 -0
  6. data/examples/bounding_box/bounding_boxes.rb +44 -0
  7. data/examples/bounding_box/lazy_bounding_boxes.rb +28 -0
  8. data/examples/bounding_box/padded_box.rb +24 -0
  9. data/examples/{russian_boxes.rb → bounding_box/russian_boxes.rb} +9 -6
  10. data/examples/general/background.rb +20 -0
  11. data/examples/{canvas.rb → general/canvas.rb} +6 -2
  12. data/examples/general/measurement_units.rb +52 -0
  13. data/examples/{multi_page_layout.rb → general/multi_page_layout.rb} +6 -3
  14. data/examples/{page_geometry.rb → general/page_geometry.rb} +6 -2
  15. data/examples/{image.rb → graphics/basic_images.rb} +8 -4
  16. data/examples/graphics/cmyk.rb +13 -0
  17. data/examples/graphics/curves.rb +12 -0
  18. data/examples/{hexagon.rb → graphics/hexagon.rb} +5 -5
  19. data/examples/graphics/image_fit.rb +16 -0
  20. data/examples/graphics/image_flow.rb +38 -0
  21. data/examples/graphics/image_position.rb +18 -0
  22. data/examples/{line.rb → graphics/line.rb} +4 -2
  23. data/examples/{png_types.rb → graphics/png_types.rb} +4 -4
  24. data/examples/{polygons.rb → graphics/polygons.rb} +5 -4
  25. data/examples/graphics/remote_images.rb +12 -0
  26. data/examples/{ruport_helpers.rb → graphics/ruport_style_helpers.rb} +8 -5
  27. data/examples/graphics/stroke_bounds.rb +23 -0
  28. data/examples/{chinese_text_wrapping.rb → m17n/chinese_text_wrapping.rb} +7 -4
  29. data/examples/m17n/euro.rb +16 -0
  30. data/examples/m17n/sjis.rb +29 -0
  31. data/examples/m17n/utf8.rb +14 -0
  32. data/examples/m17n/win_ansi_charset.rb +55 -0
  33. data/examples/{addressbook.csv → table/addressbook.csv} +0 -0
  34. data/examples/{cell.rb → table/cell.rb} +8 -6
  35. data/examples/{currency.csv → table/currency.csv} +0 -0
  36. data/examples/{fancy_table.rb → table/fancy_table.rb} +9 -6
  37. data/examples/{ruport_formatter.rb → table/ruport_formatter.rb} +6 -3
  38. data/examples/{table.rb → table/table.rb} +6 -2
  39. data/examples/table/table_alignment.rb +18 -0
  40. data/examples/table/table_border_color.rb +17 -0
  41. data/examples/table/table_colspan.rb +19 -0
  42. data/examples/table/table_header_color.rb +19 -0
  43. data/examples/table/table_header_underline.rb +15 -0
  44. data/examples/{alignment.rb → text/alignment.rb} +5 -2
  45. data/examples/text/family_based_styling.rb +25 -0
  46. data/examples/{flowing_text_with_header_and_footer.rb → text/flowing_text_with_header_and_footer.rb} +19 -8
  47. data/examples/text/font_calculations.rb +91 -0
  48. data/examples/text/font_size.rb +34 -0
  49. data/examples/{kerning.rb → text/kerning.rb} +5 -1
  50. data/examples/text/simple_text.rb +18 -0
  51. data/examples/text/simple_text_ttf.rb +18 -0
  52. data/examples/{span.rb → text/span.rb} +5 -2
  53. data/examples/text/text_box.rb +26 -0
  54. data/examples/{text_flow.rb → text/text_flow.rb} +5 -2
  55. data/lib/prawn.rb +26 -20
  56. data/lib/prawn/compatibility.rb +5 -8
  57. data/lib/prawn/document.rb +29 -13
  58. data/lib/prawn/document/annotations.rb +63 -0
  59. data/lib/prawn/document/bounding_box.rb +18 -3
  60. data/lib/prawn/document/destinations.rb +81 -0
  61. data/lib/prawn/document/internals.rb +16 -2
  62. data/lib/prawn/document/page_geometry.rb +58 -57
  63. data/lib/prawn/document/span.rb +8 -0
  64. data/lib/prawn/document/table.rb +81 -31
  65. data/lib/prawn/document/text.rb +66 -21
  66. data/lib/prawn/document/text/box.rb +77 -0
  67. data/lib/prawn/encoding.rb +121 -0
  68. data/lib/prawn/errors.rb +4 -0
  69. data/lib/prawn/font.rb +70 -42
  70. data/lib/prawn/font/metrics.rb +64 -119
  71. data/lib/prawn/graphics.rb +105 -87
  72. data/lib/prawn/graphics/cell.rb +55 -28
  73. data/lib/prawn/graphics/color.rb +8 -0
  74. data/lib/prawn/images.rb +55 -12
  75. data/lib/prawn/images/jpg.rb +2 -1
  76. data/lib/prawn/images/png.rb +2 -1
  77. data/lib/prawn/literal_string.rb +14 -0
  78. data/lib/prawn/measurement_extensions.rb +46 -0
  79. data/lib/prawn/measurements.rb +71 -0
  80. data/lib/prawn/name_tree.rb +165 -0
  81. data/lib/prawn/pdf_object.rb +8 -1
  82. data/spec/annotations_spec.rb +90 -0
  83. data/spec/destinations_spec.rb +15 -0
  84. data/spec/document_spec.rb +39 -2
  85. data/spec/font_spec.rb +22 -0
  86. data/spec/graphics_spec.rb +99 -87
  87. data/spec/images_spec.rb +29 -1
  88. data/spec/measurement_units_spec.rb +23 -0
  89. data/spec/metrics_spec.rb +3 -2
  90. data/spec/name_tree_spec.rb +103 -0
  91. data/spec/pdf_object_spec.rb +15 -5
  92. data/spec/png_spec.rb +14 -14
  93. data/spec/spec_helper.rb +8 -6
  94. data/spec/table_spec.rb +40 -0
  95. data/spec/text_spec.rb +6 -4
  96. data/vendor/ttfunk/data/fonts/DejaVuSans.ttf +0 -0
  97. data/vendor/ttfunk/data/fonts/comicsans.ttf +0 -0
  98. data/vendor/ttfunk/example.rb +5 -0
  99. data/vendor/ttfunk/lib/ttfunk.rb +48 -0
  100. data/vendor/ttfunk/lib/ttfunk/table.rb +27 -0
  101. data/vendor/ttfunk/lib/ttfunk/table/cmap.rb +94 -0
  102. data/vendor/ttfunk/lib/ttfunk/table/directory.rb +25 -0
  103. data/vendor/ttfunk/lib/ttfunk/table/head.rb +25 -0
  104. data/vendor/ttfunk/lib/ttfunk/table/hhea.rb +27 -0
  105. data/vendor/ttfunk/lib/ttfunk/table/hmtx.rb +20 -0
  106. data/vendor/ttfunk/lib/ttfunk/table/kern.rb +48 -0
  107. data/vendor/ttfunk/lib/ttfunk/table/maxp.rb +17 -0
  108. data/vendor/ttfunk/lib/ttfunk/table/name.rb +52 -0
  109. metadata +93 -62
  110. data/examples/bounding_boxes.rb +0 -30
  111. data/examples/curves.rb +0 -10
  112. data/examples/family_based_styling.rb +0 -21
  113. data/examples/font_size.rb +0 -19
  114. data/examples/image2.rb +0 -13
  115. data/examples/image_flow.rb +0 -29
  116. data/examples/lazy_bounding_boxes.rb +0 -19
  117. data/examples/remote_images.rb +0 -7
  118. data/examples/simple_text.rb +0 -15
  119. data/examples/simple_text_ttf.rb +0 -16
  120. data/examples/sjis.rb +0 -21
  121. data/examples/utf8.rb +0 -12
  122. data/vendor/font_ttf/ttf.rb +0 -20
  123. data/vendor/font_ttf/ttf/datatypes.rb +0 -189
  124. data/vendor/font_ttf/ttf/encodings.rb +0 -140
  125. data/vendor/font_ttf/ttf/exceptions.rb +0 -28
  126. data/vendor/font_ttf/ttf/file.rb +0 -290
  127. data/vendor/font_ttf/ttf/fontchunk.rb +0 -77
  128. data/vendor/font_ttf/ttf/table/cmap.rb +0 -408
  129. data/vendor/font_ttf/ttf/table/cvt.rb +0 -49
  130. data/vendor/font_ttf/ttf/table/fpgm.rb +0 -48
  131. data/vendor/font_ttf/ttf/table/gasp.rb +0 -88
  132. data/vendor/font_ttf/ttf/table/glyf.rb +0 -452
  133. data/vendor/font_ttf/ttf/table/head.rb +0 -86
  134. data/vendor/font_ttf/ttf/table/hhea.rb +0 -96
  135. data/vendor/font_ttf/ttf/table/hmtx.rb +0 -98
  136. data/vendor/font_ttf/ttf/table/kern.rb +0 -186
  137. data/vendor/font_ttf/ttf/table/loca.rb +0 -75
  138. data/vendor/font_ttf/ttf/table/maxp.rb +0 -81
  139. data/vendor/font_ttf/ttf/table/name.rb +0 -222
  140. data/vendor/font_ttf/ttf/table/os2.rb +0 -172
  141. data/vendor/font_ttf/ttf/table/post.rb +0 -120
  142. data/vendor/font_ttf/ttf/table/prep.rb +0 -27
  143. data/vendor/font_ttf/ttf/table/vhea.rb +0 -45
  144. data/vendor/font_ttf/ttf/table/vmtx.rb +0 -36
@@ -0,0 +1,63 @@
1
+ # encoding: utf-8
2
+
3
+ # annotations.rb : Implements low-level annotation support for PDF
4
+ #
5
+ # Copyright November 2008, Jamis Buck. All Rights Reserved.
6
+ #
7
+ # This is free software. Please see the LICENSE and COPYING files for details.
8
+
9
+ require 'prawn/literal_string'
10
+
11
+ module Prawn
12
+ class Document
13
+
14
+ # Provides very low-level support for annotations. Those who are
15
+ # interested should check out the text-format branch of sandal/prawn,
16
+ # which includes much higher level interfaces to this code currently
17
+ # being developed by Jamis Buck to be included in a Prawn release soon.
18
+ #
19
+ # Feedback is welcome!
20
+ #
21
+ module Annotations
22
+ # Adds a new annotation (section 8.4 in PDF spec) to the current page.
23
+ # +options+ must be a Hash describing the annotation.
24
+ def annotate(options)
25
+ @current_page.data[:Annots] ||= []
26
+ options = sanitize_annotation_hash(options)
27
+ @current_page.data[:Annots] << ref(options)
28
+ return options
29
+ end
30
+
31
+ # A convenience method for creating Text annotations. +rect+ must be an array
32
+ # of four numbers, describing the bounds of the annotation. +contents+ should
33
+ # be a string, to be shown when the annotation is activated.
34
+ def text_annotation(rect, contents, options={})
35
+ options = options.merge(:Subtype => :Text, :Rect => rect, :Contents => contents)
36
+ annotate(options)
37
+ end
38
+
39
+ # A convenience method for creating Link annotations. +rect+ must be an array
40
+ # of four numbers, describing the bounds of the annotation. The +options+ hash
41
+ # should include either :Dest (describing the target destination, usually as a
42
+ # string that has been recorded in the document's Dests tree), or :A (describing
43
+ # an action to perform on clicking the link), or :PA (for describing a URL to
44
+ # link to).
45
+ def link_annotation(rect, options={})
46
+ options = options.merge(:Subtype => :Link, :Rect => rect)
47
+ annotate(options)
48
+ end
49
+
50
+ private
51
+
52
+ def sanitize_annotation_hash(options)
53
+ options = options.merge(:Type => :Annot)
54
+
55
+ if options[:Dest].is_a?(String)
56
+ options[:Dest] = Prawn::LiteralString.new(options[:Dest])
57
+ end
58
+
59
+ options
60
+ end
61
+ end
62
+ end
63
+ end
@@ -1,5 +1,11 @@
1
1
  # encoding: utf-8
2
2
 
3
+ # bounding_box.rb : Implements a mechanism for shifting the coordinate space
4
+ #
5
+ # Copyright May 2008, Gregory Brown. All Rights Reserved.
6
+ #
7
+ # This is free software. Please see the LICENSE and COPYING files for details.
8
+
3
9
  module Prawn
4
10
  class Document
5
11
 
@@ -10,7 +16,7 @@ module Prawn
10
16
  #
11
17
  # When flowing text, the usage of a bounding box is simple. Text will
12
18
  # begin at the point specified, flowing the width of the bounding box.
13
- # After the block exits, the text drawing position will be moved to
19
+ # After the block exits, the cursor position will be moved to
14
20
  # the bottom of the bounding box (y - height). If flowing text exceeds
15
21
  # the height of the bounding box, the text will be continued on the next
16
22
  # page, starting again at the top-left corner of the bounding box.
@@ -135,12 +141,21 @@ module Prawn
135
141
  )
136
142
  end
137
143
  end
144
+
145
+ # A bounding box with the same dimensions of its parents, minus a margin
146
+ # on all sides
147
+ #
148
+ def padded_box(margin, &block)
149
+ bounding_box [bounds.left + margin, bounds.top - margin],
150
+ :width => bounds.width - (margin * 2),
151
+ :height => bounds.height - (margin * 2), &block
152
+ end
138
153
 
139
154
  # A header is a LazyBoundingBox drawn relative to the margins that can be
140
155
  # repeated on every page of the document.
141
156
  #
142
157
  # Unless <tt>:width</tt> or <tt>:height</tt> are specified, the margin_box
143
- # width and height
158
+ # width and height are used.
144
159
  #
145
160
  # header margin_box.top_left do
146
161
  # text "Here's My Fancy Header", :size => 25, :align => :center
@@ -155,7 +170,7 @@ module Prawn
155
170
  # repeated on every page of the document.
156
171
  #
157
172
  # Unless <tt>:width</tt> or <tt>:height</tt> are specified, the margin_box
158
- # width and height
173
+ # width and height are used.
159
174
  #
160
175
  # footer [margin_box.left, margin_box.bottom + 25] do
161
176
  # stroke_horizontal_rule
@@ -0,0 +1,81 @@
1
+ # encoding: utf-8
2
+
3
+ # annotations.rb : Implements destination support for PDF
4
+ #
5
+ # Copyright November 2008, Jamis Buck. All Rights Reserved.
6
+ #
7
+ # This is free software. Please see the LICENSE and COPYING files for details.
8
+ #
9
+ require 'prawn/name_tree'
10
+
11
+ module Prawn
12
+ class Document
13
+ module Destinations
14
+ # The maximum number of children to fit into a single node in the Dests tree.
15
+ NAME_TREE_CHILDREN_LIMIT = 20 #:nodoc:
16
+
17
+ # The Dests name tree in the Name dictionary (see Prawn::Document::Internal#names).
18
+ # This name tree is used to store named destinations (PDF spec 8.2.1).
19
+ # (For more on name trees, see section 3.8.4 in the PDF spec.)
20
+ def dests
21
+ names.data[:Dests] ||= ref(Prawn::NameTree::Node.new(self, NAME_TREE_CHILDREN_LIMIT))
22
+ end
23
+
24
+ # Adds a new destination to the dests name tree (see #dests). The
25
+ # +reference+ parameter will be converted into a Prawn::Reference if
26
+ # it is not already one.
27
+ def add_dest(name, reference)
28
+ reference = ref(reference) unless reference.is_a?(Prawn::Reference)
29
+ dests.data.add(name, reference)
30
+ end
31
+
32
+ # Return a Dest specification for a specific location (and optional zoom
33
+ # level).
34
+ def dest_xyz(left, top, zoom=nil, page=@current_page)
35
+ [page, :XYZ, left, top, zoom]
36
+ end
37
+
38
+ # Return a Dest specification that will fit the given page into the
39
+ # viewport.
40
+ def dest_fit(page=@current_page)
41
+ [page, :Fit]
42
+ end
43
+
44
+ # Return a Dest specification that will fit the given page horizontally
45
+ # into the viewport, aligned vertically at the given top coordinate.
46
+ def dest_fit_horizontally(top, page=@current_page)
47
+ [page, :FitH, top]
48
+ end
49
+
50
+ # Return a Dest specification that will fit the given page vertically
51
+ # into the viewport, aligned horizontally at the given left coordinate.
52
+ def dest_fit_vertically(left, page=@current_page)
53
+ [page, :FitV, left]
54
+ end
55
+
56
+ # Return a Dest specification that will fit the given rectangle into the
57
+ # viewport, for the given page.
58
+ def dest_fit_rect(left, bottom, right, top, page=@current_page)
59
+ [page, :FitR, left, bottom, right, top]
60
+ end
61
+
62
+ # Return a Dest specfication that will fit the given page's bounding box
63
+ # into the viewport.
64
+ def dest_fit_bounds(page=@current_page)
65
+ [page, :FitB]
66
+ end
67
+
68
+ # Same as #dest_fit_horizontally, but works on the page's bounding box
69
+ # instead of the entire page.
70
+ def dest_fit_bounds_horizontally(top, page=@current_page)
71
+ [page, :FitBH, top]
72
+ end
73
+
74
+ # Same as #dest_fit_vertically, but works on the page's bounding box
75
+ # instead of the entire page.
76
+ def dest_fit_bounds_vertically(left, page=@current_page)
77
+ [page, :FitBV, left]
78
+ end
79
+ end
80
+ end
81
+ end
@@ -1,3 +1,11 @@
1
+ # encoding: utf-8
2
+ #
3
+ # internals.rb : Implements document internals for Prawn
4
+ #
5
+ # Copyright August 2008, Gregory Brown. All Rights Reserved.
6
+ #
7
+ # This is free software. Please see the LICENSE and COPYING files for details.
8
+
1
9
  module Prawn
2
10
  class Document
3
11
 
@@ -7,7 +15,6 @@ module Prawn
7
15
  # are you won't need anything you find here.
8
16
  #
9
17
  module Internals
10
-
11
18
  # Creates a new Prawn::Reference and adds it to the Document's object
12
19
  # list. The +data+ argument is anything that Prawn::PdfObject() can convert.
13
20
  def ref(data)
@@ -50,6 +57,13 @@ module Prawn
50
57
  page_resources[:XObject] ||= {}
51
58
  end
52
59
 
60
+ # The Name dictionary (PDF spec 3.6.3) for this document. It is
61
+ # lazily initialized, so that documents that do not need a name
62
+ # dictionary do not incur the additional overhead.
63
+ def names
64
+ @root.data[:Names] ||= ref(:Type => :Names)
65
+ end
66
+
53
67
  private
54
68
 
55
69
  def finish_page_content
@@ -104,4 +118,4 @@ module Prawn
104
118
 
105
119
  end
106
120
  end
107
- end
121
+ end
@@ -9,70 +9,71 @@
9
9
  module Prawn
10
10
  class Document
11
11
  module PageGeometry
12
-
12
+
13
13
  # Dimensions pulled from PDF::Writer, rubyforge.org/projects/ruby-pdf
14
- SIZES = { "4A0" => [4767.87, 6740.79],
15
- "2A0" => [3370.39, 4767.87],
16
- "A0" => [2383.94, 3370.39],
17
- "A1" => [1683.78, 2383.94],
18
- "A2" => [1190.55, 1683.78],
19
- "A3" => [841.89, 1190.55],
20
- "A4" => [595.28, 841.89],
21
- "A5" => [419.53, 595.28],
22
- "A6" => [297.64, 419.53],
23
- "A7" => [209.76, 297.64],
24
- "A8" => [147.40, 209.76],
25
- "A9" => [104.88, 147.40],
26
- "A10" => [73.70, 104.88],
27
- "B0" => [2834.65, 4008.19],
28
- "B1" => [2004.09, 2834.65],
29
- "B2" => [1417.32, 2004.09],
30
- "B3" => [1000.63, 1417.32],
31
- "B4" => [708.66, 1000.63],
32
- "B5" => [498.90, 708.66],
33
- "B6" => [354.33, 498.90],
34
- "B7" => [249.45, 354.33],
35
- "B8" => [175.75, 249.45],
36
- "B9" => [124.72, 175.75],
37
- "B10" => [87.87, 124.72],
38
- "C0" => [2599.37, 3676.54],
39
- "C1" => [1836.85, 2599.37],
40
- "C2" => [1298.27, 1836.85],
41
- "C3" => [918.43, 1298.27],
42
- "C4" => [649.13, 918.43],
43
- "C5" => [459.21, 649.13],
44
- "C6" => [323.15, 459.21],
45
- "C7" => [229.61, 323.15],
46
- "C8" => [161.57, 229.61],
47
- "C9" => [113.39, 161.57],
48
- "C10" => [79.37, 113.39],
49
- "RA0" => [2437.80, 3458.27],
50
- "RA1" => [1729.13, 2437.80],
51
- "RA2" => [1218.90, 1729.13],
52
- "RA3" => [864.57, 1218.90],
53
- "RA4" => [609.45, 864.57],
54
- "SRA0" => [2551.18, 3628.35],
55
- "SRA1" => [1814.17, 2551.18],
56
- "SRA2" => [1275.59, 1814.17],
57
- "SRA3" => [907.09, 1275.59],
58
- "SRA4" => [637.80, 907.09],
59
- "LETTER" => [612.00, 792.00],
60
- "LEGAL" => [612.00, 1008.00],
61
- "FOLIO" => [612.00, 936.00],
62
- "EXECUTIVE" => [521.86, 756.00] }
63
-
14
+ SIZES = { "4A0" => [4767.87, 6740.79],
15
+ "2A0" => [3370.39, 4767.87],
16
+ "A0" => [2383.94, 3370.39],
17
+ "A1" => [1683.78, 2383.94],
18
+ "A2" => [1190.55, 1683.78],
19
+ "A3" => [841.89, 1190.55],
20
+ "A4" => [595.28, 841.89],
21
+ "A5" => [419.53, 595.28],
22
+ "A6" => [297.64, 419.53],
23
+ "A7" => [209.76, 297.64],
24
+ "A8" => [147.40, 209.76],
25
+ "A9" => [104.88, 147.40],
26
+ "A10" => [73.70, 104.88],
27
+ "B0" => [2834.65, 4008.19],
28
+ "B1" => [2004.09, 2834.65],
29
+ "B2" => [1417.32, 2004.09],
30
+ "B3" => [1000.63, 1417.32],
31
+ "B4" => [708.66, 1000.63],
32
+ "B5" => [498.90, 708.66],
33
+ "B6" => [354.33, 498.90],
34
+ "B7" => [249.45, 354.33],
35
+ "B8" => [175.75, 249.45],
36
+ "B9" => [124.72, 175.75],
37
+ "B10" => [87.87, 124.72],
38
+ "C0" => [2599.37, 3676.54],
39
+ "C1" => [1836.85, 2599.37],
40
+ "C2" => [1298.27, 1836.85],
41
+ "C3" => [918.43, 1298.27],
42
+ "C4" => [649.13, 918.43],
43
+ "C5" => [459.21, 649.13],
44
+ "C6" => [323.15, 459.21],
45
+ "C7" => [229.61, 323.15],
46
+ "C8" => [161.57, 229.61],
47
+ "C9" => [113.39, 161.57],
48
+ "C10" => [79.37, 113.39],
49
+ "RA0" => [2437.80, 3458.27],
50
+ "RA1" => [1729.13, 2437.80],
51
+ "RA2" => [1218.90, 1729.13],
52
+ "RA3" => [864.57, 1218.90],
53
+ "RA4" => [609.45, 864.57],
54
+ "SRA0" => [2551.18, 3628.35],
55
+ "SRA1" => [1814.17, 2551.18],
56
+ "SRA2" => [1275.59, 1814.17],
57
+ "SRA3" => [907.09, 1275.59],
58
+ "SRA4" => [637.80, 907.09],
59
+ "EXECUTIVE" => [521.86, 756.00],
60
+ "FOLIO" => [612.00, 936.00],
61
+ "LEGAL" => [612.00, 1008.00],
62
+ "LETTER" => [612.00, 792.00],
63
+ "TABLOID" => [792.00, 1224.00] }
64
+
64
65
  def page_dimensions #:nodoc:
65
66
  coords = SIZES[page_size] || page_size
66
- [0,0] + case(page_layout)
67
+ [0,0] + case(page_layout)
67
68
  when :portrait
68
69
  coords
69
70
  when :landscape
70
- coords.reverse
71
- else
72
- raise Prawn::Errors::InvalidPageLayout,
71
+ coords.reverse
72
+ else
73
+ raise Prawn::Errors::InvalidPageLayout,
73
74
  "Layout must be either :portrait or :landscape"
74
75
  end
75
- end
76
- end
76
+ end
77
+ end
77
78
  end
78
79
  end
@@ -1,3 +1,11 @@
1
+ # encoding: utf-8
2
+
3
+ # span.rb : Implements text columns
4
+ #
5
+ # Copyright September 2008, Gregory Brown. All Rights Reserved.
6
+ #
7
+ # This is free software. Please see the LICENSE and COPYING files for details.
8
+
1
9
  module Prawn
2
10
  class Document
3
11
  # A span is a special purpose bounding box that allows a column of
@@ -37,7 +37,14 @@ module Prawn
37
37
  #
38
38
  # end
39
39
  #
40
+ # Will raise <tt>Prawn::Errors::EmptyTable</tt> given
41
+ # a nil or empty <tt>data</tt> paramater.
42
+ #
40
43
  def table(data,options={})
44
+ if data.nil? || data.empty?
45
+ raise Prawn::Errors::EmptyTable,
46
+ "data must be a non-empty, non-nil, two dimensional array of Prawn::Cells or strings"
47
+ end
41
48
  Prawn::Document::Table.new(data,self,options).draw
42
49
  end
43
50
 
@@ -80,17 +87,22 @@ module Prawn
80
87
  # The following options are available for customizing your tables, with
81
88
  # defaults shown in [] at the end of each description.
82
89
  #
90
+ # <tt>:headers</tt>:: An array of table headers, either strings or Cells. [Empty]
91
+ # <tt>:align_headers</tt>:: Alignment of header text. Specify for entire header (<tt>:left</tt>) or by column (<tt>{ 0 => :right, 1 => :left}</tt>). If omitted, the header alignment is the same as the column alignment.
92
+ # <tt>:header_text_color</tt>:: Sets the text color of the headers
93
+ # <tt>:header_color</tt>:: Manually sets the header color
83
94
  # <tt>:font_size</tt>:: The font size for the text cells . [12]
84
95
  # <tt>:horizontal_padding</tt>:: The horizontal cell padding in PDF points [5]
85
96
  # <tt>:vertical_padding</tt>:: The vertical cell padding in PDF points [5]
86
97
  # <tt>:padding</tt>:: Horizontal and vertical cell padding (overrides both)
87
98
  # <tt>:border_width</tt>:: With of border lines in PDF points [1]
88
- # <tt>:border_style</tt>:: If set to :grid, fills in all borders. Otherwise, borders are drawn on columns only, not rows
99
+ # <tt>:border_style</tt>:: If set to :grid, fills in all borders. If set to :underline_header, underline header only. Otherwise, borders are drawn on columns only, not rows
100
+ # <tt>:border_color</tt>:: Sets the color of the borders.
89
101
  # <tt>:position</tt>:: One of <tt>:left</tt>, <tt>:center</tt> or <tt>n</tt>, where <tt>n</tt> is an x-offset from the left edge of the current bounding box
90
102
  # <tt>:widths:</tt> A hash of indices and widths in PDF points. E.g. <tt>{ 0 => 50, 1 => 100 }</tt>
91
103
  # <tt>:row_colors</tt>:: An array of row background colors which are used cyclicly.
92
104
  # <tt>:align</tt>:: Alignment of text in columns, for entire table (<tt>:center</tt>) or by column (<tt>{ 0 => :left, 1 => :center}</tt>)
93
- # <tt>:align_headers</tt>:: Alignment of header text.
105
+ # <tt>:minimum_rows</tt>:: The minimum rows to display on a page, including header.
94
106
  #
95
107
  # Row colors are specified as html encoded values, e.g.
96
108
  # ["ffffff","aaaaaa","ccaaff"]. You can also specify
@@ -110,8 +122,9 @@ module Prawn
110
122
  @document = document
111
123
 
112
124
  Prawn.verify_options [:font_size,:border_style, :border_width,
113
- :position, :headers, :row_colors, :align, :align_headers,
114
- :horizontal_padding, :vertical_padding, :padding, :widths ], options
125
+ :position, :headers, :row_colors, :align, :align_headers, :header_text_color, :border_color,
126
+ :horizontal_padding, :vertical_padding, :padding, :widths,
127
+ :header_color ], options
115
128
 
116
129
  configuration.update(options)
117
130
 
@@ -193,10 +206,12 @@ module Prawn
193
206
  @document.font.size C(:font_size) do
194
207
  renderable_data.each_with_index do |row,index|
195
208
  c = Prawn::Graphics::CellBlock.new(@document)
196
- row.each_with_index do |e,i|
209
+
210
+ col_index = 0
211
+ row.each do |e|
197
212
  case C(:align)
198
213
  when Hash
199
- align = C(:align)[i]
214
+ align = C(:align)[col_index]
200
215
  else
201
216
  align = C(:align)
202
217
  end
@@ -207,7 +222,7 @@ module Prawn
207
222
  case e
208
223
  when Prawn::Graphics::Cell
209
224
  e.document = @document
210
- e.width = @col_widths[i]
225
+ e.width = @col_widths[col_index]
211
226
  e.horizontal_padding = C(:horizontal_padding)
212
227
  e.vertical_padding = C(:vertical_padding)
213
228
  e.border_width = C(:border_width)
@@ -215,28 +230,42 @@ module Prawn
215
230
  e.align = align
216
231
  c << e
217
232
  else
233
+ text = e.is_a?(Hash) ? e[:text] : e.to_s
234
+ width = if e.is_a?(Hash) && e.has_key?(:colspan)
235
+ @col_widths.slice(col_index, e[:colspan]).inject { |sum, width| sum + width }
236
+ else
237
+ @col_widths[col_index]
238
+ end
239
+
218
240
  c << Prawn::Graphics::Cell.new(
219
241
  :document => @document,
220
- :text => e.to_s,
221
- :width => @col_widths[i],
242
+ :text => text,
243
+ :width => width,
222
244
  :horizontal_padding => C(:horizontal_padding),
223
245
  :vertical_padding => C(:vertical_padding),
224
246
  :border_width => C(:border_width),
225
247
  :border_style => :sides,
226
248
  :align => align )
227
- end
249
+ end
250
+
251
+ col_index += (e.is_a?(Hash) && e.has_key?(:colspan)) ? e[:colspan] : 1
228
252
  end
229
253
 
230
254
  bbox = @parent_bounds.stretchy? ? @document.margin_box : @parent_bounds
231
255
  if c.height > y_pos - bbox.absolute_bottom
232
- draw_page(page_contents)
233
- @document.start_new_page
234
- if C(:headers)
235
- page_contents = [page_contents[0]]
236
- y_pos = @document.y - page_contents[0].height
237
- else
238
- page_contents = []
256
+ if C(:headers) && page_contents.length == 1
257
+ @document.start_new_page
239
258
  y_pos = @document.y
259
+ else
260
+ draw_page(page_contents)
261
+ @document.start_new_page
262
+ if C(:headers) && page_contents.any?
263
+ page_contents = [page_contents[0]]
264
+ y_pos = @document.y - page_contents[0].height
265
+ else
266
+ page_contents = []
267
+ y_pos = @document.y
268
+ end
240
269
  end
241
270
  end
242
271
 
@@ -254,29 +283,50 @@ module Prawn
254
283
 
255
284
  def draw_page(contents)
256
285
  return if contents.empty?
257
-
258
- if C(:border_style) == :grid || contents.length == 1
286
+
287
+ if C(:border_style) == :underline_header
288
+ contents.each { |e| e.border_style = :none }
289
+ contents.first.border_style = :bottom_only if C(:headers)
290
+ elsif C(:border_style) == :grid || contents.length == 1
259
291
  contents.each { |e| e.border_style = :all }
260
- else
261
- if C(:headers)
262
- contents.first.border_style = :all
263
- contents.first.align = C(:align_headers) || :left
264
- else
265
- contents.first.border_style = :no_bottom
292
+ else
293
+ contents.first.border_style = C(:headers) ? :all : :no_bottom
294
+ contents.last.border_style = :no_top
295
+ end
296
+
297
+ if C(:headers)
298
+ contents.first.cells.each_with_index do |e,i|
299
+ if C(:align_headers)
300
+ case C(:align_headers)
301
+ when Hash
302
+ align = C(:align_headers)[i]
303
+ else
304
+ align = C(:align_headers)
305
+ end
306
+ end
307
+ e.align = align if align
308
+ e.text_color = C(:header_text_color) if C(:header_text_color)
309
+ e.background_color = C(:header_color) if C(:header_color)
266
310
  end
267
- contents.last.border_style = :no_top
268
311
  end
269
-
270
- contents.each do |x|
271
- x.background_color = next_row_color if C(:row_colors)
312
+
313
+ contents.each do |x|
314
+ unless x.background_color
315
+ x.background_color = next_row_color if C(:row_colors)
316
+ end
317
+ x.border_color = C(:border_color) if C(:border_color)
318
+
272
319
  x.draw
273
320
  end
274
-
321
+
275
322
  reset_row_colors
276
323
  end
277
324
 
325
+
278
326
  def next_row_color
279
- C(:row_colors).unshift(C(:row_colors).pop).last
327
+ color = C(:row_colors).shift
328
+ C(:row_colors).push(color)
329
+ color
280
330
  end
281
331
 
282
332
  def reset_row_colors