prawn 0.15.0 → 1.0.0.rc1

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 (269) hide show
  1. data/COPYING +2 -2
  2. data/LICENSE +1 -1
  3. data/README.md +96 -0
  4. data/Rakefile +27 -30
  5. data/data/fonts/Action Man.dfont +0 -0
  6. data/data/fonts/Activa.ttf +0 -0
  7. data/data/fonts/Chalkboard.ttf +0 -0
  8. data/data/fonts/DejaVuSans.ttf +0 -0
  9. data/data/fonts/Dustismo_Roman.ttf +0 -0
  10. data/data/fonts/comicsans.ttf +0 -0
  11. data/data/fonts/gkai00mp.ttf +0 -0
  12. data/data/images/16bit.alpha +0 -0
  13. data/data/images/16bit.dat +0 -0
  14. data/data/images/dice.alpha +0 -0
  15. data/data/images/dice.dat +0 -0
  16. data/data/images/page_white_text.alpha +0 -0
  17. data/data/images/page_white_text.dat +0 -0
  18. data/data/images/rails.dat +0 -0
  19. data/data/images/rails.png +0 -0
  20. data/data/pdfs/nested_pages.pdf +13 -13
  21. data/lib/prawn.rb +21 -85
  22. data/lib/prawn/compatibility.rb +51 -0
  23. data/lib/prawn/core.rb +85 -0
  24. data/lib/prawn/core/annotations.rb +61 -0
  25. data/lib/prawn/core/byte_string.rb +9 -0
  26. data/lib/prawn/core/destinations.rb +90 -0
  27. data/lib/prawn/core/document_state.rb +78 -0
  28. data/lib/prawn/core/literal_string.rb +16 -0
  29. data/lib/prawn/core/name_tree.rb +177 -0
  30. data/lib/prawn/core/object_store.rb +264 -0
  31. data/lib/prawn/core/page.rb +215 -0
  32. data/lib/prawn/core/pdf_object.rb +108 -0
  33. data/lib/prawn/core/reference.rb +115 -0
  34. data/lib/prawn/core/text.rb +268 -0
  35. data/lib/prawn/core/text/formatted/arranger.rb +294 -0
  36. data/lib/prawn/core/text/formatted/line_wrap.rb +273 -0
  37. data/lib/prawn/core/text/formatted/wrap.rb +153 -0
  38. data/lib/prawn/document.rb +122 -155
  39. data/lib/prawn/document/bounding_box.rb +7 -36
  40. data/lib/prawn/document/column_box.rb +10 -38
  41. data/lib/prawn/document/graphics_state.rb +74 -11
  42. data/lib/prawn/document/internals.rb +23 -24
  43. data/lib/prawn/document/page_geometry.rb +136 -0
  44. data/lib/prawn/document/snapshot.rb +6 -7
  45. data/lib/prawn/document/span.rb +10 -12
  46. data/lib/prawn/encoding.rb +10 -9
  47. data/lib/prawn/errors.rb +30 -15
  48. data/lib/prawn/font.rb +104 -136
  49. data/lib/prawn/font/afm.rb +44 -46
  50. data/lib/prawn/font/dfont.rb +3 -4
  51. data/lib/prawn/font/ttf.rb +50 -31
  52. data/lib/prawn/graphics.rb +57 -302
  53. data/lib/prawn/graphics/cap_style.rb +3 -4
  54. data/lib/prawn/graphics/color.rb +5 -13
  55. data/lib/prawn/graphics/dash.rb +31 -53
  56. data/lib/prawn/graphics/gradient.rb +84 -0
  57. data/lib/prawn/graphics/join_style.rb +7 -9
  58. data/lib/prawn/graphics/transformation.rb +9 -10
  59. data/lib/prawn/graphics/transparency.rb +1 -3
  60. data/lib/prawn/images.rb +59 -69
  61. data/lib/prawn/images/image.rb +22 -6
  62. data/lib/prawn/images/jpg.rb +14 -20
  63. data/lib/prawn/images/png.rb +118 -61
  64. data/lib/prawn/layout.rb +15 -10
  65. data/lib/prawn/layout/grid.rb +54 -66
  66. data/lib/prawn/measurement_extensions.rb +6 -10
  67. data/lib/prawn/measurements.rb +21 -27
  68. data/lib/prawn/outline.rb +308 -6
  69. data/lib/prawn/repeater.rb +8 -10
  70. data/lib/prawn/security.rb +33 -55
  71. data/lib/prawn/security/arcfour.rb +0 -1
  72. data/lib/prawn/stamp.rb +3 -5
  73. data/lib/prawn/table.rb +60 -188
  74. data/lib/prawn/table/cell.rb +44 -272
  75. data/lib/prawn/table/cell/image.rb +3 -2
  76. data/lib/prawn/table/cell/in_table.rb +2 -4
  77. data/lib/prawn/table/cell/subtable.rb +2 -2
  78. data/lib/prawn/table/cell/text.rb +18 -41
  79. data/lib/prawn/table/cells.rb +48 -142
  80. data/lib/prawn/text.rb +25 -32
  81. data/lib/prawn/text/box.rb +6 -12
  82. data/lib/prawn/text/formatted.rb +4 -5
  83. data/lib/prawn/text/formatted/box.rb +59 -96
  84. data/lib/prawn/text/formatted/fragment.rb +23 -34
  85. data/lib/prawn/text/formatted/parser.rb +5 -15
  86. data/prawn.gemspec +13 -24
  87. data/spec/annotations_spec.rb +32 -16
  88. data/spec/bounding_box_spec.rb +17 -119
  89. data/spec/cell_spec.rb +42 -112
  90. data/spec/destinations_spec.rb +5 -5
  91. data/spec/document_spec.rb +111 -155
  92. data/spec/extensions/mocha.rb +0 -1
  93. data/spec/font_spec.rb +99 -149
  94. data/spec/formatted_text_arranger_spec.rb +43 -43
  95. data/spec/formatted_text_box_spec.rb +44 -43
  96. data/spec/formatted_text_fragment_spec.rb +8 -8
  97. data/spec/graphics_spec.rb +68 -151
  98. data/spec/grid_spec.rb +15 -26
  99. data/spec/images_spec.rb +30 -51
  100. data/spec/inline_formatted_text_parser_spec.rb +20 -69
  101. data/spec/jpg_spec.rb +4 -4
  102. data/spec/line_wrap_spec.rb +28 -28
  103. data/spec/measurement_units_spec.rb +6 -6
  104. data/spec/name_tree_spec.rb +112 -0
  105. data/spec/object_store_spec.rb +106 -17
  106. data/spec/outline_spec.rb +63 -103
  107. data/spec/pdf_object_spec.rb +170 -0
  108. data/spec/png_spec.rb +25 -25
  109. data/spec/reference_spec.rb +65 -8
  110. data/spec/repeater_spec.rb +10 -10
  111. data/spec/security_spec.rb +12 -44
  112. data/spec/snapshot_spec.rb +7 -7
  113. data/spec/span_spec.rb +15 -10
  114. data/spec/spec_helper.rb +8 -32
  115. data/spec/stamp_spec.rb +30 -29
  116. data/spec/stroke_styles_spec.rb +18 -36
  117. data/spec/table_spec.rb +111 -706
  118. data/spec/template_spec.rb +297 -0
  119. data/spec/text_at_spec.rb +33 -19
  120. data/spec/text_box_spec.rb +64 -100
  121. data/spec/text_rendering_mode_spec.rb +5 -5
  122. data/spec/text_spacing_spec.rb +4 -4
  123. data/spec/text_spec.rb +64 -84
  124. data/spec/transparency_spec.rb +5 -5
  125. metadata +290 -463
  126. checksums.yaml +0 -7
  127. data/.yardopts +0 -10
  128. data/Gemfile +0 -11
  129. data/data/images/16bit.color +0 -0
  130. data/data/images/dice.color +0 -0
  131. data/data/images/indexed_color.dat +0 -0
  132. data/data/images/indexed_color.png +0 -0
  133. data/data/images/page_white_text.color +0 -0
  134. data/lib/prawn/font_metric_cache.rb +0 -47
  135. data/lib/prawn/graphics/patterns.rb +0 -138
  136. data/lib/prawn/image_handler.rb +0 -36
  137. data/lib/prawn/soft_mask.rb +0 -96
  138. data/lib/prawn/table/cell/span_dummy.rb +0 -93
  139. data/lib/prawn/table/column_width_calculator.rb +0 -61
  140. data/lib/prawn/text/formatted/arranger.rb +0 -290
  141. data/lib/prawn/text/formatted/line_wrap.rb +0 -266
  142. data/lib/prawn/text/formatted/wrap.rb +0 -150
  143. data/lib/prawn/utilities.rb +0 -46
  144. data/manual/basic_concepts/adding_pages.rb +0 -27
  145. data/manual/basic_concepts/basic_concepts.rb +0 -34
  146. data/manual/basic_concepts/creation.rb +0 -39
  147. data/manual/basic_concepts/cursor.rb +0 -33
  148. data/manual/basic_concepts/measurement.rb +0 -25
  149. data/manual/basic_concepts/origin.rb +0 -38
  150. data/manual/basic_concepts/other_cursor_helpers.rb +0 -40
  151. data/manual/bounding_box/bounding_box.rb +0 -39
  152. data/manual/bounding_box/bounds.rb +0 -49
  153. data/manual/bounding_box/canvas.rb +0 -24
  154. data/manual/bounding_box/creation.rb +0 -23
  155. data/manual/bounding_box/indentation.rb +0 -46
  156. data/manual/bounding_box/nesting.rb +0 -45
  157. data/manual/bounding_box/russian_boxes.rb +0 -40
  158. data/manual/bounding_box/stretchy.rb +0 -31
  159. data/manual/document_and_page_options/background.rb +0 -27
  160. data/manual/document_and_page_options/document_and_page_options.rb +0 -32
  161. data/manual/document_and_page_options/metadata.rb +0 -23
  162. data/manual/document_and_page_options/page_margins.rb +0 -38
  163. data/manual/document_and_page_options/page_size.rb +0 -34
  164. data/manual/document_and_page_options/print_scaling.rb +0 -20
  165. data/manual/example_file.rb +0 -111
  166. data/manual/example_helper.rb +0 -411
  167. data/manual/example_package.rb +0 -53
  168. data/manual/example_section.rb +0 -46
  169. data/manual/graphics/circle_and_ellipse.rb +0 -22
  170. data/manual/graphics/color.rb +0 -24
  171. data/manual/graphics/common_lines.rb +0 -30
  172. data/manual/graphics/fill_and_stroke.rb +0 -42
  173. data/manual/graphics/fill_rules.rb +0 -37
  174. data/manual/graphics/gradients.rb +0 -37
  175. data/manual/graphics/graphics.rb +0 -58
  176. data/manual/graphics/helper.rb +0 -24
  177. data/manual/graphics/line_width.rb +0 -35
  178. data/manual/graphics/lines_and_curves.rb +0 -41
  179. data/manual/graphics/polygon.rb +0 -29
  180. data/manual/graphics/rectangle.rb +0 -21
  181. data/manual/graphics/rotate.rb +0 -28
  182. data/manual/graphics/scale.rb +0 -41
  183. data/manual/graphics/soft_masks.rb +0 -46
  184. data/manual/graphics/stroke_cap.rb +0 -31
  185. data/manual/graphics/stroke_dash.rb +0 -48
  186. data/manual/graphics/stroke_join.rb +0 -30
  187. data/manual/graphics/translate.rb +0 -29
  188. data/manual/graphics/transparency.rb +0 -35
  189. data/manual/images/absolute_position.rb +0 -23
  190. data/manual/images/fit.rb +0 -21
  191. data/manual/images/horizontal.rb +0 -25
  192. data/manual/images/images.rb +0 -40
  193. data/manual/images/plain_image.rb +0 -18
  194. data/manual/images/scale.rb +0 -22
  195. data/manual/images/vertical.rb +0 -28
  196. data/manual/images/width_and_height.rb +0 -25
  197. data/manual/layout/boxes.rb +0 -27
  198. data/manual/layout/content.rb +0 -25
  199. data/manual/layout/layout.rb +0 -28
  200. data/manual/layout/simple_grid.rb +0 -23
  201. data/manual/manual/cover.rb +0 -36
  202. data/manual/manual/foreword.rb +0 -85
  203. data/manual/manual/how_to_read_this_manual.rb +0 -41
  204. data/manual/manual/manual.rb +0 -34
  205. data/manual/outline/add_subsection_to.rb +0 -61
  206. data/manual/outline/insert_section_after.rb +0 -47
  207. data/manual/outline/outline.rb +0 -32
  208. data/manual/outline/sections_and_pages.rb +0 -67
  209. data/manual/repeatable_content/page_numbering.rb +0 -54
  210. data/manual/repeatable_content/repeatable_content.rb +0 -31
  211. data/manual/repeatable_content/repeater.rb +0 -55
  212. data/manual/repeatable_content/stamp.rb +0 -41
  213. data/manual/security/encryption.rb +0 -31
  214. data/manual/security/permissions.rb +0 -38
  215. data/manual/security/security.rb +0 -28
  216. data/manual/syntax_highlight.rb +0 -52
  217. data/manual/table/basic_block.rb +0 -53
  218. data/manual/table/before_rendering_page.rb +0 -26
  219. data/manual/table/cell_border_lines.rb +0 -24
  220. data/manual/table/cell_borders_and_bg.rb +0 -31
  221. data/manual/table/cell_dimensions.rb +0 -30
  222. data/manual/table/cell_text.rb +0 -38
  223. data/manual/table/column_widths.rb +0 -30
  224. data/manual/table/content_and_subtables.rb +0 -39
  225. data/manual/table/creation.rb +0 -27
  226. data/manual/table/filtering.rb +0 -36
  227. data/manual/table/flow_and_header.rb +0 -17
  228. data/manual/table/image_cells.rb +0 -33
  229. data/manual/table/position.rb +0 -29
  230. data/manual/table/row_colors.rb +0 -20
  231. data/manual/table/span.rb +0 -30
  232. data/manual/table/style.rb +0 -22
  233. data/manual/table/table.rb +0 -52
  234. data/manual/table/width.rb +0 -27
  235. data/manual/text/alignment.rb +0 -44
  236. data/manual/text/color.rb +0 -24
  237. data/manual/text/column_box.rb +0 -32
  238. data/manual/text/fallback_fonts.rb +0 -37
  239. data/manual/text/font.rb +0 -41
  240. data/manual/text/font_size.rb +0 -45
  241. data/manual/text/font_style.rb +0 -23
  242. data/manual/text/formatted_callbacks.rb +0 -60
  243. data/manual/text/formatted_text.rb +0 -54
  244. data/manual/text/free_flowing_text.rb +0 -51
  245. data/manual/text/group.rb +0 -31
  246. data/manual/text/inline.rb +0 -43
  247. data/manual/text/kerning_and_character_spacing.rb +0 -39
  248. data/manual/text/leading.rb +0 -25
  249. data/manual/text/line_wrapping.rb +0 -41
  250. data/manual/text/paragraph_indentation.rb +0 -26
  251. data/manual/text/positioned_text.rb +0 -38
  252. data/manual/text/registering_families.rb +0 -48
  253. data/manual/text/rendering_and_color.rb +0 -37
  254. data/manual/text/right_to_left_text.rb +0 -43
  255. data/manual/text/rotation.rb +0 -43
  256. data/manual/text/single_usage.rb +0 -37
  257. data/manual/text/text.rb +0 -75
  258. data/manual/text/text_box_excess.rb +0 -32
  259. data/manual/text/text_box_extensions.rb +0 -45
  260. data/manual/text/text_box_overflow.rb +0 -44
  261. data/manual/text/utf8.rb +0 -28
  262. data/manual/text/win_ansi_charset.rb +0 -59
  263. data/spec/acceptance/png.rb +0 -23
  264. data/spec/column_box_spec.rb +0 -65
  265. data/spec/extensions/encoding_helpers.rb +0 -9
  266. data/spec/font_metric_cache_spec.rb +0 -52
  267. data/spec/image_handler_spec.rb +0 -54
  268. data/spec/soft_mask_spec.rb +0 -117
  269. data/spec/table/span_dummy_spec.rb +0 -17
@@ -0,0 +1,153 @@
1
+ require "prawn/core/text/formatted/line_wrap"
2
+ require "prawn/core/text/formatted/arranger"
3
+
4
+ module Prawn
5
+ module Core
6
+ module Text
7
+ module Formatted #:nodoc:
8
+ module Wrap #:nodoc:
9
+
10
+ def initialize(array, options)
11
+ @line_wrap = Prawn::Core::Text::Formatted::LineWrap.new
12
+ @arranger = Prawn::Core::Text::Formatted::Arranger.new(@document,
13
+ :kerning => options[:kerning])
14
+ end
15
+
16
+
17
+ # See the developer documentation for Prawn::Core::Text#wrap
18
+ #
19
+ # Formatted#wrap should set the following variables:
20
+ # <tt>@line_height</tt>::
21
+ # the height of the tallest fragment in the last printed line
22
+ # <tt>@descender</tt>::
23
+ # the descender height of the tallest fragment in the last
24
+ # printed line
25
+ # <tt>@ascender</tt>::
26
+ # the ascender heigth of the tallest fragment in the last
27
+ # printed line
28
+ # <tt>@baseline_y</tt>::
29
+ # the baseline of the current line
30
+ # <tt>@nothing_printed</tt>::
31
+ # set to true until something is printed, then false
32
+ # <tt>@everything_printed</tt>::
33
+ # set to false until everything printed, then true
34
+ #
35
+ # Returns any formatted text that was not printed
36
+ #
37
+ def wrap(array) #:nodoc:
38
+ initialize_wrap(array)
39
+
40
+ stop = false
41
+ while !stop
42
+ # wrap before testing if enough height for this line because the
43
+ # height of the highest fragment on this line will be used to
44
+ # determine the line height
45
+ @line_wrap.wrap_line(:document => @document,
46
+ :kerning => @kerning,
47
+ :width => available_width,
48
+ :arranger => @arranger)
49
+
50
+ if enough_height_for_this_line?
51
+ move_baseline_down
52
+ print_line
53
+ else
54
+ stop = true
55
+ end
56
+
57
+ stop ||= @single_line || @arranger.finished?
58
+ end
59
+ @text = @printed_lines.join("\n")
60
+ @everything_printed = @arranger.finished?
61
+ @arranger.unconsumed
62
+ end
63
+
64
+ private
65
+
66
+ def print_line
67
+ @nothing_printed = false
68
+ printed_fragments = []
69
+ fragments_this_line = []
70
+
71
+ word_spacing = word_spacing_for_this_line
72
+ while fragment = @arranger.retrieve_fragment
73
+ fragment.word_spacing = word_spacing
74
+ if fragment.text == "\n"
75
+ printed_fragments << "\n" if @printed_lines.last == ""
76
+ break
77
+ end
78
+ printed_fragments << fragment.text
79
+ fragments_this_line << fragment
80
+ end
81
+
82
+ accumulated_width = 0
83
+ fragments_this_line.reverse! if @direction == :rtl
84
+ fragments_this_line.each do |fragment|
85
+ fragment.default_direction = @direction
86
+ format_and_draw_fragment(fragment, accumulated_width,
87
+ @line_wrap.width, word_spacing)
88
+ accumulated_width += fragment.width
89
+ end
90
+
91
+ if "".respond_to?(:force_encoding)
92
+ printed_fragments.map! { |s| s.force_encoding("utf-8") }
93
+ end
94
+ @printed_lines << printed_fragments.join
95
+ end
96
+
97
+ def word_spacing_for_this_line
98
+ if @align == :justify &&
99
+ @line_wrap.space_count > 0 &&
100
+ !@line_wrap.paragraph_finished?
101
+ (available_width - @line_wrap.width) / @line_wrap.space_count
102
+ else
103
+ 0
104
+ end
105
+ end
106
+
107
+ def enough_height_for_this_line?
108
+ @line_height = @arranger.max_line_height
109
+ @descender = @arranger.max_descender
110
+ @ascender = @arranger.max_ascender
111
+ if @baseline_y == 0
112
+ diff = @ascender + @descender
113
+ else
114
+ diff = @descender + @line_height + @leading
115
+ end
116
+ required_total_height = @baseline_y.abs + diff
117
+ if required_total_height > @height + 0.0001
118
+ # no room for the full height of this line
119
+ @arranger.repack_unretrieved
120
+ false
121
+ else
122
+ true
123
+ end
124
+ end
125
+
126
+ def initialize_wrap(array)
127
+ @text = nil
128
+ @arranger.format_array = array
129
+
130
+ # these values will depend on the maximum value within a given line
131
+ @line_height = 0
132
+ @descender = 0
133
+ @ascender = 0
134
+ @baseline_y = 0
135
+
136
+ @printed_lines = []
137
+ @nothing_printed = true
138
+ @everything_printed = false
139
+ end
140
+
141
+ def format_and_draw_fragment(fragment, accumulated_width,
142
+ line_width, word_spacing)
143
+ @arranger.apply_color_and_font_settings(fragment) do
144
+ draw_fragment(fragment, accumulated_width,
145
+ line_width, word_spacing)
146
+ end
147
+ end
148
+
149
+ end
150
+ end
151
+ end
152
+ end
153
+ end
@@ -7,13 +7,13 @@
7
7
  # This is free software. Please see the LICENSE and COPYING files for details.
8
8
 
9
9
  require "stringio"
10
-
11
- require_relative "document/bounding_box"
12
- require_relative "document/column_box"
13
- require_relative "document/internals"
14
- require_relative "document/span"
15
- require_relative "document/snapshot"
16
- require_relative "document/graphics_state"
10
+ require "prawn/document/page_geometry"
11
+ require "prawn/document/bounding_box"
12
+ require "prawn/document/column_box"
13
+ require "prawn/document/internals"
14
+ require "prawn/document/span"
15
+ require "prawn/document/snapshot"
16
+ require "prawn/document/graphics_state"
17
17
 
18
18
  module Prawn
19
19
 
@@ -52,8 +52,8 @@ module Prawn
52
52
  #
53
53
  class Document
54
54
  include Prawn::Document::Internals
55
- include PDF::Core::Annotations
56
- include PDF::Core::Destinations
55
+ include Prawn::Core::Annotations
56
+ include Prawn::Core::Destinations
57
57
  include Prawn::Document::Snapshot
58
58
  include Prawn::Document::GraphicsState
59
59
  include Prawn::Document::Security
@@ -61,17 +61,6 @@ module Prawn
61
61
  include Prawn::Graphics
62
62
  include Prawn::Images
63
63
  include Prawn::Stamp
64
- include Prawn::SoftMask
65
-
66
- # @group Extension API
67
-
68
- # NOTE: We probably need to rethink the options validation system, but this
69
- # constant temporarily allows for extensions to modify the list.
70
-
71
- VALID_OPTIONS = [:page_size, :page_layout, :margin, :left_margin,
72
- :right_margin, :top_margin, :bottom_margin, :skip_page_creation,
73
- :compress, :skip_encoding, :background, :info,
74
- :optimize_objects, :text_formatter, :print_scaling]
75
64
 
76
65
  # Any module added to this array will be included into instances of
77
66
  # Prawn::Document at the per-object level. These will also be inherited by
@@ -93,28 +82,14 @@ module Prawn
93
82
  # party!
94
83
  # end
95
84
  #
96
- #
97
85
  def self.extensions
98
86
  @extensions ||= []
99
87
  end
100
88
 
101
- # @private
102
- def self.inherited(base)
89
+ def self.inherited(base) #:nodoc:
103
90
  extensions.each { |e| base.extensions << e }
104
91
  end
105
92
 
106
- # @group Stable Attributes
107
-
108
- attr_accessor :margin_box
109
- attr_reader :margins, :y
110
- attr_accessor :page_number
111
-
112
- # @group Extension Attributes
113
-
114
- attr_accessor :text_formatter
115
-
116
- # @group Stable API
117
-
118
93
  # Creates and renders a PDF document.
119
94
  #
120
95
  # When using the implicit block form, Prawn will evaluate the block
@@ -161,9 +136,8 @@ module Prawn
161
136
  # <tt>:compress</tt>:: Compresses content streams before rendering them [false]
162
137
  # <tt>:optimize_objects</tt>:: Reduce number of PDF objects in output, at expense of render time [false]
163
138
  # <tt>:background</tt>:: An image path to be used as background on all pages [nil]
164
- # <tt>:background_scale</tt>:: Backgound image scale [1] [nil]
165
139
  # <tt>:info</tt>:: Generic hash allowing for custom metadata properties [nil]
166
- # <tt>:text_formatter</tt>: The text formatter to use for <tt>:inline_format</tt>ted text [Prawn::Text::Formatted::Parser]
140
+ # <tt>:template</tt>:: The path to an existing PDF file to use as a template [nil]
167
141
  #
168
142
  # Setting e.g. the :margin to 100 points and the :left_margin to 50 will result in margins
169
143
  # of 100 points on every side except for the left, where it will be 50.
@@ -192,25 +166,25 @@ module Prawn
192
166
  # pdf = Prawn::Document.new(:page_size => [200, 300])
193
167
  #
194
168
  # # New document, with background
195
- # pdf = Prawn::Document.new(:background => "#{Prawn::DATADIR}/images/pigs.jpg")
169
+ # pdf = Prawn::Document.new(:background => "#{Prawn::BASEDIR}/data/images/pigs.jpg")
196
170
  #
197
171
  def initialize(options={},&block)
198
172
  options = options.dup
199
173
 
200
- Prawn.verify_options VALID_OPTIONS, options
174
+ Prawn.verify_options [:page_size, :page_layout, :margin, :left_margin,
175
+ :right_margin, :top_margin, :bottom_margin, :skip_page_creation,
176
+ :compress, :skip_encoding, :background, :info,
177
+ :optimize_objects, :template], options
201
178
 
202
179
  # need to fix, as the refactoring breaks this
203
180
  # raise NotImplementedError if options[:skip_page_creation]
204
181
 
205
182
  self.class.extensions.reverse_each { |e| extend e }
206
- @internal_state = PDF::Core::DocumentState.new(options)
183
+ @internal_state = Prawn::Core::DocumentState.new(options)
207
184
  @internal_state.populate_pages_from_store(self)
208
185
  min_version(state.store.min_version) if state.store.min_version
209
186
 
210
- min_version(1.6) if options[:print_scaling] == :none
211
-
212
187
  @background = options[:background]
213
- @background_scale = options[:background_scale] || 1
214
188
  @font_size = 12
215
189
 
216
190
  @bounding_box = nil
@@ -218,12 +192,19 @@ module Prawn
218
192
 
219
193
  @page_number = 0
220
194
 
221
- @text_formatter = options.delete(:text_formatter) || Text::Formatted::Parser
222
-
223
195
  options[:size] = options.delete(:page_size)
224
196
  options[:layout] = options.delete(:page_layout)
225
197
 
226
- initialize_first_page(options)
198
+ if options[:template]
199
+ fresh_content_streams(options)
200
+ go_to_page(1)
201
+ else
202
+ if options[:skip_page_creation] || options[:template]
203
+ start_new_page(options.merge(:orphan => true))
204
+ else
205
+ start_new_page(options)
206
+ end
207
+ end
227
208
 
228
209
  @bounding_box = @margin_box
229
210
 
@@ -232,7 +213,18 @@ module Prawn
232
213
  end
233
214
  end
234
215
 
235
- # @group Stable API
216
+ attr_accessor :margin_box
217
+ attr_reader :margins, :y
218
+ attr_writer :font_size
219
+ attr_accessor :page_number
220
+
221
+ def state
222
+ @internal_state
223
+ end
224
+
225
+ def page
226
+ state.page
227
+ end
236
228
 
237
229
  # Creates and advances to a new page in the document.
238
230
  #
@@ -244,6 +236,11 @@ module Prawn
244
236
  # pdf.start_new_page(:left_margin => 50, :right_margin => 50)
245
237
  # pdf.start_new_page(:margin => 100)
246
238
  #
239
+ # A template for a page can be specified by pointing to the path of and existing pdf.
240
+ # One can also specify which page of the template which defaults otherwise to 1.
241
+ #
242
+ # pdf.start_new_page(:template => multipage_template.pdf, :template_page => 2)
243
+ #
247
244
  def start_new_page(options = {})
248
245
  if last_page = state.page
249
246
  last_page_size = last_page.size
@@ -255,13 +252,14 @@ module Prawn
255
252
  :layout => options[:layout] || last_page_layout,
256
253
  :margins => last_page_margins}
257
254
  if last_page
258
- new_graphic_state = last_page.graphic_state.dup if last_page.graphic_state
255
+ new_graphic_state = last_page.graphic_state.dup
259
256
  #erase the color space so that it gets reset on new page for fussy pdf-readers
260
- new_graphic_state.color_space = {} if new_graphic_state
257
+ new_graphic_state.color_space = {}
261
258
  page_options.merge!(:graphic_state => new_graphic_state)
262
259
  end
260
+ merge_template_options(page_options, options) if options[:template]
263
261
 
264
- state.page = PDF::Core::Page.new(self, page_options)
262
+ state.page = Prawn::Core::Page.new(self, page_options)
265
263
 
266
264
  apply_margin_options(options)
267
265
  generate_margin_box
@@ -272,13 +270,14 @@ module Prawn
272
270
  @bounding_box = @margin_box
273
271
  end
274
272
 
275
- use_graphic_settings
273
+ state.page.new_content_stream if options[:template]
274
+ use_graphic_settings(options[:template])
276
275
 
277
276
  unless options[:orphan]
278
277
  state.insert_page(state.page, @page_number)
279
278
  @page_number += 1
280
279
 
281
- canvas { image(@background, :scale => @background_scale, :at => bounds.top_left) } if @background
280
+ canvas { image(@background, :at => bounds.top_left) } if @background
282
281
  @y = @bounding_box.absolute_top
283
282
 
284
283
  float do
@@ -349,26 +348,19 @@ module Prawn
349
348
  self.y = original_y
350
349
  end
351
350
 
352
- # Renders the PDF document to string.
353
- # Pass an open file descriptor to render to file.
351
+ # Renders the PDF document to string
354
352
  #
355
- def render(output = StringIO.new)
356
- if output.instance_of?(StringIO)
357
- output.set_encoding(::Encoding::ASCII_8BIT)
358
- end
353
+ def render
354
+ output = StringIO.new
359
355
  finalize_all_page_contents
360
356
 
361
357
  render_header(output)
362
358
  render_body(output)
363
359
  render_xref(output)
364
360
  render_trailer(output)
365
- if output.instance_of?(StringIO)
366
- str = output.string
367
- str.force_encoding(::Encoding::ASCII_8BIT)
368
- return str
369
- else
370
- return nil
371
- end
361
+ str = output.string
362
+ str.force_encoding("ASCII-8BIT") if str.respond_to?(:force_encoding)
363
+ str
372
364
  end
373
365
 
374
366
  # Renders the PDF document to file.
@@ -376,7 +368,8 @@ module Prawn
376
368
  # pdf.render_file "foo.pdf"
377
369
  #
378
370
  def render_file(filename)
379
- File.open(filename, "wb") { |f| render(f) }
371
+ Kernel.const_defined?("Encoding") ? mode = "wb:ASCII-8BIT" : mode = "wb"
372
+ File.open(filename,mode) { |f| f << render }
380
373
  end
381
374
 
382
375
  # The bounds method returns the current bounding box you are currently in,
@@ -412,7 +405,6 @@ module Prawn
412
405
 
413
406
  # Returns the innermost non-stretchy bounding box.
414
407
  #
415
- # @private
416
408
  def reference_bounds
417
409
  @bounding_box.reference_bounds
418
410
  end
@@ -498,6 +490,47 @@ module Prawn
498
490
  bounds.indent(left, right, &block)
499
491
  end
500
492
 
493
+
494
+ def mask(*fields) # :nodoc:
495
+ # Stores the current state of the named attributes, executes the block, and
496
+ # then restores the original values after the block has executed.
497
+ # -- I will remove the nodoc if/when this feature is a little less hacky
498
+ stored = {}
499
+ fields.each { |f| stored[f] = send(f) }
500
+ yield
501
+ fields.each { |f| send("#{f}=", stored[f]) }
502
+ end
503
+
504
+ # Attempts to group the given block vertically within the current context.
505
+ # First attempts to render it in the current position on the current page.
506
+ # If that attempt overflows, it is tried anew after starting a new context
507
+ # (page or column). Returns a logically true value if the content fits in
508
+ # one page/column, false if a new page or column was needed.
509
+ #
510
+ # Raises CannotGroup if the provided content is too large to fit alone in
511
+ # the current page or column.
512
+ #
513
+ def group(second_attempt=false)
514
+ old_bounding_box = @bounding_box
515
+ @bounding_box = SimpleDelegator.new(@bounding_box)
516
+
517
+ def @bounding_box.move_past_bottom
518
+ raise RollbackTransaction
519
+ end
520
+
521
+ success = transaction { yield }
522
+
523
+ @bounding_box = old_bounding_box
524
+
525
+ unless success
526
+ raise Prawn::Errors::CannotGroup if second_attempt
527
+ old_bounding_box.move_past_bottom
528
+ group(second_attempt=true) { yield }
529
+ end
530
+
531
+ success
532
+ end
533
+
501
534
  # Places a text box on specified pages for page numbering. This should be called
502
535
  # towards the end of document creation, after all your content is already in
503
536
  # place. In your template string, <page> refers to the current page, and
@@ -506,15 +539,15 @@ module Prawn
506
539
  # through existing pages after they are created.
507
540
  #
508
541
  # Parameters are:
509
- #
510
- # <tt>string</tt>:: Template string for page number wording.
542
+ #
543
+ # <tt>string</tt>:: Template string for page number wording.
511
544
  # Should include '<page>' and, optionally, '<total>'.
512
545
  # <tt>options</tt>:: A hash for page numbering and text box options.
513
- # <tt>:page_filter</tt>:: A filter to specify which pages to place page numbers on.
546
+ # <tt>:page_filter</tt>:: A filter to specify which pages to place page numbers on.
514
547
  # Refer to the method 'page_match?'
515
548
  # <tt>:start_count_at</tt>:: The starting count to increment pages from.
516
549
  # <tt>:total_pages</tt>:: If provided, will replace <total> with the value given.
517
- # Useful to override the total number of pages when using
550
+ # Useful to override the total number of pages when using
518
551
  # the start_count_at option.
519
552
  # <tt>:color</tt>:: Text fill color.
520
553
  #
@@ -525,7 +558,7 @@ module Prawn
525
558
  # five.
526
559
  #
527
560
  # Prawn::Document.generate("page_with_numbering.pdf") do
528
- # number_pages "<page> in a total of <total>",
561
+ # number_pages "<page> in a total of <total>",
529
562
  # {:start_count_at => 5,
530
563
  # :page_filter => lambda{ |pg| pg != 1 },
531
564
  # :at => [bounds.right - 50, 0],
@@ -544,8 +577,8 @@ module Prawn
544
577
  total_pages = opts.delete(:total_pages)
545
578
  txtcolor = opts.delete(:color)
546
579
  # An explicit height so that we can draw page numbers in the margins
547
- opts[:height] = 50 unless opts.has_key?(:height)
548
-
580
+ opts[:height] = 50
581
+
549
582
  start_count = false
550
583
  pseudopage = 0
551
584
  (1..page_count).each do |p|
@@ -556,7 +589,7 @@ module Prawn
556
589
  else
557
590
  start_count_at.to_i
558
591
  end
559
- end
592
+ end
560
593
  if page_match?(page_filter, p)
561
594
  go_to_page(p)
562
595
  # have to use fill_color here otherwise text reverts back to default fill color
@@ -565,53 +598,13 @@ module Prawn
565
598
  str = string.gsub("<page>","#{pseudopage}").gsub("<total>","#{total_pages}")
566
599
  text_box str, opts
567
600
  start_count = true # increment page count as soon as first match found
568
- end
601
+ end
569
602
  pseudopage += 1 if start_count
570
603
  end
571
604
  end
572
605
 
573
- # Returns true if content streams will be compressed before rendering,
574
- # false otherwise
575
- #
576
- def compression_enabled?
577
- !!state.compress
578
- end
579
-
580
- # @group Experimental API
581
-
582
- # Attempts to group the given block vertically within the current context.
583
- # First attempts to render it in the current position on the current page.
584
- # If that attempt overflows, it is tried anew after starting a new context
585
- # (page or column). Returns a logically true value if the content fits in
586
- # one page/column, false if a new page or column was needed.
587
- #
588
- # Raises CannotGroup if the provided content is too large to fit alone in
589
- # the current page or column.
590
- #
591
- def group(second_attempt=false)
592
- old_bounding_box = @bounding_box
593
- @bounding_box = SimpleDelegator.new(@bounding_box)
594
-
595
- # @private
596
- def @bounding_box.move_past_bottom
597
- raise RollbackTransaction
598
- end
599
-
600
- success = transaction { yield }
601
-
602
- @bounding_box = old_bounding_box
603
-
604
- unless success
605
- raise Prawn::Errors::CannotGroup if second_attempt
606
- old_bounding_box.move_past_bottom
607
- group(second_attempt=true) { yield }
608
- end
609
-
610
- success
611
- end
612
-
613
606
  # Provides a way to execute a block of code repeatedly based on a
614
- # page_filter.
607
+ # page_filter.
615
608
  #
616
609
  # Available page filters are:
617
610
  # :all repeats on every page
@@ -619,7 +612,7 @@ module Prawn
619
612
  # :even repeats on even pages
620
613
  # some_array repeats on every page listed in the array
621
614
  # some_range repeats on every page included in the range
622
- # some_lambda yields page number and repeats for true return values
615
+ # some_lambda yields page number and repeats for true return values
623
616
  def page_match?(page_filter, page_number)
624
617
  case page_filter
625
618
  when :all
@@ -633,47 +626,25 @@ module Prawn
633
626
  when Proc
634
627
  page_filter.call(page_number)
635
628
  end
636
- end
637
-
638
- # @private
639
-
640
- def mask(*fields)
641
- # Stores the current state of the named attributes, executes the block, and
642
- # then restores the original values after the block has executed.
643
- # -- I will remove the nodoc if/when this feature is a little less hacky
644
- stored = {}
645
- fields.each { |f| stored[f] = send(f) }
646
- yield
647
- fields.each { |f| send("#{f}=", stored[f]) }
648
- end
649
-
650
- # @group Extension API
651
-
652
- def initialize_first_page(options)
653
- if options[:skip_page_creation]
654
- start_new_page(options.merge(:orphan => true))
655
- else
656
- start_new_page(options)
657
- end
658
- end
629
+ end
659
630
 
660
- ## Internals. Don't depend on them!
661
631
 
662
- # @private
663
- def state
664
- @internal_state
665
- end
666
-
667
- # @private
668
- def page
669
- state.page
632
+ # Returns true if content streams will be compressed before rendering,
633
+ # false otherwise
634
+ #
635
+ def compression_enabled?
636
+ !!state.compress
670
637
  end
671
638
 
672
639
  private
673
640
 
641
+ def merge_template_options(page_options, options)
642
+ object_id = state.store.import_page(options[:template], options[:template_page] || 1)
643
+ page_options.merge!(:object_id => object_id )
644
+ end
674
645
 
675
646
  # setting override_settings to true ensures that a new graphic state does not end up using
676
- # previous settings.
647
+ # previous settings especially from imported template streams
677
648
  def use_graphic_settings(override_settings = false)
678
649
  set_fill_color if current_fill_color != "000000" || override_settings
679
650
  set_stroke_color if current_stroke_color != "000000" || override_settings
@@ -726,9 +697,5 @@ module Prawn
726
697
  end
727
698
  end
728
699
  end
729
-
730
- def font_metric_cache #:nodoc:
731
- @font_metric_cache ||= FontMetricCache.new( self )
732
- end
733
700
  end
734
701
  end