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,437 @@
1
+ # encoding: utf-8
2
+
3
+ # text.rb : Implements PDF text primitives
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
+
9
+ require "zlib"
10
+
11
+ require "pdf/core/text"
12
+
13
+ require_relative "text/formatted"
14
+ require_relative "text/box"
15
+
16
+ module Prawn
17
+ module Text
18
+
19
+ include PDF::Core::Text
20
+ include Prawn::Text::Formatted
21
+
22
+ # No-Break Space
23
+ Prawn::Text::NBSP = " "
24
+ # Zero Width Space (indicate word boundaries without a space)
25
+ Prawn::Text::ZWSP = [8203].pack("U")
26
+ # Soft Hyphen (invisible, except when causing a line break)
27
+ Prawn::Text::SHY = "­"
28
+
29
+ # @group Stable API
30
+
31
+ # If you want text to flow onto a new page or between columns, this is the
32
+ # method to use. If, instead, if you want to place bounded text outside of
33
+ # the flow of a document (for captions, labels, charts, etc.), use Text::Box
34
+ # or its convenience method text_box.
35
+ #
36
+ # Draws text on the page. Prawn attempts to wrap the text to fit within your
37
+ # current bounding box (or margin_box if no bounding box is being used).
38
+ # Text will flow onto the next page when it reaches the bottom of the
39
+ # bounding box. Text wrap in Prawn does not re-flow linebreaks, so if you
40
+ # want fully automated text wrapping, be sure to remove newlines before
41
+ # attempting to draw your string.
42
+ #
43
+ # == Examples
44
+ #
45
+ # pdf.text "Will be wrapped when it hits the edge of your bounding box"
46
+ # pdf.text "This will be centered", :align => :center
47
+ # pdf.text "This will be right aligned", :align => :right
48
+ # pdf.text "This <i>includes <b>inline</b></i> <font size='24'>" +
49
+ # "formatting</font>", :inline_format => true
50
+ #
51
+ # If your font contains kerning pair data that Prawn can parse, the
52
+ # text will be kerned by default. You can disable kerning by including
53
+ # a false <tt>:kerning</tt> option. If you want to disable kerning on an
54
+ # entire document, set default_kerning = false for that document
55
+ #
56
+ # === Text Positioning Details
57
+ #
58
+ # The text is positioned at font.ascender below the baseline,
59
+ # making it easy to use this method within bounding boxes and spans.
60
+ #
61
+ # == Encoding
62
+ #
63
+ # Note that strings passed to this function should be encoded as UTF-8.
64
+ # If you get unexpected characters appearing in your rendered document,
65
+ # check this.
66
+ #
67
+ # If the current font is a built-in one, although the string must be
68
+ # encoded as UTF-8, only characters that are available in WinAnsi
69
+ # are allowed.
70
+ #
71
+ # If an empty box is rendered to your PDF instead of the character you
72
+ # wanted it usually means the current font doesn't include that character.
73
+ #
74
+ # == Options (default values marked in [])
75
+ #
76
+ # <tt>:inline_format</tt>::
77
+ # <tt>boolean</tt>. If true, then the string parameter is interpreted
78
+ # as a HTML-esque string that recognizes the following tags
79
+ # (assuming the default text formatter is used):
80
+ # <tt>\<b></b></tt>:: bold
81
+ # <tt>\<i></i></tt>:: italic
82
+ # <tt>\<u></u></tt>:: underline
83
+ # <tt>\<strikethrough></strikethrough></tt>:: strikethrough
84
+ # <tt>\<sub></sub></tt>:: subscript
85
+ # <tt>\<sup></sup></tt>:: superscript
86
+ # <tt>\<font></font></tt>::
87
+ # with the following attributes (using double or single quotes)
88
+ # <tt>size="24"</tt>::
89
+ # attribute for setting size
90
+ # <tt>character_spacing="2.5"</tt>::
91
+ # attribute for setting character spacing
92
+ # <tt>name="Helvetica"</tt>::
93
+ # attribute for setting the font. The font name must be an
94
+ # AFM font with the desired faces or must be a font that is
95
+ # already registered using Prawn::Document#font_families
96
+ # <tt>\<color></color></tt>::
97
+ # with the following attributes
98
+ # <tt>rgb="ffffff" or rgb="#ffffff"</tt>::
99
+ # <tt>c="100" m="100" y="100" k="100"</tt>::
100
+ # <tt>\<link></link></tt>::
101
+ # with the following attributes
102
+ # <tt>href="http://example.com"</tt>:: an external link
103
+ # Note that you must explicitly underline and color using the
104
+ # appropriate tags if you which to draw attention to the link
105
+ #
106
+ # <tt>:kerning</tt>:: <tt>boolean</tt>. Whether or not to use kerning (if it
107
+ # is available with the current font)
108
+ # [value of document.default_kerning?]
109
+ # <tt>:size</tt>:: <tt>number</tt>. The font size to use. [current font
110
+ # size]
111
+ # <tt>:color</tt>:: an RGB color ("ff0000") or CMYK array [10, 20, 30, 40].
112
+ # <tt>:character_spacing</tt>:: <tt>number</tt>. The amount of space to add
113
+ # to or remove from the default character
114
+ # spacing. [0]
115
+ # <tt>:style</tt>:: The style to use. The requested style must be part of
116
+ # the current font familly. [current style]
117
+ # <tt>:indent_paragraphs</tt>:: <tt>number</tt>. The amount to indent the
118
+ # first line of each paragraph. Omit this
119
+ # option if you do not want indenting.
120
+ # <tt>:direction</tt>::
121
+ # <tt>:ltr</tt>, <tt>:rtl</tt>, Direction of the text (left-to-right
122
+ # or right-to-left) [value of document.text_direction]
123
+ # <tt>:fallback_fonts</tt>::
124
+ # An array of font names. Each name must be the name of an AFM font or
125
+ # the name that was used to register a family of TTF fonts (see
126
+ # Prawn::Document#font_families). If present, then each glyph will be
127
+ # rendered using the first font that includes the glyph, starting with
128
+ # the current font and then moving through :fallback_fonts from
129
+ # left to right.
130
+ # <tt>:align</tt>::
131
+ # <tt>:left</tt>, <tt>:center</tt>, <tt>:right</tt>, or
132
+ # <tt>:justify</tt> Alignment within the bounding box
133
+ # [:left if direction is :ltr, :right if direction is :rtl]
134
+ # <tt>:valign</tt>:: <tt>:top</tt>, <tt>:center</tt>, or <tt>:bottom</tt>.
135
+ # Vertical alignment within the bounding box [:top]
136
+ # <tt>:leading</tt>::
137
+ # <tt>number</tt>. Additional space between lines [value of
138
+ # document.default_leading]
139
+ # <tt>:final_gap</tt>:: <tt>boolean</tt>. If true, then the space between
140
+ # each line is included below the last line;
141
+ # otherwise, document.y is placed just below the
142
+ # descender of the last line printed [true]
143
+ # <tt>:mode</tt>:: The text rendering mode to use. Use this to specify if the
144
+ # text should render with the fill color, stroke color or
145
+ # both. See the comments to text_rendering_mode() to see
146
+ # a list of valid options. [0]
147
+ #
148
+ # == Exceptions
149
+ #
150
+ # Raises <tt>ArgumentError</tt> if <tt>:at</tt> option included
151
+ #
152
+ # Raises <tt>Prawn::Errrors::CannotFit</tt> if not wide enough to print
153
+ # any text
154
+ #
155
+ def text(string, options={})
156
+ return false if string.nil?
157
+ # we modify the options. don't change the user's hash
158
+ options = options.dup
159
+
160
+ if p = options[:inline_format]
161
+ p = [] unless p.is_a?(Array)
162
+ options.delete(:inline_format)
163
+ array = self.text_formatter.format(string, *p)
164
+ else
165
+ array = [{ :text => string }]
166
+ end
167
+
168
+ formatted_text(array, options)
169
+ end
170
+
171
+ # Draws formatted text to the page.
172
+ # Formatted text is comprised of an array of hashes, where each hash defines
173
+ # text and format information. See Text::Formatted#formatted_text_box for
174
+ # more information on the structure of this array
175
+ #
176
+ # == Example
177
+ #
178
+ # text([{ :text => "hello" },
179
+ # { :text => "world",
180
+ # :size => 24,
181
+ # :styles => [:bold, :italic] }])
182
+ #
183
+ # == Options
184
+ #
185
+ # Accepts the same options as #text
186
+ #
187
+ # == Exceptions
188
+ #
189
+ # Same as for #text
190
+ #
191
+ def formatted_text(array, options={})
192
+ options = inspect_options_for_text(options.dup)
193
+
194
+ if color = options.delete(:color)
195
+ array = array.map do |fragment|
196
+ fragment[:color] ? fragment : fragment.merge(:color => color)
197
+ end
198
+ end
199
+
200
+ if @indent_paragraphs
201
+ self.text_formatter.array_paragraphs(array).each do |paragraph|
202
+ remaining_text = draw_indented_formatted_line(paragraph, options)
203
+
204
+ if @no_text_printed
205
+ # unless this paragraph was an empty line
206
+ unless @all_text_printed
207
+ @bounding_box.move_past_bottom
208
+ remaining_text = draw_indented_formatted_line(paragraph, options)
209
+ end
210
+ end
211
+
212
+ remaining_text = fill_formatted_text_box(remaining_text, options)
213
+ draw_remaining_formatted_text_on_new_pages(remaining_text, options)
214
+ end
215
+ else
216
+ remaining_text = fill_formatted_text_box(array, options)
217
+ draw_remaining_formatted_text_on_new_pages(remaining_text, options)
218
+ end
219
+ end
220
+
221
+ # Draws text on the page, beginning at the point specified by the :at option
222
+ # the string is assumed to be pre-formatted to properly fit the page.
223
+ #
224
+ # pdf.draw_text "Hello World", :at => [100,100]
225
+ # pdf.draw_text "Goodbye World", :at => [50,50], :size => 16
226
+ #
227
+ # If your font contains kerning pair data that Prawn can parse, the
228
+ # text will be kerned by default. You can disable kerning by including
229
+ # a false <tt>:kerning</tt> option. If you want to disable kerning on an
230
+ # entire document, set default_kerning = false for that document
231
+ #
232
+ # === Text Positioning Details:
233
+ #
234
+ # Prawn will position your text by the left-most edge of its baseline, and
235
+ # flow along a single line. (This means that :align will not work)
236
+ #
237
+ # == Rotation
238
+ #
239
+ # Text can be rotated before it is placed on the canvas by specifying the
240
+ # <tt>:rotate</tt> option with a given angle. Rotation occurs counter-clockwise.
241
+ #
242
+ # == Encoding
243
+ #
244
+ # Note that strings passed to this function should be encoded as UTF-8.
245
+ # If you get unexpected characters appearing in your rendered document,
246
+ # check this.
247
+ #
248
+ # If the current font is a built-in one, although the string must be
249
+ # encoded as UTF-8, only characters that are available in WinAnsi
250
+ # are allowed.
251
+ #
252
+ # If an empty box is rendered to your PDF instead of the character you
253
+ # wanted it usually means the current font doesn't include that character.
254
+ #
255
+ # == Options (default values marked in [])
256
+ #
257
+ # <tt>:at</tt>:: <tt>[x, y]</tt>(required). The position at which to start the text
258
+ # <tt>:kerning</tt>:: <tt>boolean</tt>. Whether or not to use kerning (if it
259
+ # is available with the current font)
260
+ # [value of default_kerning?]
261
+ # <tt>:size</tt>:: <tt>number</tt>. The font size to use. [current font
262
+ # size]
263
+ # <tt>:style</tt>:: The style to use. The requested style must be part of
264
+ # the current font familly. [current style]
265
+ #
266
+ # <tt>:rotate</tt>:: <tt>number</tt>. The angle to which to rotate text
267
+ #
268
+ # == Exceptions
269
+ #
270
+ # Raises <tt>ArgumentError</tt> if <tt>:at</tt> option omitted
271
+ #
272
+ # Raises <tt>ArgumentError</tt> if <tt>:align</tt> option included
273
+ #
274
+ def draw_text(text, options)
275
+ options = inspect_options_for_draw_text(options.dup)
276
+
277
+ # dup because normalize_encoding changes the string
278
+ text = text.to_s.dup
279
+ save_font do
280
+ process_text_options(options)
281
+ font.normalize_encoding!(text)
282
+ font_size(options[:size]) { draw_text!(text, options) }
283
+ end
284
+ end
285
+
286
+ # Low level text placement method. All font and size alterations
287
+ # should already be set
288
+ #
289
+ def draw_text!(text, options)
290
+ unless font.unicode? || font.class.hide_m17n_warning || text.ascii_only?
291
+ warn "PDF's built-in fonts have very limited support for "+
292
+ "internationalized text.\nIf you need full UTF-8 support, "+
293
+ "consider using a TTF font instead.\n\nTo disable this "+
294
+ "warning, add the following line to your code:\n"+
295
+ "Prawn::Font::AFM.hide_m17n_warning = true\n"
296
+
297
+ font.class.hide_m17n_warning = true
298
+ end
299
+
300
+ x,y = map_to_absolute(options[:at])
301
+ add_text_content(text,x,y,options)
302
+ end
303
+
304
+ # Gets height of text in PDF points.
305
+ # Same options as #text, except as noted.
306
+ # Not compatible with :indent_paragraphs option
307
+ #
308
+ # ==Example
309
+ #
310
+ # height_of("hello\nworld")
311
+ #
312
+ # == Exceptions
313
+ #
314
+ # Raises <tt>NotImplementedError</tt> if <tt>:indent_paragraphs</tt>
315
+ # option included
316
+ #
317
+ # Raises <tt>Prawn::Errrors::CannotFit</tt> if not wide enough to print
318
+ # any text
319
+ #
320
+ def height_of(string, options={})
321
+ height_of_formatted([{ :text => string }], options)
322
+ end
323
+
324
+ # Gets height of formatted text in PDF points.
325
+ # See documentation for #height_of.
326
+ #
327
+ # ==Example
328
+ #
329
+ # height_of_formatted([{ :text => "hello" },
330
+ # { :text => "world",
331
+ # :size => 24,
332
+ # :styles => [:bold, :italic] }])
333
+ #
334
+ def height_of_formatted(array, options={})
335
+ if options[:indent_paragraphs]
336
+ raise NotImplementedError, ":indent_paragraphs option not available" +
337
+ "with height_of"
338
+ end
339
+ process_final_gap_option(options)
340
+ box = Text::Formatted::Box.new(array,
341
+ options.merge(:height => 100000000,
342
+ :document => self))
343
+ box.render(:dry_run => true)
344
+
345
+ height = box.height
346
+ height += box.line_gap + box.leading if @final_gap
347
+ height
348
+ end
349
+
350
+ private
351
+
352
+ def draw_remaining_formatted_text_on_new_pages(remaining_text, options)
353
+ while remaining_text.length > 0
354
+ @bounding_box.move_past_bottom
355
+ previous_remaining_text = remaining_text
356
+ remaining_text = fill_formatted_text_box(remaining_text, options)
357
+ break if remaining_text == previous_remaining_text
358
+ end
359
+ end
360
+
361
+ def draw_indented_formatted_line(string, options)
362
+ gap = options.fetch(:direction, text_direction) == :ltr ?
363
+ [@indent_paragraphs, 0] : [0, @indent_paragraphs]
364
+
365
+ indent(*gap) do
366
+ fill_formatted_text_box(string, options.dup.merge(:single_line => true))
367
+ end
368
+ end
369
+
370
+ def fill_formatted_text_box(text, options)
371
+ merge_text_box_positioning_options(options)
372
+ box = Text::Formatted::Box.new(text, options)
373
+ remaining_text = box.render
374
+ @no_text_printed = box.nothing_printed?
375
+ @all_text_printed = box.everything_printed?
376
+
377
+ self.y -= box.height
378
+ self.y -= box.line_gap + box.leading if @final_gap
379
+
380
+ remaining_text
381
+ end
382
+
383
+ def merge_text_box_positioning_options(options)
384
+ bottom = @bounding_box.stretchy? ? @margin_box.absolute_bottom :
385
+ @bounding_box.absolute_bottom
386
+
387
+ options[:height] = y - bottom
388
+ options[:width] = bounds.width
389
+ options[:at] = [@bounding_box.left_side - @bounding_box.absolute_left,
390
+ y - @bounding_box.absolute_bottom]
391
+ end
392
+
393
+ def inspect_options_for_draw_text(options)
394
+ if options[:at].nil?
395
+ raise ArgumentError, "The :at option is required for draw_text"
396
+ elsif options[:align]
397
+ raise ArgumentError, "The :align option does not work with draw_text"
398
+ end
399
+ if options[:kerning].nil? then
400
+ options[:kerning] = default_kerning?
401
+ end
402
+ valid_options = PDF::Core::Text::VALID_OPTIONS + [:at, :rotate]
403
+ Prawn.verify_options(valid_options, options)
404
+ options
405
+ end
406
+
407
+ def inspect_options_for_text(options)
408
+ if options[:at]
409
+ raise ArgumentError, ":at is no longer a valid option with text." +
410
+ "use draw_text or text_box instead"
411
+ end
412
+ process_final_gap_option(options)
413
+ process_indent_paragraphs_option(options)
414
+ options[:document] = self
415
+ options
416
+ end
417
+
418
+ def process_final_gap_option(options)
419
+ @final_gap = options[:final_gap].nil? || options[:final_gap]
420
+ options.delete(:final_gap)
421
+ end
422
+
423
+ def process_indent_paragraphs_option(options)
424
+ @indent_paragraphs = options[:indent_paragraphs]
425
+ options.delete(:indent_paragraphs)
426
+ end
427
+
428
+ def move_text_position(dy)
429
+ bottom = @bounding_box.stretchy? ? @margin_box.absolute_bottom :
430
+ @bounding_box.absolute_bottom
431
+
432
+ @bounding_box.move_past_bottom if (y - dy) < bottom
433
+
434
+ self.y -= dy
435
+ end
436
+ end
437
+ end
@@ -0,0 +1,141 @@
1
+ # encoding: utf-8
2
+
3
+ # text/rectangle.rb : Implements text boxes
4
+ #
5
+ # Copyright November 2009, Daniel Nelson. All Rights Reserved.
6
+ #
7
+ # This is free software. Please see the LICENSE and COPYING files for details.
8
+ #
9
+
10
+ require_relative "formatted/box"
11
+
12
+ module Prawn
13
+ module Text
14
+ # @group Stable API
15
+
16
+ # Draws the requested text into a box. When the text overflows
17
+ # the rectangle, you shrink to fit, or truncate the text. Text
18
+ # boxes are independent of the document y position.
19
+ #
20
+ # == Encoding
21
+ #
22
+ # Note that strings passed to this function should be encoded as UTF-8.
23
+ # If you get unexpected characters appearing in your rendered document,
24
+ # check this.
25
+ #
26
+ # If the current font is a built-in one, although the string must be
27
+ # encoded as UTF-8, only characters that are available in WinAnsi
28
+ # are allowed.
29
+ #
30
+ # If an empty box is rendered to your PDF instead of the character you
31
+ # wanted it usually means the current font doesn't include that character.
32
+ #
33
+ # == Options (default values marked in [])
34
+ #
35
+ # <tt>:kerning</tt>:: <tt>boolean</tt>. Whether or not to use kerning (if it
36
+ # is available with the current font)
37
+ # [value of document.default_kerning?]
38
+ # <tt>:size</tt>:: <tt>number</tt>. The font size to use. [current font
39
+ # size]
40
+ # <tt>:character_spacing</tt>:: <tt>number</tt>. The amount of space to add
41
+ # to or remove from the default character
42
+ # spacing. [0]
43
+ # <tt>:disable_wrap_by_char</tt>:: <tt>boolean</tt> Whether
44
+ # or not to prevent mid-word breaks when text does not fit in box. [false]
45
+ # <tt>:mode</tt>:: <tt>symbol</tt>. The text rendering mode. See
46
+ # documentation for Prawn::Document#text_rendering_mode
47
+ # for a list of valid options. [:fill]
48
+ # <tt>:style</tt>:: The style to use. The requested style must be part of
49
+ # the current font familly. [current style]
50
+ #
51
+ # <tt>:at</tt>::
52
+ # <tt>[x, y]</tt>. The upper left corner of the box
53
+ # [@document.bounds.left, @document.bounds.top]
54
+ # <tt>:width</tt>::
55
+ # <tt>number</tt>. The width of the box [@document.bounds.right - @at[0]]
56
+ # <tt>:height</tt>::
57
+ # <tt>number</tt>. The height of the box [default_height()]
58
+ # <tt>:direction</tt>::
59
+ # <tt>:ltr</tt>, <tt>:rtl</tt>, Direction of the text (left-to-right
60
+ # or right-to-left) [value of document.text_direction]
61
+ # <tt>:fallback_fonts</tt>::
62
+ # An array of font names. Each name must be the name of an AFM font or
63
+ # the name that was used to register a family of TTF fonts (see
64
+ # Prawn::Document#font_families). If present, then each glyph will be
65
+ # rendered using the first font that includes the glyph, starting with
66
+ # the current font and then moving through :fallback_fonts from
67
+ # left to right.
68
+ # <tt>:align</tt>::
69
+ # <tt>:left</tt>, <tt>:center</tt>, <tt>:right</tt>, or
70
+ # <tt>:justify</tt> Alignment within the bounding box
71
+ # [:left if direction is :ltr, :right if direction is :rtl]
72
+ # <tt>:valign</tt>::
73
+ # <tt>:top</tt>, <tt>:center</tt>, or <tt>:bottom</tt>. Vertical
74
+ # alignment within the bounding box [:top]
75
+ # <tt>:rotate</tt>::
76
+ # <tt>number</tt>. The angle to rotate the text
77
+ # <tt>:rotate_around</tt>::
78
+ # <tt>:center</tt>, <tt>:upper_left</tt>, <tt>:upper_right</tt>,
79
+ # <tt>:lower_right</tt>, or <tt>:lower_left</tt>. The point around which
80
+ # to rotate the text [:upper_left]
81
+ # <tt>:leading</tt>::
82
+ # <tt>number</tt>. Additional space between lines [value of
83
+ # document.default_leading]
84
+ # <tt>:single_line</tt>::
85
+ # <tt>boolean</tt>. If true, then only the first line will be drawn [false]
86
+ # <tt>:overflow</tt>::
87
+ # <tt>:truncate</tt>, <tt>:shrink_to_fit</tt>, or <tt>:expand</tt>
88
+ # This controls the behavior when the amount of text
89
+ # exceeds the available space. [:truncate]
90
+ # <tt>:min_font_size</tt>::
91
+ # <tt>number</tt>. The minimum font size to use when :overflow is set to
92
+ # :shrink_to_fit (that is the font size will not be reduced to less than
93
+ # this value, even if it means that some text will be cut off). [5]
94
+ #
95
+ # == Returns
96
+ #
97
+ # Returns any text that did not print under the current settings.
98
+ #
99
+ # == Exceptions
100
+ #
101
+ # Raises <tt>Prawn::Errors::CannotFit</tt> if not wide enough to print
102
+ # any text
103
+ #
104
+ def text_box(string, options={})
105
+ options = options.dup
106
+ options[:document] = self
107
+
108
+ box = if p = options.delete(:inline_format)
109
+ p = [] unless p.is_a?(Array)
110
+ array = self.text_formatter.format(string, *p)
111
+ Text::Formatted::Box.new(array, options)
112
+ else
113
+ Text::Box.new(string, options)
114
+ end
115
+
116
+ box.render
117
+ end
118
+
119
+ # @group Experimental API
120
+
121
+ # Generally, one would use the Prawn::Text#text_box convenience
122
+ # method. However, using Text::Box.new in conjunction with
123
+ # #render(:dry_run=> true) enables one to do look-ahead calculations prior
124
+ # to placing text on the page, or to determine how much vertical space was
125
+ # consumed by the printed text
126
+ #
127
+ class Box < Prawn::Text::Formatted::Box
128
+
129
+ def initialize(string, options={})
130
+ super([{ :text => string }], options)
131
+ end
132
+
133
+ def render(flags={})
134
+ leftover = super(flags)
135
+ leftover.collect { |hash| hash[:text] }.join
136
+ end
137
+
138
+ end
139
+
140
+ end
141
+ end