prawn 0.2.3 → 0.3.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 (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