prawn-git 2.0.1

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 (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,46 @@
1
+ # encoding: utf-8
2
+ #
3
+ # font_metric_cache.rb : The Prawn font class
4
+ #
5
+ # Copyright Dec 2012, Kenneth Kalmer. All Rights Reserved.
6
+ #
7
+ # This is free software. Please see the LICENSE and COPYING files for details.
8
+ #
9
+
10
+ module Prawn
11
+
12
+ # Cache used internally by Prawn::Document instances to calculate the width
13
+ # of various strings for layout purposes.
14
+ #
15
+ # @private
16
+ class FontMetricCache
17
+
18
+ CacheEntry = Struct.new( :font, :options, :string )
19
+
20
+ def initialize( document )
21
+ @document = document
22
+
23
+ @cache = {}
24
+ end
25
+
26
+ def width_of( string, options )
27
+ f = if options[:style]
28
+ # override style with :style => :bold
29
+ @document.find_font(@document.font.family, :style => options[:style])
30
+ else
31
+ @document.font
32
+ end
33
+
34
+ key = CacheEntry.new( f, options, string )
35
+
36
+ unless length = @cache[ key ]
37
+ length = @cache[ key ] = f.compute_width_of(string, options)
38
+ end
39
+
40
+ length +
41
+ (@document.character_spacing * @document.font.character_count(string))
42
+ end
43
+
44
+ end
45
+
46
+ end
@@ -0,0 +1,646 @@
1
+ # encoding: utf-8
2
+
3
+ # graphics.rb : Implements PDF drawing primitives
4
+ #
5
+ # Copyright April 2008, Gregory Brown. All Rights Reserved.
6
+ #
7
+ # This is free software. Please see the LICENSE and COPYING files for details.
8
+
9
+
10
+ require_relative "graphics/color"
11
+ require_relative "graphics/dash"
12
+ require_relative "graphics/cap_style"
13
+ require_relative "graphics/join_style"
14
+ require_relative "graphics/transparency"
15
+ require_relative "graphics/transformation"
16
+ require_relative "graphics/patterns"
17
+
18
+ module Prawn
19
+
20
+ # Implements the drawing facilities for Prawn::Document.
21
+ # Use this to draw the most beautiful imaginable things.
22
+ #
23
+ # This file lifts and modifies several of PDF::Writer's graphics functions
24
+ # ruby-pdf.rubyforge.org
25
+ #
26
+ module Graphics
27
+
28
+ include Color
29
+ include Dash
30
+ include CapStyle
31
+ include JoinStyle
32
+ include Transparency
33
+ include Transformation
34
+ include Patterns
35
+
36
+ # @group Stable API
37
+
38
+ #######################################################################
39
+ # Low level drawing operations must map the point to absolute coords! #
40
+ #######################################################################
41
+
42
+ # Moves the drawing position to a given point. The point can be
43
+ # specified as a tuple or a flattened argument list
44
+ #
45
+ # pdf.move_to [100,50]
46
+ # pdf.move_to(100,50)
47
+ #
48
+ def move_to(*point)
49
+ xy = PDF::Core.real_params(map_to_absolute(point))
50
+ renderer.add_content("#{xy} m")
51
+ end
52
+
53
+ # Draws a line from the current drawing position to the specified point.
54
+ # The destination may be described as a tuple or a flattened list:
55
+ #
56
+ # pdf.line_to [50,50]
57
+ # pdf.line_to(50,50)
58
+ #
59
+ def line_to(*point)
60
+ xy = PDF::Core.real_params(map_to_absolute(point))
61
+ renderer.add_content("#{xy} l")
62
+ end
63
+
64
+ # Draws a Bezier curve from the current drawing position to the
65
+ # specified point, bounded by two additional points.
66
+ #
67
+ # pdf.curve_to [100,100], :bounds => [[90,90],[75,75]]
68
+ #
69
+ def curve_to(dest,options={})
70
+ options[:bounds] or raise Prawn::Errors::InvalidGraphicsPath,
71
+ "Bounding points for bezier curve must be specified "+
72
+ "as :bounds => [[x1,y1],[x2,y2]]"
73
+
74
+ curve_points = PDF::Core.real_params(
75
+ (options[:bounds] << dest).flat_map { |e| map_to_absolute(e) })
76
+
77
+ renderer.add_content("#{curve_points} c")
78
+ end
79
+
80
+ # Draws a rectangle given <tt>point</tt>, <tt>width</tt> and
81
+ # <tt>height</tt>. The rectangle is bounded by its upper-left corner.
82
+ #
83
+ # pdf.rectangle [300,300], 100, 200
84
+ #
85
+ def rectangle(point,width,height)
86
+ x,y = map_to_absolute(point)
87
+ box = PDF::Core.real_params([x, y - height, width, height])
88
+
89
+ renderer.add_content("#{box} re")
90
+ end
91
+
92
+ # Draws a rounded rectangle given <tt>point</tt>, <tt>width</tt> and
93
+ # <tt>height</tt> and <tt>radius</tt> for the rounded corner. The rectangle
94
+ # is bounded by its upper-left corner.
95
+ #
96
+ # pdf.rounded_rectangle [300,300], 100, 200, 10
97
+ #
98
+ def rounded_rectangle(point,width,height,radius)
99
+ x, y = point
100
+ rounded_polygon(radius, point, [x + width, y], [x + width, y - height], [x, y - height])
101
+ end
102
+
103
+
104
+ ###########################################################
105
+ # Higher level functions: May use relative coords #
106
+ ###########################################################
107
+
108
+ # Sets line thickness to the <tt>width</tt> specified.
109
+ #
110
+ def line_width=(width)
111
+ self.current_line_width = width
112
+ write_line_width
113
+ end
114
+
115
+ # When called without an argument, returns the current line thickness.
116
+ # When called with an argument, sets the line thickness to the specified
117
+ # value (in PDF points)
118
+ #
119
+ # pdf.line_width #=> 1
120
+ # pdf.line_width(5)
121
+ # pdf.line_width #=> 5
122
+ #
123
+ def line_width(width=nil)
124
+ if width
125
+ self.line_width = width
126
+ else
127
+ current_line_width
128
+ end
129
+ end
130
+
131
+ # Draws a line from one point to another. Points may be specified as
132
+ # tuples or flattened argument list:
133
+ #
134
+ # pdf.line [100,100], [200,250]
135
+ # pdf.line(100,100,200,250)
136
+ #
137
+ def line(*points)
138
+ x0,y0,x1,y1 = points.flatten
139
+ move_to(x0, y0)
140
+ line_to(x1, y1)
141
+ end
142
+
143
+ # Draws a horizontal line from <tt>x1</tt> to <tt>x2</tt> at the
144
+ # current <tt>y</tt> position, or the position specified by the :at option.
145
+ #
146
+ # # draw a line from [25, 75] to [100, 75]
147
+ # horizontal_line 25, 100, :at => 75
148
+ #
149
+ def horizontal_line(x1,x2,options={})
150
+ if options[:at]
151
+ y1 = options[:at]
152
+ else
153
+ y1 = y - bounds.absolute_bottom
154
+ end
155
+
156
+ line(x1,y1,x2,y1)
157
+ end
158
+
159
+ # Draws a horizontal line from the left border to the right border of the
160
+ # bounding box at the current <tt>y</tt> position.
161
+ #
162
+ def horizontal_rule
163
+ horizontal_line(bounds.left, bounds.right)
164
+ end
165
+
166
+ # Draws a vertical line at the x cooordinate given by :at from y1 to y2.
167
+ #
168
+ # # draw a line from [25, 100] to [25, 300]
169
+ # vertical_line 100, 300, :at => 25
170
+ #
171
+ def vertical_line(y1,y2,params)
172
+ line(params[:at],y1,params[:at],y2)
173
+ end
174
+
175
+ # Draws a Bezier curve between two points, bounded by two additional
176
+ # points
177
+ #
178
+ # pdf.curve [50,100], [100,100], :bounds => [[90,90],[75,75]]
179
+ #
180
+ def curve(origin,dest, options={})
181
+ move_to(*origin)
182
+ curve_to(dest,options)
183
+ end
184
+
185
+ # This constant is used to approximate a symmetrical arc using a cubic
186
+ # Bezier curve.
187
+ #
188
+ KAPPA = 4.0 * ((Math.sqrt(2) - 1.0) / 3.0)
189
+
190
+ # Draws a circle of radius <tt>radius</tt> with the centre-point at <tt>point</tt>
191
+ # as a complete subpath. The drawing point will be moved to the
192
+ # centre-point upon completion of the drawing the circle.
193
+ #
194
+ # pdf.circle [100,100], 25
195
+ #
196
+ def circle(center, radius)
197
+ ellipse(center, radius, radius)
198
+ end
199
+
200
+ # Draws an ellipse of +x+ radius <tt>r1</tt> and +y+ radius <tt>r2</tt>
201
+ # with the centre-point at <tt>point</tt> as a complete subpath. The
202
+ # drawing point will be moved to the centre-point upon completion of the
203
+ # drawing the ellipse.
204
+ #
205
+ # # draws an ellipse with x-radius 25 and y-radius 50
206
+ # pdf.ellipse [100,100], 25, 50
207
+ #
208
+ def ellipse(point, r1, r2 = r1)
209
+ x, y = point
210
+ l1 = r1 * KAPPA
211
+ l2 = r2 * KAPPA
212
+
213
+ move_to(x + r1, y)
214
+
215
+ # Upper right hand corner
216
+ curve_to [x, y + r2],
217
+ :bounds => [[x + r1, y + l2], [x + l1, y + r2]]
218
+
219
+ # Upper left hand corner
220
+ curve_to [x - r1, y],
221
+ :bounds => [[x - l1, y + r2], [x - r1, y + l2]]
222
+
223
+ # Lower left hand corner
224
+ curve_to [x, y - r2],
225
+ :bounds => [[x - r1, y - l2], [x - l1, y - r2]]
226
+
227
+ # Lower right hand corner
228
+ curve_to [x + r1, y],
229
+ :bounds => [[x + l1, y - r2], [x + r1, y - l2]]
230
+
231
+ move_to(x, y)
232
+ end
233
+
234
+ # Draws a polygon from the specified points.
235
+ #
236
+ # # draws a snazzy triangle
237
+ # pdf.polygon [100,100], [100,200], [200,200]
238
+ #
239
+ def polygon(*points)
240
+ move_to points[0]
241
+ (points[1..-1] << points[0]).each do |point|
242
+ line_to(*point)
243
+ end
244
+ # close the path
245
+ renderer.add_content "h"
246
+ end
247
+
248
+ # Draws a rounded polygon from specified points using the radius to define bezier curves
249
+ #
250
+ # # draws a rounded filled in polygon
251
+ # pdf.fill_and_stroke_rounded_polygon(10, [100, 250], [200, 300], [300, 250],
252
+ # [300, 150], [200, 100], [100, 150])
253
+ def rounded_polygon(radius, *points)
254
+ move_to point_on_line(radius, points[1], points[0])
255
+ sides = points.size
256
+ points << points[0] << points[1]
257
+ (sides).times do |i|
258
+ rounded_vertex(radius, points[i], points[i + 1], points[i + 2])
259
+ end
260
+ # close the path
261
+ renderer.add_content "h"
262
+ end
263
+
264
+
265
+ # Creates a rounded vertex for a line segment used for building a rounded polygon
266
+ # requires a radius to define bezier curve and three points. The first two points define
267
+ # the line segment and the third point helps define the curve for the vertex.
268
+ def rounded_vertex(radius, *points)
269
+ radial_point_1 = point_on_line(radius, points[0], points[1])
270
+ bezier_point_1 = point_on_line((radius - radius*KAPPA), points[0], points[1] )
271
+ radial_point_2 = point_on_line(radius, points[2], points[1])
272
+ bezier_point_2 = point_on_line((radius - radius*KAPPA), points[2], points[1])
273
+ line_to(radial_point_1)
274
+ curve_to(radial_point_2, :bounds => [bezier_point_1, bezier_point_2])
275
+ end
276
+
277
+ # Strokes the current path. If a block is provided, yields to the block
278
+ # before closing the path. See Graphics::Color for color details.
279
+ #
280
+ def stroke
281
+ yield if block_given?
282
+ renderer.add_content "S"
283
+ end
284
+
285
+ # Closes and strokes the current path. If a block is provided, yields to
286
+ # the block before closing the path. See Graphics::Color for color details.
287
+ #
288
+ def close_and_stroke
289
+ yield if block_given?
290
+ renderer.add_content "s"
291
+ end
292
+
293
+ # Draws and strokes a rectangle represented by the current bounding box
294
+ #
295
+ def stroke_bounds
296
+ stroke_rectangle bounds.top_left, bounds.width, bounds.height
297
+ end
298
+
299
+ # Draws and strokes X and Y axes rulers beginning at the current bounding
300
+ # box origin (or at a custom location).
301
+ #
302
+ # == Options
303
+ #
304
+ # +:at+::
305
+ # Origin of the X and Y axes (default: [0, 0] = origin of the bounding
306
+ # box)
307
+ #
308
+ # +:width+::
309
+ # Length of the X axis (default: width of the bounding box)
310
+ #
311
+ # +:height+::
312
+ # Length of the Y axis (default: height of the bounding box)
313
+ #
314
+ # +:step_length+::
315
+ # Length of the step between markers (default: 100)
316
+ #
317
+ # +:negative_axes_length+::
318
+ # Length of the negative parts of the axes (default: 20)
319
+ #
320
+ # +:color+:
321
+ # The color of the axes and the text.
322
+ #
323
+ def stroke_axis(options = {})
324
+ options = {
325
+ :at => [0,0],
326
+ :height => bounds.height.to_i - (options[:at] || [0,0])[1],
327
+ :width => bounds.width.to_i - (options[:at] || [0,0])[0],
328
+ :step_length => 100,
329
+ :negative_axes_length => 20,
330
+ :color => "000000",
331
+ }.merge(options)
332
+
333
+ Prawn.verify_options([:at, :width, :height, :step_length,
334
+ :negative_axes_length, :color], options)
335
+
336
+ save_graphics_state do
337
+ fill_color(options[:color])
338
+ stroke_color(options[:color])
339
+
340
+ dash(1, :space => 4)
341
+ stroke_horizontal_line(options[:at][0] - options[:negative_axes_length],
342
+ options[:at][0] + options[:width], :at => options[:at][1])
343
+ stroke_vertical_line(options[:at][1] - options[:negative_axes_length],
344
+ options[:at][1] + options[:height], :at => options[:at][0])
345
+ undash
346
+
347
+ fill_circle(options[:at], 1)
348
+
349
+ (options[:step_length]..options[:width]).step(options[:step_length]) do |point|
350
+ fill_circle([options[:at][0] + point, options[:at][1]], 1)
351
+ draw_text(point, :at => [options[:at][0] + point - 5, options[:at][1] - 10], :size => 7)
352
+ end
353
+
354
+ (options[:step_length]..options[:height]).step(options[:step_length]) do |point|
355
+ fill_circle([options[:at][0], options[:at][1] + point], 1)
356
+ draw_text(point, :at => [options[:at][0] - 17, options[:at][1] + point - 2], :size => 7)
357
+ end
358
+ end
359
+ end
360
+
361
+ # Closes and fills the current path. See Graphics::Color for color details.
362
+ #
363
+ # If the option :fill_rule => :even_odd is specified, Prawn will use the
364
+ # even-odd rule to fill the path. Otherwise, the nonzero winding number rule
365
+ # will be used. See the PDF reference, "Graphics -> Path Construction and
366
+ # Painting -> Clipping Path Operators" for details on the difference.
367
+ #
368
+ def fill(options={})
369
+ yield if block_given?
370
+ renderer.add_content(options[:fill_rule] == :even_odd ? "f*" : "f")
371
+ end
372
+
373
+ # Closes, fills, and strokes the current path. If a block is provided,
374
+ # yields to the block before closing the path. See Graphics::Color for
375
+ # color details.
376
+ #
377
+ # If the option :fill_rule => :even_odd is specified, Prawn will use the
378
+ # even-odd rule to fill the path. Otherwise, the nonzero winding number rule
379
+ # will be used. See the PDF reference, "Graphics -> Path Construction and
380
+ # Painting -> Clipping Path Operators" for details on the difference.
381
+ #
382
+ def fill_and_stroke(options={})
383
+ yield if block_given?
384
+ renderer.add_content(options[:fill_rule] == :even_odd ? "b*" : "b")
385
+ end
386
+
387
+ # Closes the current path.
388
+ #
389
+ def close_path
390
+ renderer.add_content "h"
391
+ end
392
+
393
+ ##
394
+ # :method: stroke_rectangle
395
+ #
396
+ # Draws and strokes a rectangle given +point+, +width+ and +height+. The
397
+ # rectangle is bounded by its upper-left corner.
398
+ #
399
+ # :call-seq:
400
+ # stroke_rectangle(point,width,height)
401
+
402
+ ##
403
+ # :method: fill_rectangle
404
+ #
405
+ # Draws and fills ills a rectangle given +point+, +width+ and +height+. The
406
+ # rectangle is bounded by its upper-left corner.
407
+ #
408
+ # :call-seq:
409
+ # fill_rectangle(point,width,height)
410
+
411
+ ##
412
+ # :method: fill_and_stroke_rectangle
413
+ #
414
+ # Draws, fills, and strokes a rectangle given +point+, +width+ and +height+.
415
+ # The rectangle is bounded by its upper-left corner.
416
+ #
417
+ # :call-seq:
418
+ # fill_and_stroke_rectangle(point,width,height)
419
+
420
+ ##
421
+ # :method: stroke_rounded_rectangle
422
+ #
423
+ # Draws and strokes a rounded rectangle given +point+, +width+ and +height+
424
+ # and +radius+ for the rounded corner. The rectangle is bounded by its
425
+ # upper-left corner.
426
+ #
427
+ # :call-seq:
428
+ # stroke_rounded_rectangle(point,width,height,radius)
429
+
430
+ ##
431
+ # :method: fill_rounded_rectangle
432
+ #
433
+ # Draws and fills a rounded rectangle given +point+, +width+ and +height+
434
+ # and +radius+ for the rounded corner. The rectangle is bounded by its
435
+ # upper-left corner.
436
+ #
437
+ # :call-seq:
438
+ # fill_rounded_rectangle(point,width,height,radius)
439
+
440
+ ##
441
+ # :method: stroke_and_fill_rounded_rectangle
442
+ #
443
+ # Draws, fills, and strokes a rounded rectangle given +point+, +width+ and
444
+ # +height+ and +radius+ for the rounded corner. The rectangle is bounded by
445
+ # its upper-left corner.
446
+ #
447
+ # :call-seq:
448
+ # stroke_and_fill_rounded_rectangle(point,width,height,radius)
449
+
450
+ ##
451
+ # :method: stroke_line
452
+ #
453
+ # Strokes a line from one point to another. Points may be specified as
454
+ # tuples or flattened argument list.
455
+ #
456
+ # :call-seq:
457
+ # stroke_line(*points)
458
+
459
+ ##
460
+ # :method: stroke_horizontal_line
461
+ #
462
+ # Strokes a horizontal line from +x1+ to +x2+ at the current y position, or
463
+ # the position specified by the :at option.
464
+ #
465
+ # :call-seq:
466
+ # stroke_horizontal_line(x1,x2,options={})
467
+
468
+ ##
469
+ # :method: stroke_horizontal_rule
470
+ #
471
+ # Strokes a horizontal line from the left border to the right border of the
472
+ # bounding box at the current y position.
473
+ #
474
+ # :call-seq:
475
+ # stroke_horizontal_rule
476
+
477
+ ##
478
+ # :method: stroke_vertical_line
479
+ #
480
+ # Strokes a vertical line at the x coordinate given by :at from y1 to y2.
481
+ #
482
+ # :call-seq:
483
+ # stroke_vertical_line(y1,y2,params)
484
+
485
+ ##
486
+ # :method: stroke_curve
487
+ #
488
+ # Strokes a Bezier curve between two points, bounded by two additional
489
+ # points.
490
+ #
491
+ # :call-seq:
492
+ # stroke_curve(origin,dest,options={})
493
+
494
+ ##
495
+ # :method: stroke_circle
496
+ #
497
+ # Draws and strokes a circle of radius +radius+ with the centre-point at
498
+ # +point+.
499
+ #
500
+ # :call-seq:
501
+ # stroke_circle(center,radius)
502
+
503
+ ##
504
+ # :method: fill_circle
505
+ #
506
+ # Draws and fills a circle of radius +radius+ with the centre-point at
507
+ # +point+.
508
+ #
509
+ # :call-seq:
510
+ # fill_circle(center,radius)
511
+
512
+ ##
513
+ # :method: fill_and_stroke_circle
514
+ #
515
+ # Draws, strokes, and fills a circle of radius +radius+ with the
516
+ # centre-point at +point+.
517
+ #
518
+ # :call-seq:
519
+ # fill_and_stroke_circle(center,radius)
520
+
521
+ ##
522
+ # :method: stroke_ellipse
523
+ #
524
+ # Draws and strokes an ellipse of x radius +r1+ and y radius +r2+ with the
525
+ # centre-point at +point+.
526
+ #
527
+ # :call-seq:
528
+ # stroke_ellipse(point, r1, r2 = r1)
529
+
530
+ ##
531
+ # :method: fill_ellipse
532
+ #
533
+ # Draws and fills an ellipse of x radius +r1+ and y radius +r2+ with the
534
+ # centre-point at +point+.
535
+ #
536
+ # :call-seq:
537
+ # fill_ellipse(point, r1, r2 = r1)
538
+
539
+ ##
540
+ # :method: fill_and_stroke_ellipse
541
+ #
542
+ # Draws, strokes, and fills an ellipse of x radius +r1+ and y radius +r2+
543
+ # with the centre-point at +point+.
544
+ #
545
+ # :call-seq:
546
+ # fill_and_stroke_ellipse(point, r1, r2 = r1)
547
+
548
+ ##
549
+ # :method: stroke_polygon
550
+ #
551
+ # Draws and strokes a polygon from the specified points.
552
+ #
553
+ # :call-seq:
554
+ # stroke_polygon(*points)
555
+
556
+ ##
557
+ # :method: fill_polygon
558
+ #
559
+ # Draws and fills a polygon from the specified points.
560
+ #
561
+ # :call-seq:
562
+ # fill_polygon(*points)
563
+
564
+ ##
565
+ # :method: fill_and_stroke_polygon
566
+ #
567
+ # Draws, strokes, and fills a polygon from the specified points.
568
+ #
569
+ # :call-seq:
570
+ # fill_and_stroke_polygon(*points)
571
+
572
+ ##
573
+ # :method: stroke_rounded_polygon
574
+ #
575
+ # Draws and strokes a rounded polygon from specified points, using +radius+
576
+ # to define Bezier curves.
577
+ #
578
+ # :call-seq:
579
+ # stroke_rounded_polygon(radius, *points)
580
+
581
+ ##
582
+ # :method: fill_rounded_polygon
583
+ #
584
+ # Draws and fills a rounded polygon from specified points, using +radius+ to
585
+ # define Bezier curves.
586
+ #
587
+ # :call-seq:
588
+ # fill_rounded_polygon(radius, *points)
589
+
590
+ ##
591
+ # :method: fill_and_stroke_rounded_polygon
592
+ #
593
+ # Draws, strokes, and fills a rounded polygon from specified points, using
594
+ # +radius+ to define Bezier curves.
595
+ #
596
+ # :call-seq:
597
+ # fill_and_stroke_rounded_polygon(radius, *points)
598
+
599
+ ops = %w{fill stroke fill_and_stroke}
600
+ shapes = %w{line_to curve_to rectangle rounded_rectangle line horizontal_line horizontal_rule vertical_line
601
+ curve circle_at circle ellipse_at ellipse polygon rounded_polygon rounded_vertex}
602
+
603
+ ops.product(shapes).each do |operation,shape|
604
+ class_eval "def #{operation}_#{shape}(*args); #{shape}(*args); #{operation}; end"
605
+ end
606
+
607
+ private
608
+
609
+ def current_line_width
610
+ graphic_state.line_width
611
+ end
612
+
613
+ def current_line_width=(width)
614
+ graphic_state.line_width = width
615
+ end
616
+
617
+ def write_line_width
618
+ renderer.add_content("#{current_line_width} w")
619
+ end
620
+
621
+ def map_to_absolute(*point)
622
+ x,y = point.flatten
623
+ [@bounding_box.absolute_left + x, @bounding_box.absolute_bottom + y]
624
+ end
625
+
626
+ def map_to_absolute!(point)
627
+ point.replace(map_to_absolute(point))
628
+ end
629
+
630
+ def degree_to_rad(angle)
631
+ angle * Math::PI / 180
632
+ end
633
+
634
+ # Returns the coordinates for a point on a line that is a given distance away from the second
635
+ # point defining the line segement
636
+ def point_on_line(distance_from_end, *points)
637
+ x0,y0,x1,y1 = points.flatten
638
+ length = Math.sqrt((x1 - x0)**2 + (y1 - y0)**2)
639
+ p = (length - distance_from_end) / length
640
+ xr = x0 + p*(x1 - x0)
641
+ yr = y0 + p*(y1 - y0)
642
+ [xr, yr]
643
+ end
644
+
645
+ end
646
+ end