prawn-git 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (252) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +10 -0
  3. data/COPYING +2 -0
  4. data/GPLv2 +340 -0
  5. data/GPLv3 +674 -0
  6. data/Gemfile +11 -0
  7. data/LICENSE +56 -0
  8. data/Rakefile +55 -0
  9. data/data/fonts/Courier-Bold.afm +342 -0
  10. data/data/fonts/Courier-BoldOblique.afm +342 -0
  11. data/data/fonts/Courier-Oblique.afm +342 -0
  12. data/data/fonts/Courier.afm +342 -0
  13. data/data/fonts/Helvetica-Bold.afm +2827 -0
  14. data/data/fonts/Helvetica-BoldOblique.afm +2827 -0
  15. data/data/fonts/Helvetica-Oblique.afm +3051 -0
  16. data/data/fonts/Helvetica.afm +3051 -0
  17. data/data/fonts/MustRead.html +19 -0
  18. data/data/fonts/Symbol.afm +213 -0
  19. data/data/fonts/Times-Bold.afm +2588 -0
  20. data/data/fonts/Times-BoldItalic.afm +2384 -0
  21. data/data/fonts/Times-Italic.afm +2667 -0
  22. data/data/fonts/Times-Roman.afm +2419 -0
  23. data/data/fonts/ZapfDingbats.afm +225 -0
  24. data/data/images/16bit.alpha +0 -0
  25. data/data/images/16bit.color +0 -0
  26. data/data/images/16bit.png +0 -0
  27. data/data/images/arrow.png +0 -0
  28. data/data/images/arrow2.png +0 -0
  29. data/data/images/dice.alpha +0 -0
  30. data/data/images/dice.color +0 -0
  31. data/data/images/dice.png +0 -0
  32. data/data/images/dice_interlaced.png +0 -0
  33. data/data/images/fractal.jpg +0 -0
  34. data/data/images/indexed_color.dat +0 -0
  35. data/data/images/indexed_color.png +0 -0
  36. data/data/images/letterhead.jpg +0 -0
  37. data/data/images/license.md +8 -0
  38. data/data/images/page_white_text.alpha +0 -0
  39. data/data/images/page_white_text.color +0 -0
  40. data/data/images/page_white_text.png +0 -0
  41. data/data/images/pal_bk.png +0 -0
  42. data/data/images/pigs.jpg +0 -0
  43. data/data/images/prawn.png +0 -0
  44. data/data/images/ruport.png +0 -0
  45. data/data/images/ruport_data.dat +0 -0
  46. data/data/images/ruport_transparent.png +0 -0
  47. data/data/images/ruport_type0.png +0 -0
  48. data/data/images/stef.jpg +0 -0
  49. data/data/images/tru256.bmp +0 -0
  50. data/data/images/web-links.dat +1 -0
  51. data/data/images/web-links.png +0 -0
  52. data/data/pdfs/complex_template.pdf +0 -0
  53. data/data/pdfs/contains_ttf_font.pdf +0 -0
  54. data/data/pdfs/encrypted.pdf +0 -0
  55. data/data/pdfs/form.pdf +820 -0
  56. data/data/pdfs/hexagon.pdf +61 -0
  57. data/data/pdfs/indirect_reference.pdf +86 -0
  58. data/data/pdfs/multipage_template.pdf +127 -0
  59. data/data/pdfs/nested_pages.pdf +118 -0
  60. data/data/pdfs/page_without_mediabox.pdf +193 -0
  61. data/data/pdfs/resources_as_indirect_object.pdf +83 -0
  62. data/data/pdfs/two_hexagons.pdf +90 -0
  63. data/data/pdfs/version_1_6.pdf +61 -0
  64. data/data/shift_jis_text.txt +1 -0
  65. data/lib/prawn.rb +89 -0
  66. data/lib/prawn/document.rb +706 -0
  67. data/lib/prawn/document/bounding_box.rb +539 -0
  68. data/lib/prawn/document/column_box.rb +144 -0
  69. data/lib/prawn/document/internals.rb +58 -0
  70. data/lib/prawn/document/span.rb +57 -0
  71. data/lib/prawn/encoding.rb +87 -0
  72. data/lib/prawn/errors.rb +80 -0
  73. data/lib/prawn/font.rb +413 -0
  74. data/lib/prawn/font/afm.rb +256 -0
  75. data/lib/prawn/font/dfont.rb +43 -0
  76. data/lib/prawn/font/ttf.rb +355 -0
  77. data/lib/prawn/font_metric_cache.rb +46 -0
  78. data/lib/prawn/graphics.rb +646 -0
  79. data/lib/prawn/graphics/cap_style.rb +47 -0
  80. data/lib/prawn/graphics/color.rb +232 -0
  81. data/lib/prawn/graphics/dash.rb +109 -0
  82. data/lib/prawn/graphics/join_style.rb +49 -0
  83. data/lib/prawn/graphics/patterns.rb +126 -0
  84. data/lib/prawn/graphics/transformation.rb +157 -0
  85. data/lib/prawn/graphics/transparency.rb +101 -0
  86. data/lib/prawn/grid.rb +279 -0
  87. data/lib/prawn/image_handler.rb +44 -0
  88. data/lib/prawn/images.rb +199 -0
  89. data/lib/prawn/images/image.rb +49 -0
  90. data/lib/prawn/images/jpg.rb +91 -0
  91. data/lib/prawn/images/png.rb +290 -0
  92. data/lib/prawn/measurement_extensions.rb +50 -0
  93. data/lib/prawn/measurements.rb +77 -0
  94. data/lib/prawn/outline.rb +289 -0
  95. data/lib/prawn/repeater.rb +124 -0
  96. data/lib/prawn/security.rb +288 -0
  97. data/lib/prawn/security/arcfour.rb +54 -0
  98. data/lib/prawn/soft_mask.rb +94 -0
  99. data/lib/prawn/stamp.rb +136 -0
  100. data/lib/prawn/text.rb +437 -0
  101. data/lib/prawn/text/box.rb +141 -0
  102. data/lib/prawn/text/formatted.rb +7 -0
  103. data/lib/prawn/text/formatted/arranger.rb +290 -0
  104. data/lib/prawn/text/formatted/box.rb +614 -0
  105. data/lib/prawn/text/formatted/fragment.rb +264 -0
  106. data/lib/prawn/text/formatted/line_wrap.rb +277 -0
  107. data/lib/prawn/text/formatted/parser.rb +224 -0
  108. data/lib/prawn/text/formatted/wrap.rb +160 -0
  109. data/lib/prawn/utilities.rb +46 -0
  110. data/lib/prawn/version.rb +5 -0
  111. data/lib/prawn/view.rb +91 -0
  112. data/manual/absolute_position.pdf +0 -0
  113. data/manual/basic_concepts/adding_pages.rb +27 -0
  114. data/manual/basic_concepts/basic_concepts.rb +36 -0
  115. data/manual/basic_concepts/creation.rb +39 -0
  116. data/manual/basic_concepts/cursor.rb +33 -0
  117. data/manual/basic_concepts/measurement.rb +25 -0
  118. data/manual/basic_concepts/origin.rb +38 -0
  119. data/manual/basic_concepts/other_cursor_helpers.rb +40 -0
  120. data/manual/basic_concepts/view.rb +42 -0
  121. data/manual/bounding_box/bounding_box.rb +39 -0
  122. data/manual/bounding_box/bounds.rb +49 -0
  123. data/manual/bounding_box/canvas.rb +24 -0
  124. data/manual/bounding_box/creation.rb +23 -0
  125. data/manual/bounding_box/indentation.rb +46 -0
  126. data/manual/bounding_box/nesting.rb +45 -0
  127. data/manual/bounding_box/russian_boxes.rb +40 -0
  128. data/manual/bounding_box/stretchy.rb +31 -0
  129. data/manual/contents.rb +29 -0
  130. data/manual/cover.rb +39 -0
  131. data/manual/document_and_page_options/background.rb +27 -0
  132. data/manual/document_and_page_options/document_and_page_options.rb +32 -0
  133. data/manual/document_and_page_options/metadata.rb +23 -0
  134. data/manual/document_and_page_options/page_margins.rb +38 -0
  135. data/manual/document_and_page_options/page_size.rb +34 -0
  136. data/manual/document_and_page_options/print_scaling.rb +20 -0
  137. data/manual/example_helper.rb +7 -0
  138. data/manual/graphics/circle_and_ellipse.rb +22 -0
  139. data/manual/graphics/color.rb +24 -0
  140. data/manual/graphics/common_lines.rb +30 -0
  141. data/manual/graphics/fill_and_stroke.rb +42 -0
  142. data/manual/graphics/fill_rules.rb +37 -0
  143. data/manual/graphics/gradients.rb +37 -0
  144. data/manual/graphics/graphics.rb +58 -0
  145. data/manual/graphics/helper.rb +24 -0
  146. data/manual/graphics/line_width.rb +35 -0
  147. data/manual/graphics/lines_and_curves.rb +41 -0
  148. data/manual/graphics/polygon.rb +29 -0
  149. data/manual/graphics/rectangle.rb +21 -0
  150. data/manual/graphics/rotate.rb +28 -0
  151. data/manual/graphics/scale.rb +41 -0
  152. data/manual/graphics/soft_masks.rb +46 -0
  153. data/manual/graphics/stroke_cap.rb +31 -0
  154. data/manual/graphics/stroke_dash.rb +48 -0
  155. data/manual/graphics/stroke_join.rb +30 -0
  156. data/manual/graphics/translate.rb +29 -0
  157. data/manual/graphics/transparency.rb +35 -0
  158. data/manual/how_to_read_this_manual.rb +40 -0
  159. data/manual/images/absolute_position.rb +23 -0
  160. data/manual/images/fit.rb +21 -0
  161. data/manual/images/horizontal.rb +25 -0
  162. data/manual/images/images.rb +40 -0
  163. data/manual/images/plain_image.rb +18 -0
  164. data/manual/images/scale.rb +22 -0
  165. data/manual/images/vertical.rb +28 -0
  166. data/manual/images/width_and_height.rb +25 -0
  167. data/manual/layout/boxes.rb +27 -0
  168. data/manual/layout/content.rb +25 -0
  169. data/manual/layout/layout.rb +28 -0
  170. data/manual/layout/simple_grid.rb +23 -0
  171. data/manual/outline/add_subsection_to.rb +61 -0
  172. data/manual/outline/insert_section_after.rb +47 -0
  173. data/manual/outline/outline.rb +32 -0
  174. data/manual/outline/sections_and_pages.rb +67 -0
  175. data/manual/repeatable_content/alternate_page_numbering.rb +32 -0
  176. data/manual/repeatable_content/page_numbering.rb +54 -0
  177. data/manual/repeatable_content/repeatable_content.rb +32 -0
  178. data/manual/repeatable_content/repeater.rb +55 -0
  179. data/manual/repeatable_content/stamp.rb +41 -0
  180. data/manual/security/encryption.rb +31 -0
  181. data/manual/security/permissions.rb +38 -0
  182. data/manual/security/security.rb +28 -0
  183. data/manual/table.rb +16 -0
  184. data/manual/text/alignment.rb +44 -0
  185. data/manual/text/color.rb +24 -0
  186. data/manual/text/column_box.rb +32 -0
  187. data/manual/text/fallback_fonts.rb +37 -0
  188. data/manual/text/font.rb +41 -0
  189. data/manual/text/font_size.rb +45 -0
  190. data/manual/text/font_style.rb +23 -0
  191. data/manual/text/formatted_callbacks.rb +60 -0
  192. data/manual/text/formatted_text.rb +50 -0
  193. data/manual/text/free_flowing_text.rb +51 -0
  194. data/manual/text/inline.rb +41 -0
  195. data/manual/text/kerning_and_character_spacing.rb +39 -0
  196. data/manual/text/leading.rb +25 -0
  197. data/manual/text/line_wrapping.rb +41 -0
  198. data/manual/text/paragraph_indentation.rb +34 -0
  199. data/manual/text/positioned_text.rb +38 -0
  200. data/manual/text/registering_families.rb +48 -0
  201. data/manual/text/rendering_and_color.rb +37 -0
  202. data/manual/text/right_to_left_text.rb +47 -0
  203. data/manual/text/rotation.rb +43 -0
  204. data/manual/text/single_usage.rb +37 -0
  205. data/manual/text/text.rb +73 -0
  206. data/manual/text/text_box_excess.rb +32 -0
  207. data/manual/text/text_box_extensions.rb +45 -0
  208. data/manual/text/text_box_overflow.rb +48 -0
  209. data/manual/text/utf8.rb +28 -0
  210. data/manual/text/win_ansi_charset.rb +60 -0
  211. data/prawn.gemspec +45 -0
  212. data/spec/acceptance/png.rb +25 -0
  213. data/spec/annotations_spec.rb +74 -0
  214. data/spec/bounding_box_spec.rb +510 -0
  215. data/spec/column_box_spec.rb +65 -0
  216. data/spec/data/curves.pdf +66 -0
  217. data/spec/destinations_spec.rb +15 -0
  218. data/spec/document_spec.rb +748 -0
  219. data/spec/extensions/encoding_helpers.rb +11 -0
  220. data/spec/extensions/mocha.rb +46 -0
  221. data/spec/font_metric_cache_spec.rb +52 -0
  222. data/spec/font_spec.rb +474 -0
  223. data/spec/formatted_text_arranger_spec.rb +421 -0
  224. data/spec/formatted_text_box_spec.rb +705 -0
  225. data/spec/formatted_text_fragment_spec.rb +298 -0
  226. data/spec/graphics_spec.rb +683 -0
  227. data/spec/grid_spec.rb +96 -0
  228. data/spec/image_handler_spec.rb +54 -0
  229. data/spec/images_spec.rb +153 -0
  230. data/spec/inline_formatted_text_parser_spec.rb +564 -0
  231. data/spec/jpg_spec.rb +25 -0
  232. data/spec/line_wrap_spec.rb +367 -0
  233. data/spec/measurement_units_spec.rb +25 -0
  234. data/spec/outline_spec.rb +430 -0
  235. data/spec/png_spec.rb +245 -0
  236. data/spec/reference_spec.rb +25 -0
  237. data/spec/repeater_spec.rb +160 -0
  238. data/spec/security_spec.rb +158 -0
  239. data/spec/soft_mask_spec.rb +79 -0
  240. data/spec/span_spec.rb +44 -0
  241. data/spec/spec_helper.rb +54 -0
  242. data/spec/stamp_spec.rb +160 -0
  243. data/spec/stroke_styles_spec.rb +211 -0
  244. data/spec/text_at_spec.rb +143 -0
  245. data/spec/text_box_spec.rb +1043 -0
  246. data/spec/text_rendering_mode_spec.rb +45 -0
  247. data/spec/text_spacing_spec.rb +93 -0
  248. data/spec/text_spec.rb +557 -0
  249. data/spec/text_with_inline_formatting_spec.rb +35 -0
  250. data/spec/transparency_spec.rb +91 -0
  251. data/spec/view_spec.rb +43 -0
  252. metadata +509 -0
@@ -0,0 +1,157 @@
1
+ # encoding: utf-8
2
+ #
3
+ # transformation.rb: Implements rotate, translate, skew, scale and a generic
4
+ # transformation_matrix
5
+ #
6
+ # Copyright January 2010, Michael Witrant. All Rights Reserved.
7
+ #
8
+ # This is free software. Please see the LICENSE and COPYING files for details.
9
+
10
+ module Prawn
11
+ module Graphics
12
+ module Transformation
13
+ # @group Stable API
14
+
15
+ # Rotate the user space. If a block is not provided, then you must save
16
+ # and restore the graphics state yourself.
17
+ #
18
+ # == Options
19
+ # <tt>:origin</tt>:: <tt>[number, number]</tt>. The point around which to
20
+ # rotate. A block must be provided if using the :origin
21
+ #
22
+ # raises <tt>Prawn::Errors::BlockRequired</tt> if an :origin option is
23
+ # provided, but no block is given
24
+ #
25
+ # Example without a block:
26
+ #
27
+ # save_graphics_state
28
+ # rotate 30
29
+ # text "rotated text"
30
+ # restore_graphics_state
31
+ #
32
+ # Example with a block: rotating a rectangle around its upper-left corner
33
+ #
34
+ # x = 300
35
+ # y = 300
36
+ # width = 150
37
+ # height = 200
38
+ # angle = 30
39
+ # pdf.rotate(angle, :origin => [x, y]) do
40
+ # pdf.stroke_rectangle([x, y], width, height)
41
+ # end
42
+ #
43
+ def rotate(angle, options={}, &block)
44
+ Prawn.verify_options(:origin, options)
45
+ rad = degree_to_rad(angle)
46
+ cos = Math.cos(rad)
47
+ sin = Math.sin(rad)
48
+ if options[:origin].nil?
49
+ transformation_matrix(cos, sin, -sin, cos, 0, 0, &block)
50
+ else
51
+ raise Prawn::Errors::BlockRequired unless block_given?
52
+ x = options[:origin][0] + bounds.absolute_left
53
+ y = options[:origin][1] + bounds.absolute_bottom
54
+ x_prime = x * cos - y * sin
55
+ y_prime = x * sin + y * cos
56
+ translate(x - x_prime, y - y_prime) do
57
+ transformation_matrix(cos, sin, -sin, cos, 0, 0, &block)
58
+ end
59
+ end
60
+ end
61
+
62
+ # Translate the user space. If a block is not provided, then you must save
63
+ # and restore the graphics state yourself.
64
+ #
65
+ # Example without a block: move the text up and over 10
66
+ #
67
+ # save_graphics_state
68
+ # translate(10, 10)
69
+ # text "scaled text"
70
+ # restore_graphics_state
71
+ #
72
+ # Example with a block: draw a rectangle with its upper-left corner at
73
+ # x + 10, y + 10
74
+ #
75
+ # x = 300
76
+ # y = 300
77
+ # width = 150
78
+ # height = 200
79
+ # pdf.translate(10, 10) do
80
+ # pdf.stroke_rectangle([x, y], width, height)
81
+ # end
82
+ #
83
+ def translate(x, y, &block)
84
+ transformation_matrix(1, 0, 0, 1, x, y, &block)
85
+ end
86
+
87
+ # Scale the user space. If a block is not provided, then you must save
88
+ # and restore the graphics state yourself.
89
+ #
90
+ # == Options
91
+ # <tt>:origin</tt>:: <tt>[number, number]</tt>. The point from which to
92
+ # scale. A block must be provided if using the :origin
93
+ #
94
+ # raises <tt>Prawn::Errors::BlockRequired</tt> if an :origin option is
95
+ # provided, but no block is given
96
+ #
97
+ # Example without a block:
98
+ #
99
+ # save_graphics_state
100
+ # scale 1.5
101
+ # text "scaled text"
102
+ # restore_graphics_state
103
+ #
104
+ # Example with a block: scale a rectangle from its upper-left corner
105
+ #
106
+ # x = 300
107
+ # y = 300
108
+ # width = 150
109
+ # height = 200
110
+ # factor = 1.5
111
+ # pdf.scale(angle, :origin => [x, y]) do
112
+ # pdf.stroke_rectangle([x, y], width, height)
113
+ # end
114
+ #
115
+ def scale(factor, options={}, &block)
116
+ Prawn.verify_options(:origin, options)
117
+ if options[:origin].nil?
118
+ transformation_matrix(factor, 0, 0, factor, 0, 0, &block)
119
+ else
120
+ raise Prawn::Errors::BlockRequired unless block_given?
121
+ x = options[:origin][0] + bounds.absolute_left
122
+ y = options[:origin][1] + bounds.absolute_bottom
123
+ x_prime = factor * x
124
+ y_prime = factor * y
125
+ translate(x - x_prime, y - y_prime) do
126
+ transformation_matrix(factor, 0, 0, factor, 0, 0, &block)
127
+ end
128
+ end
129
+ end
130
+
131
+ # The following definition of skew would only work in a clearly
132
+ # predicatable manner when if the document had no margin. don't provide
133
+ # this shortcut until it behaves in a clearly understood manner
134
+ #
135
+ # def skew(a, b, &block)
136
+ # transformation_matrix(1,
137
+ # Math.tan(degree_to_rad(a)),
138
+ # Math.tan(degree_to_rad(b)),
139
+ # 1, 0, 0, &block)
140
+ # end
141
+
142
+ # Transform the user space (see notes for rotate regarding graphics state)
143
+ # Generally, one would use the rotate, scale, translate, and skew
144
+ # convenience methods instead of calling transformation_matrix directly
145
+ def transformation_matrix(a, b, c, d, e, f)
146
+ values = [a, b, c, d, e, f].map { |x| "%.5f" % x }.join(" ")
147
+ save_graphics_state if block_given?
148
+ renderer.add_content "#{values} cm"
149
+ if block_given?
150
+ yield
151
+ restore_graphics_state
152
+ end
153
+ end
154
+
155
+ end
156
+ end
157
+ end
@@ -0,0 +1,101 @@
1
+ # encoding: utf-8
2
+ #
3
+ # transparency.rb : Implements transparency
4
+ #
5
+ # Copyright October 2009, Daniel Nelson. All Rights Reserved.
6
+ #
7
+ # This is free software. Please see the LICENSE and COPYING files for details.
8
+ #
9
+
10
+ module Prawn
11
+ module Graphics
12
+
13
+ # The Prawn::Transparency module is used to place transparent
14
+ # content on the page. It has the capacity for separate
15
+ # transparency values for stroked content and all other content.
16
+ #
17
+ # Example:
18
+ # # both the fill and stroke will be at 50% opacity
19
+ # pdf.transparent(0.5) do
20
+ # pdf.text("hello world")
21
+ # pdf.fill_and_stroke_circle([x, y], 25)
22
+ # end
23
+ #
24
+ # # the fill will be at 50% opacity, but the stroke will
25
+ # # be at 75% opacity
26
+ # pdf.transparent(0.5, 0.75) do
27
+ # pdf.text("hello world")
28
+ # pdf.fill_and_stroke_circle([x, y], 25)
29
+ # end
30
+ #
31
+ module Transparency
32
+
33
+ # @group Stable API
34
+
35
+ # Sets the <tt>opacity</tt> and <tt>stroke_opacity</tt> for all
36
+ # the content within the <tt>block</tt>
37
+ # If <tt>stroke_opacity</tt> is not provided, then it takes on
38
+ # the same value as <tt>opacity</tt>
39
+ #
40
+ # Valid ranges for both paramters are 0.0 to 1.0
41
+ #
42
+ # Example:
43
+ # # both the fill and stroke will be at 50% opacity
44
+ # pdf.transparent(0.5) do
45
+ # pdf.text("hello world")
46
+ # pdf.fill_and_stroke_circle([x, y], 25)
47
+ # end
48
+ #
49
+ # # the fill will be at 50% opacity, but the stroke will
50
+ # # be at 75% opacity
51
+ # pdf.transparent(0.5, 0.75) do
52
+ # pdf.text("hello world")
53
+ # pdf.fill_and_stroke_circle([x, y], 25)
54
+ # end
55
+ #
56
+ def transparent(opacity, stroke_opacity=opacity, &block)
57
+ renderer.min_version(1.4)
58
+
59
+ opacity = [[opacity, 0.0].max, 1.0].min
60
+ stroke_opacity = [[stroke_opacity, 0.0].max, 1.0].min
61
+
62
+ save_graphics_state
63
+ renderer.add_content "/#{opacity_dictionary_name(opacity, stroke_opacity)} gs"
64
+ yield
65
+ restore_graphics_state
66
+ end
67
+
68
+ private
69
+
70
+ def opacity_dictionary_registry
71
+ @opacity_dictionary_registry ||= {}
72
+ end
73
+
74
+ def next_opacity_dictionary_id
75
+ opacity_dictionary_registry.length + 1
76
+ end
77
+
78
+ def opacity_dictionary_name(opacity, stroke_opacity)
79
+ key = "#{opacity}_#{stroke_opacity}"
80
+
81
+ if opacity_dictionary_registry[key]
82
+ dictionary = opacity_dictionary_registry[key][:obj]
83
+ dictionary_name = opacity_dictionary_registry[key][:name]
84
+ else
85
+ dictionary = ref!(:Type => :ExtGState,
86
+ :CA => stroke_opacity,
87
+ :ca => opacity
88
+ )
89
+
90
+ dictionary_name = "Tr#{next_opacity_dictionary_id}"
91
+ opacity_dictionary_registry[key] = { :name => dictionary_name,
92
+ :obj => dictionary }
93
+ end
94
+
95
+ page.ext_gstates.merge!(dictionary_name => dictionary)
96
+ dictionary_name
97
+ end
98
+
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,279 @@
1
+ # encoding: utf-8
2
+
3
+ # grid.rb: Provides a basic grid layout system for Prawn
4
+ #
5
+ # Contributed by Andrew O'Brien in March 2009
6
+ #
7
+ # This is free software. Please see the LICENSE and COPYING files for details.
8
+
9
+ module Prawn
10
+ class Document
11
+ # @group Experimental API
12
+
13
+ # Defines the grid system for a particular document. Takes the number of
14
+ # rows and columns and the width to use for the gutter as the
15
+ # keys :rows, :columns, :gutter, :row_gutter, :column_gutter
16
+ #
17
+ # Note that a completely new grid object is built each time define_grid()
18
+ # is called. This means that all subsequent calls to grid() will use
19
+ # the newly defined Grid object -- grids are not nestable like
20
+ # bounding boxes are.
21
+
22
+ def define_grid(options = {})
23
+ @boxes = nil
24
+ @grid = Grid.new(self, options)
25
+ end
26
+
27
+ # A method that can either be used to access a particular grid on the page
28
+ # or work with the grid system directly.
29
+ #
30
+ # @pdf.grid # Get the Grid directly
31
+ # @pdf.grid([0,1]) # Get the GridBox at [0,1]
32
+ # @pdf.grid([0,1], [1,2]) # Get a multi-box spanning from [0,1] to [1,2]
33
+ #
34
+ def grid(*args)
35
+ @boxes ||= {}
36
+ @boxes[args] ||= if args.empty?
37
+ @grid
38
+ else
39
+ g1, g2 = args
40
+ if(g1.class == Array && g2.class == Array &&
41
+ g1.length == 2 && g2.length == 2)
42
+ multi_box(single_box(*g1), single_box(*g2))
43
+ else
44
+ single_box(g1, g2)
45
+ end
46
+ end
47
+ end
48
+
49
+ # A Grid represents the entire grid system of a Page and calculates
50
+ # the column width and row height of the base box.
51
+ #
52
+ # @group Experimental API
53
+ class Grid
54
+ attr_reader :pdf, :columns, :rows, :gutter, :row_gutter, :column_gutter
55
+ def initialize(pdf, options = {}) # :nodoc:
56
+ valid_options = [:columns, :rows, :gutter, :row_gutter, :column_gutter]
57
+ Prawn.verify_options valid_options, options
58
+
59
+ @pdf = pdf
60
+ @columns = options[:columns]
61
+ @rows = options[:rows]
62
+ set_gutter(options)
63
+ end
64
+
65
+ # Calculates the base width of boxes.
66
+ def column_width
67
+ @column_width ||= subdivide(pdf.bounds.width, columns, column_gutter)
68
+ end
69
+
70
+ # Calculates the base height of boxes.
71
+ def row_height
72
+ @row_height ||= subdivide(pdf.bounds.height, rows, row_gutter)
73
+ end
74
+
75
+ # Diagnostic tool to show all of the grids. Defaults to gray.
76
+ def show_all(color = "CCCCCC")
77
+ self.rows.times do |i|
78
+ self.columns.times do |j|
79
+ pdf.grid(i,j).show(color)
80
+ end
81
+ end
82
+ end
83
+
84
+ private
85
+
86
+ def subdivide(total, num, gutter)
87
+ (total.to_f - (gutter * (num - 1).to_f)) / num.to_f
88
+ end
89
+
90
+ def set_gutter(options)
91
+ if options.has_key?(:gutter)
92
+ @gutter = options[:gutter].to_f
93
+ @row_gutter, @column_gutter = @gutter, @gutter
94
+ else
95
+ @row_gutter = options[:row_gutter].to_f
96
+ @column_gutter = options[:column_gutter].to_f
97
+ @gutter = 0
98
+ end
99
+ end
100
+ end
101
+
102
+ # A Box is a class that represents a bounded area of a page.
103
+ # A Grid object has methods that allow easy access to the coordinates of
104
+ # its corners, which can be plugged into most existing prawnmethods.
105
+ #
106
+ # @group Experimental API
107
+ class GridBox
108
+ attr_reader :pdf
109
+
110
+ def initialize(pdf, i, j)
111
+ @pdf = pdf
112
+ @i = i
113
+ @j = j
114
+ end
115
+
116
+ # Mostly diagnostic method that outputs the name of a box as
117
+ # col_num, row_num
118
+ #
119
+ def name
120
+ "#{@i.to_s},#{@j.to_s}"
121
+ end
122
+
123
+ # :nodoc
124
+ def total_height
125
+ pdf.bounds.height.to_f
126
+ end
127
+
128
+ # Width of a box
129
+ def width
130
+ grid.column_width.to_f
131
+ end
132
+
133
+ # Height of a box
134
+ def height
135
+ grid.row_height.to_f
136
+ end
137
+
138
+ # Width of the gutter
139
+ def gutter
140
+ grid.gutter.to_f
141
+ end
142
+
143
+ # x-coordinate of left side
144
+ def left
145
+ @left ||= (width + grid.column_gutter) * @j.to_f
146
+ end
147
+
148
+ # x-coordinate of right side
149
+ def right
150
+ @right ||= left + width
151
+ end
152
+
153
+ # y-coordinate of the top
154
+ def top
155
+ @top ||= total_height - ((height + grid.row_gutter) * @i.to_f)
156
+ end
157
+
158
+ # y-coordinate of the bottom
159
+ def bottom
160
+ @bottom ||= top - height
161
+ end
162
+
163
+ # x,y coordinates of top left corner
164
+ def top_left
165
+ [left, top]
166
+ end
167
+
168
+ # x,y coordinates of top right corner
169
+ def top_right
170
+ [right, top]
171
+ end
172
+
173
+ # x,y coordinates of bottom left corner
174
+ def bottom_left
175
+ [left, bottom]
176
+ end
177
+
178
+ # x,y coordinates of bottom right corner
179
+ def bottom_right
180
+ [right, bottom]
181
+ end
182
+
183
+ # Creates a standard bounding box based on the grid box.
184
+ def bounding_box(&blk)
185
+ pdf.bounding_box(top_left, :width => width, :height => height, &blk)
186
+ end
187
+
188
+ # Diagnostic method
189
+ def show(grid_color = "CCCCCC")
190
+ self.bounding_box do
191
+ original_stroke_color = pdf.stroke_color
192
+
193
+ pdf.stroke_color = grid_color
194
+ pdf.text self.name
195
+ pdf.stroke_bounds
196
+
197
+ pdf.stroke_color = original_stroke_color
198
+ end
199
+ end
200
+
201
+ private
202
+ def grid
203
+ pdf.grid
204
+ end
205
+ end
206
+
207
+ # A MultiBox is specified by 2 Boxes and spans the areas between.
208
+ #
209
+ # @group Experimental API
210
+ class MultiBox < GridBox
211
+ def initialize(pdf, b1, b2)
212
+ @pdf = pdf
213
+ @bs = [b1, b2]
214
+ end
215
+
216
+ def name
217
+ @bs.map {|b| b.name}.join(":")
218
+ end
219
+
220
+ def total_height
221
+ @bs[0].total_height
222
+ end
223
+
224
+ def width
225
+ right_box.right - left_box.left
226
+ end
227
+
228
+ def height
229
+ top_box.top - bottom_box.bottom
230
+ end
231
+
232
+ def gutter
233
+ @bs[0].gutter
234
+ end
235
+
236
+ def left
237
+ left_box.left
238
+ end
239
+
240
+ def right
241
+ right_box.right
242
+ end
243
+
244
+ def top
245
+ top_box.top
246
+ end
247
+
248
+ def bottom
249
+ bottom_box.bottom
250
+ end
251
+
252
+ private
253
+ def left_box
254
+ @left_box ||= @bs.min {|a,b| a.left <=> b.left}
255
+ end
256
+
257
+ def right_box
258
+ @right_box ||= @bs.max {|a,b| a.right <=> b.right}
259
+ end
260
+
261
+ def top_box
262
+ @top_box ||= @bs.max {|a,b| a.top <=> b.top}
263
+ end
264
+
265
+ def bottom_box
266
+ @bottom_box ||= @bs.min {|a,b| a.bottom <=> b.bottom}
267
+ end
268
+ end
269
+
270
+ private
271
+ def single_box(i, j)
272
+ GridBox.new(self, i, j)
273
+ end
274
+
275
+ def multi_box(b1, b2)
276
+ MultiBox.new(self, b1, b2)
277
+ end
278
+ end
279
+ end