prawn-core 0.5.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 (186) hide show
  1. data/COPYING +340 -0
  2. data/LICENSE +56 -0
  3. data/README +121 -0
  4. data/Rakefile +74 -0
  5. data/data/encodings/win_ansi.txt +29 -0
  6. data/data/fonts/Action Man.dfont +0 -0
  7. data/data/fonts/Activa.ttf +0 -0
  8. data/data/fonts/Chalkboard.ttf +0 -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/DejaVuSans.ttf +0 -0
  14. data/data/fonts/Dustismo_Roman.ttf +0 -0
  15. data/data/fonts/Helvetica-Bold.afm +2827 -0
  16. data/data/fonts/Helvetica-BoldOblique.afm +2827 -0
  17. data/data/fonts/Helvetica-Oblique.afm +3051 -0
  18. data/data/fonts/Helvetica.afm +3051 -0
  19. data/data/fonts/MustRead.html +19 -0
  20. data/data/fonts/Symbol.afm +213 -0
  21. data/data/fonts/Times-Bold.afm +2588 -0
  22. data/data/fonts/Times-BoldItalic.afm +2384 -0
  23. data/data/fonts/Times-Italic.afm +2667 -0
  24. data/data/fonts/Times-Roman.afm +2419 -0
  25. data/data/fonts/ZapfDingbats.afm +225 -0
  26. data/data/fonts/comicsans.ttf +0 -0
  27. data/data/fonts/gkai00mp.ttf +0 -0
  28. data/data/images/16bit.alpha +0 -0
  29. data/data/images/16bit.dat +0 -0
  30. data/data/images/16bit.png +0 -0
  31. data/data/images/arrow.png +0 -0
  32. data/data/images/arrow2.png +0 -0
  33. data/data/images/barcode_issue.png +0 -0
  34. data/data/images/dice.alpha +0 -0
  35. data/data/images/dice.dat +0 -0
  36. data/data/images/dice.png +0 -0
  37. data/data/images/dice_interlaced.png +0 -0
  38. data/data/images/fractal.jpg +0 -0
  39. data/data/images/letterhead.jpg +0 -0
  40. data/data/images/page_white_text.alpha +0 -0
  41. data/data/images/page_white_text.dat +0 -0
  42. data/data/images/page_white_text.png +0 -0
  43. data/data/images/pigs.jpg +0 -0
  44. data/data/images/rails.dat +0 -0
  45. data/data/images/rails.png +0 -0
  46. data/data/images/ruport.png +0 -0
  47. data/data/images/ruport_data.dat +0 -0
  48. data/data/images/ruport_transparent.png +0 -0
  49. data/data/images/ruport_type0.png +0 -0
  50. data/data/images/stef.jpg +0 -0
  51. data/data/images/tru256.bmp +0 -0
  52. data/data/images/web-links.dat +1 -0
  53. data/data/images/web-links.png +0 -0
  54. data/data/shift_jis_text.txt +1 -0
  55. data/examples/bounding_box/bounding_boxes.rb +44 -0
  56. data/examples/bounding_box/russian_boxes.rb +37 -0
  57. data/examples/column_box/column_box_example.rb +44 -0
  58. data/examples/general/background.rb +20 -0
  59. data/examples/general/canvas.rb +16 -0
  60. data/examples/general/measurement_units.rb +52 -0
  61. data/examples/general/metadata-info.rb +17 -0
  62. data/examples/general/multi_page_layout.rb +17 -0
  63. data/examples/general/page_geometry.rb +32 -0
  64. data/examples/graphics/basic_images.rb +24 -0
  65. data/examples/graphics/cmyk.rb +13 -0
  66. data/examples/graphics/curves.rb +12 -0
  67. data/examples/graphics/hexagon.rb +14 -0
  68. data/examples/graphics/image_fit.rb +16 -0
  69. data/examples/graphics/image_flow.rb +38 -0
  70. data/examples/graphics/image_position.rb +18 -0
  71. data/examples/graphics/line.rb +33 -0
  72. data/examples/graphics/png_types.rb +23 -0
  73. data/examples/graphics/polygons.rb +17 -0
  74. data/examples/graphics/remote_images.rb +12 -0
  75. data/examples/graphics/ruport_style_helpers.rb +20 -0
  76. data/examples/graphics/stroke_bounds.rb +21 -0
  77. data/examples/m17n/chinese_text_wrapping.rb +20 -0
  78. data/examples/m17n/euro.rb +16 -0
  79. data/examples/m17n/sjis.rb +29 -0
  80. data/examples/m17n/utf8.rb +14 -0
  81. data/examples/m17n/win_ansi_charset.rb +55 -0
  82. data/examples/text/alignment.rb +19 -0
  83. data/examples/text/dfont.rb +49 -0
  84. data/examples/text/family_based_styling.rb +25 -0
  85. data/examples/text/font_calculations.rb +92 -0
  86. data/examples/text/font_size.rb +34 -0
  87. data/examples/text/kerning.rb +31 -0
  88. data/examples/text/simple_text.rb +18 -0
  89. data/examples/text/simple_text_ttf.rb +18 -0
  90. data/examples/text/span.rb +30 -0
  91. data/examples/text/text_box.rb +26 -0
  92. data/examples/text/text_flow.rb +68 -0
  93. data/lib/prawn/compatibility.rb +38 -0
  94. data/lib/prawn/core.rb +79 -0
  95. data/lib/prawn/document.rb +399 -0
  96. data/lib/prawn/document/annotations.rb +63 -0
  97. data/lib/prawn/document/bounding_box.rb +377 -0
  98. data/lib/prawn/document/column_box.rb +89 -0
  99. data/lib/prawn/document/destinations.rb +81 -0
  100. data/lib/prawn/document/internals.rb +133 -0
  101. data/lib/prawn/document/page_geometry.rb +149 -0
  102. data/lib/prawn/document/span.rb +55 -0
  103. data/lib/prawn/document/text.rb +186 -0
  104. data/lib/prawn/document/text/box.rb +83 -0
  105. data/lib/prawn/document/text/wrapping.rb +59 -0
  106. data/lib/prawn/encoding.rb +121 -0
  107. data/lib/prawn/errors.rb +49 -0
  108. data/lib/prawn/font.rb +292 -0
  109. data/lib/prawn/font/afm.rb +202 -0
  110. data/lib/prawn/font/dfont.rb +31 -0
  111. data/lib/prawn/font/ttf.rb +327 -0
  112. data/lib/prawn/graphics.rb +257 -0
  113. data/lib/prawn/graphics/color.rb +141 -0
  114. data/lib/prawn/images.rb +339 -0
  115. data/lib/prawn/images/jpg.rb +45 -0
  116. data/lib/prawn/images/png.rb +217 -0
  117. data/lib/prawn/literal_string.rb +14 -0
  118. data/lib/prawn/measurement_extensions.rb +46 -0
  119. data/lib/prawn/measurements.rb +71 -0
  120. data/lib/prawn/name_tree.rb +165 -0
  121. data/lib/prawn/pdf_object.rb +77 -0
  122. data/lib/prawn/reference.rb +59 -0
  123. data/spec/annotations_spec.rb +90 -0
  124. data/spec/bounding_box_spec.rb +141 -0
  125. data/spec/destinations_spec.rb +15 -0
  126. data/spec/document_spec.rb +178 -0
  127. data/spec/font_spec.rb +274 -0
  128. data/spec/graphics_spec.rb +209 -0
  129. data/spec/images_spec.rb +79 -0
  130. data/spec/jpg_spec.rb +25 -0
  131. data/spec/measurement_units_spec.rb +23 -0
  132. data/spec/name_tree_spec.rb +103 -0
  133. data/spec/pdf_object_spec.rb +117 -0
  134. data/spec/png_spec.rb +236 -0
  135. data/spec/reference_spec.rb +42 -0
  136. data/spec/span_spec.rb +45 -0
  137. data/spec/spec_helper.rb +23 -0
  138. data/spec/text_box_spec.rb +83 -0
  139. data/spec/text_spec.rb +178 -0
  140. data/vendor/pdf-inspector/README +18 -0
  141. data/vendor/pdf-inspector/lib/pdf/inspector.rb +25 -0
  142. data/vendor/pdf-inspector/lib/pdf/inspector/graphics.rb +80 -0
  143. data/vendor/pdf-inspector/lib/pdf/inspector/page.rb +16 -0
  144. data/vendor/pdf-inspector/lib/pdf/inspector/text.rb +31 -0
  145. data/vendor/pdf-inspector/lib/pdf/inspector/xobject.rb +19 -0
  146. data/vendor/ttfunk/data/fonts/DejaVuSans.ttf +0 -0
  147. data/vendor/ttfunk/data/fonts/comicsans.ttf +0 -0
  148. data/vendor/ttfunk/example.rb +45 -0
  149. data/vendor/ttfunk/lib/ttfunk.rb +102 -0
  150. data/vendor/ttfunk/lib/ttfunk/directory.rb +17 -0
  151. data/vendor/ttfunk/lib/ttfunk/encoding/mac_roman.rb +88 -0
  152. data/vendor/ttfunk/lib/ttfunk/encoding/windows_1252.rb +69 -0
  153. data/vendor/ttfunk/lib/ttfunk/reader.rb +44 -0
  154. data/vendor/ttfunk/lib/ttfunk/resource_file.rb +78 -0
  155. data/vendor/ttfunk/lib/ttfunk/subset.rb +18 -0
  156. data/vendor/ttfunk/lib/ttfunk/subset/base.rb +141 -0
  157. data/vendor/ttfunk/lib/ttfunk/subset/mac_roman.rb +46 -0
  158. data/vendor/ttfunk/lib/ttfunk/subset/unicode.rb +48 -0
  159. data/vendor/ttfunk/lib/ttfunk/subset/unicode_8bit.rb +63 -0
  160. data/vendor/ttfunk/lib/ttfunk/subset/windows_1252.rb +51 -0
  161. data/vendor/ttfunk/lib/ttfunk/subset_collection.rb +72 -0
  162. data/vendor/ttfunk/lib/ttfunk/table.rb +46 -0
  163. data/vendor/ttfunk/lib/ttfunk/table/cmap.rb +34 -0
  164. data/vendor/ttfunk/lib/ttfunk/table/cmap/format00.rb +54 -0
  165. data/vendor/ttfunk/lib/ttfunk/table/cmap/format04.rb +126 -0
  166. data/vendor/ttfunk/lib/ttfunk/table/cmap/subtable.rb +79 -0
  167. data/vendor/ttfunk/lib/ttfunk/table/glyf.rb +64 -0
  168. data/vendor/ttfunk/lib/ttfunk/table/glyf/compound.rb +81 -0
  169. data/vendor/ttfunk/lib/ttfunk/table/glyf/simple.rb +37 -0
  170. data/vendor/ttfunk/lib/ttfunk/table/head.rb +44 -0
  171. data/vendor/ttfunk/lib/ttfunk/table/hhea.rb +41 -0
  172. data/vendor/ttfunk/lib/ttfunk/table/hmtx.rb +47 -0
  173. data/vendor/ttfunk/lib/ttfunk/table/kern.rb +79 -0
  174. data/vendor/ttfunk/lib/ttfunk/table/kern/format0.rb +62 -0
  175. data/vendor/ttfunk/lib/ttfunk/table/loca.rb +43 -0
  176. data/vendor/ttfunk/lib/ttfunk/table/maxp.rb +40 -0
  177. data/vendor/ttfunk/lib/ttfunk/table/name.rb +119 -0
  178. data/vendor/ttfunk/lib/ttfunk/table/os2.rb +78 -0
  179. data/vendor/ttfunk/lib/ttfunk/table/post.rb +91 -0
  180. data/vendor/ttfunk/lib/ttfunk/table/post/format10.rb +43 -0
  181. data/vendor/ttfunk/lib/ttfunk/table/post/format20.rb +35 -0
  182. data/vendor/ttfunk/lib/ttfunk/table/post/format25.rb +23 -0
  183. data/vendor/ttfunk/lib/ttfunk/table/post/format30.rb +17 -0
  184. data/vendor/ttfunk/lib/ttfunk/table/post/format40.rb +17 -0
  185. data/vendor/ttfunk/lib/ttfunk/table/simple.rb +14 -0
  186. metadata +245 -0
@@ -0,0 +1,68 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Basic text flowing example including the use of bounding boxes. A somewhat
4
+ # old example, mostly retained for nostalgia.
5
+ #
6
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', '..', 'lib'))
7
+ require "prawn/core"
8
+
9
+ content = <<-EOS
10
+ How does
11
+ Prawn deal with
12
+ white
13
+ space
14
+
15
+ and
16
+
17
+ line
18
+ breaks?
19
+ EOS
20
+
21
+ poem = <<-EOS
22
+ GOOD-BYE
23
+
24
+ Good-bye, proud world! I'm going home: Thou art not my friend, and I'm not thine. Long through thy weary crowds I roam; A river-ark on the ocean brine, Long I've been tossed like the driven foam: But now, proud world! I'm going home.
25
+
26
+ Good-bye to Flattery's fawning face; To Grandeur with his wise grimace; To upstart Wealth's averted eye; To supple Office, low and high; To crowded halls, to court and street; To frozen hearts and hasting feet; To those who go, and those who come; Good-bye, proud world! I'm going home.
27
+
28
+ I am going to my own hearth-stone, Bosomed in yon green hills alone,-- secret nook in a pleasant land, Whose groves the frolic fairies planned; Where arches green, the livelong day, Echo the blackbird's roundelay, And vulgar feet have never trod A spot that is sacred to thought and God.
29
+
30
+ O, when I am safe in my sylvan home, I tread on the pride of Greece and Rome; And when I am stretched beneath the pines, Where the evening star so holy shines, I laugh at the lore and the pride of man, At the sophist schools and the learned clan; For what are they all, in their high conceit, When man in the bush with God may meet?
31
+ EOS
32
+
33
+ overflow = "This text should flow gracefully onto the next page, like a stream"+
34
+ " flows elegantly from a mountain lake down into the village below."
35
+
36
+ Prawn::Document.generate("flow.pdf") do |pdf|
37
+
38
+ pdf.font "Times-Roman"
39
+ pdf.stroke_line [pdf.bounds.left, pdf.bounds.top],
40
+ [pdf.bounds.right, pdf.bounds.top]
41
+
42
+ pdf.text content, :size => 10
43
+
44
+ pdf.bounding_box([100,600], :width => 200, :height => 525) do
45
+ pdf.stroke_line [pdf.bounds.left, pdf.bounds.top],
46
+ [pdf.bounds.right, pdf.bounds.top]
47
+ pdf.text poem, :size => 12
48
+ end
49
+
50
+ pdf.bounding_box([325,600], :width => 200, :height => 525) do
51
+ pdf.stroke_line [pdf.bounds.left, pdf.bounds.top],
52
+ [pdf.bounds.right, pdf.bounds.top]
53
+ pdf.text poem.reverse, :size => 12
54
+ end
55
+
56
+ pdf.text overflow * 10, :size => 14
57
+
58
+ pdf.text "Hooray! We've conquered the evil PDF gods", :size => 36
59
+
60
+ pdf.bounding_box([100,450], :width => 300) do
61
+ pdf.stroke_line [pdf.bounds.left, pdf.bounds.top],
62
+ [pdf.bounds.right, pdf.bounds.top]
63
+ pdf.text poem, :size => 10, :spacing => 5
64
+ end
65
+
66
+ pdf.text "And this text automatically goes below the poem", :size => 18
67
+
68
+ end
@@ -0,0 +1,38 @@
1
+ # coding: utf-8
2
+ #
3
+ # Why would we ever use Ruby 1.8.7 when we can backport with something
4
+ # as simple as this?
5
+ #
6
+ class String #:nodoc:
7
+ unless "".respond_to?(:lines)
8
+ alias_method :lines, :to_a
9
+ end
10
+ end
11
+
12
+ unless File.respond_to?(:binread)
13
+ def File.binread(file)
14
+ File.open(file,"rb") { |f| f.read }
15
+ end
16
+ end
17
+
18
+ if RUBY_VERSION < "1.9"
19
+
20
+ def ruby_18 #:nodoc:
21
+ yield
22
+ end
23
+
24
+ def ruby_19 #:nodoc:
25
+ false
26
+ end
27
+
28
+ else
29
+
30
+ def ruby_18 #:nodoc:
31
+ false
32
+ end
33
+
34
+ def ruby_19 #:nodoc:
35
+ yield
36
+ end
37
+
38
+ end
@@ -0,0 +1,79 @@
1
+ # encoding: utf-8
2
+
3
+ # prawn.rb : A library for PDF generation in Ruby
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
+ %w[ttfunk/lib].each do |dep|
10
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + "/../../vendor/#{dep}")
11
+ end
12
+
13
+ begin
14
+ require 'ttfunk'
15
+ rescue LoadError
16
+ puts "Failed to load ttfunk. If you are running Prawn from git:"
17
+ puts " git submodule init"
18
+ puts " git submodule update"
19
+ exit
20
+ end
21
+
22
+ module Prawn
23
+ file = __FILE__
24
+ file = File.readlink(file) if File.symlink?(file)
25
+ dir = File.dirname(file)
26
+
27
+ # The base source directory for Prawn as installed on the system
28
+ BASEDIR = File.expand_path(File.join(dir, '..', '..'))
29
+
30
+ VERSION = "0.5.0.1"
31
+
32
+ extend self
33
+
34
+ # Whe set to true, Prawn will verify hash options to ensure only valid keys
35
+ # are used. Off by default.
36
+ #
37
+ attr_accessor :debug
38
+
39
+ def verify_options(accepted,actual) #:nodoc:
40
+ return unless debug || $DEBUG
41
+ require "set"
42
+ unless (act=Set[*actual.keys]).subset?(acc=Set[*accepted])
43
+ raise Prawn::Errors::UnknownOption,
44
+ "\nDetected unknown option(s): #{(act - acc).to_a.inspect}\n" <<
45
+ "Accepted options are: #{accepted.inspect}"
46
+ end
47
+ yield if block_given?
48
+ end
49
+
50
+ module Configurable #:nodoc:
51
+ def configuration(*args)
52
+ @config ||= Marshal.load(Marshal.dump(default_configuration))
53
+ if Hash === args[0]
54
+ @config.update(args[0])
55
+ elsif args.length > 1
56
+ @config.values_at(*args)
57
+ elsif args.length == 1
58
+ @config[args[0]]
59
+ else
60
+ @config
61
+ end
62
+ end
63
+
64
+ alias_method :C, :configuration
65
+ end
66
+ end
67
+
68
+ require "prawn/compatibility"
69
+ require "prawn/errors"
70
+ require "prawn/pdf_object"
71
+ require "prawn/graphics"
72
+ require "prawn/images"
73
+ require "prawn/images/jpg"
74
+ require "prawn/images/png"
75
+ require "prawn/document"
76
+ require "prawn/reference"
77
+ require "prawn/font"
78
+ require "prawn/encoding"
79
+ require "prawn/measurements"
@@ -0,0 +1,399 @@
1
+ # encoding: utf-8
2
+
3
+ # document.rb : Implements PDF document generation for Prawn
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
+ require "stringio"
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/text"
16
+ require "prawn/document/annotations"
17
+ require "prawn/document/destinations"
18
+
19
+ module Prawn
20
+ # The Prawn::Document class is how you start creating a PDF document.
21
+ #
22
+ # There are three basic ways you can instantiate PDF Documents in Prawn, they
23
+ # are through assignment, implicit block or explicit block. Below is an exmple
24
+ # of each type, each example does exactly the same thing, makes a PDF document
25
+ # with all the defaults and puts in the default font "Hello There" and then
26
+ # saves it to the current directory as "example.pdf"
27
+ #
28
+ # For example, assignment can be like this:
29
+ #
30
+ # pdf = Prawn::Document.new
31
+ # pdf.text "Hello There"
32
+ # pdf.render_file "example.pdf"
33
+ #
34
+ # Or you can do an implied block form:
35
+ #
36
+ # Prawn::Document.generate "example.pdf" do
37
+ # text "Hello There"
38
+ # end
39
+ #
40
+ # Or if you need to access a variable outside the scope of the block, the
41
+ # explicit block form:
42
+ #
43
+ # words = "Hello There"
44
+ # Prawn::Document.generate "example.pdf" do |pdf|
45
+ # pdf.text words
46
+ # end
47
+ #
48
+ # Usually, the block forms are used when you are simply creating a PDF document
49
+ # that you want to immediately save or render out.
50
+ #
51
+ # See the new and generate methods for further details on the above.
52
+ class Document
53
+
54
+ include Text
55
+ include PageGeometry
56
+ include Internals
57
+ include Annotations
58
+ include Destinations
59
+ include Prawn::Graphics
60
+ include Prawn::Images
61
+
62
+ attr_accessor :y, :margin_box
63
+ attr_reader :margins, :page_size, :page_layout
64
+ attr_writer :font_size
65
+
66
+ # Creates and renders a PDF document.
67
+ #
68
+ # When using the implicit block form, Prawn will evaluate the block
69
+ # within an instance of Prawn::Document, simplifying your syntax.
70
+ # However, please note that you will not be able to reference variables
71
+ # from the enclosing scope within this block.
72
+ #
73
+ # # Using implicit block form and rendering to a file
74
+ # Prawn::Document.generate "example.pdf" do
75
+ # # self here is set to the newly instantiated Prawn::Document
76
+ # # and so any variables in the outside scope are unavailable
77
+ # font "Times-Roman"
78
+ # text "Hello World", :at => [200,720], :size => 32
79
+ # end
80
+ #
81
+ # If you need to access your local and instance variables, use the explicit
82
+ # block form shown below. In this case, Prawn yields an instance of
83
+ # PDF::Document and the block is an ordinary closure:
84
+ #
85
+ # # Using explicit block form and rendering to a file
86
+ # content = "Hello World"
87
+ # Prawn::Document.generate "example.pdf" do |pdf|
88
+ # # self here is left alone
89
+ # pdf.font "Times-Roman"
90
+ # pdf.text content, :at => [200,720], :size => 32
91
+ # end
92
+ #
93
+ def self.generate(filename,options={},&block)
94
+ pdf = new(options,&block)
95
+ pdf.render_file(filename)
96
+ end
97
+
98
+ # Creates a new PDF Document. The following options are available (with
99
+ # the default values marked in [])
100
+ #
101
+ # <tt>:page_size</tt>:: One of the Document::PageGeometry sizes [LETTER]
102
+ # <tt>:page_layout</tt>:: Either <tt>:portrait</tt> or <tt>:landscape</tt>
103
+ # <tt>:left_margin</tt>:: Sets the left margin in points [0.5 inch]
104
+ # <tt>:right_margin</tt>:: Sets the right margin in points [0.5 inch]
105
+ # <tt>:top_margin</tt>:: Sets the top margin in points [0.5 inch]
106
+ # <tt>:bottom_margin</tt>:: Sets the bottom margin in points [0.5 inch]
107
+ # <tt>:skip_page_creation</tt>:: Creates a document without starting the first page [false]
108
+ # <tt>:compress</tt>:: Compresses content streams before rendering them [false]
109
+ # <tt>:background</tt>:: An image path to be used as background on all pages [nil]
110
+ # <tt>:info</tt>:: Generic hash allowing for custom metadata properties [nil]
111
+
112
+ # Additionally, :page_size can be specified as a simple two value array giving
113
+ # the width and height of the document you need in PDF Points.
114
+ #
115
+ # Usage:
116
+ #
117
+ # # New document, US Letter paper, portrait orientation
118
+ # pdf = Prawn::Document.new
119
+ #
120
+ # # New document, A4 paper, landscaped
121
+ # pdf = Prawn::Document.new(:page_size => "A4", :page_layout => :landscape)
122
+ #
123
+ # # New document, Custom size
124
+ # pdf = Prawn::Document.new(:page_size => [200, 300])
125
+ #
126
+ # # New document, with background
127
+ # pdf = Prawn::Document.new(:background => "#{Prawn::BASEDIR}/data/images/pigs.jpg")
128
+ #
129
+ def initialize(options={},&block)
130
+ Prawn.verify_options [:page_size, :page_layout, :left_margin,
131
+ :right_margin, :top_margin, :bottom_margin, :skip_page_creation,
132
+ :compress, :skip_encoding, :text_options, :background, :info], options
133
+
134
+ options[:info] ||= {}
135
+ options[:info][:Creator] ||= "Prawn"
136
+ options[:info][:Producer] = "Prawn"
137
+
138
+ options[:info].keys.each do |key|
139
+ if options[:info][key].kind_of?(String)
140
+ options[:info][key] = Prawn::LiteralString.new(options[:info][key])
141
+ end
142
+ end
143
+
144
+ @version = 1.3
145
+ @objects = []
146
+ @info = ref(options[:info])
147
+ @pages = ref(:Type => :Pages, :Count => 0, :Kids => [])
148
+ @root = ref(:Type => :Catalog, :Pages => @pages)
149
+ @page_size = options[:page_size] || "LETTER"
150
+ @page_layout = options[:page_layout] || :portrait
151
+ @compress = options[:compress] || false
152
+ @skip_encoding = options[:skip_encoding]
153
+ @background = options[:background]
154
+ @font_size = 12
155
+
156
+ text_options.update(options[:text_options] || {})
157
+
158
+ @margins = { :left => options[:left_margin] || 36,
159
+ :right => options[:right_margin] || 36,
160
+ :top => options[:top_margin] || 36,
161
+ :bottom => options[:bottom_margin] || 36 }
162
+
163
+ generate_margin_box
164
+
165
+ @bounding_box = @margin_box
166
+
167
+ start_new_page unless options[:skip_page_creation]
168
+
169
+ if block
170
+ block.arity < 1 ? instance_eval(&block) : block[self]
171
+ end
172
+ end
173
+
174
+ # Creates and advances to a new page in the document.
175
+ #
176
+ # Page size, margins, and layout can also be set when generating a
177
+ # new page. These values will become the new defaults for page creation
178
+ #
179
+ # pdf.start_new_page #=> Starts new page keeping current values
180
+ # pdf.start_new_page(:size => "LEGAL", :layout => :landscape)
181
+ # pdf.start_new_page(:left_margin => 50, :right_margin => 50)
182
+ #
183
+ def start_new_page(options = {})
184
+ @page_size = options[:size] if options[:size]
185
+ @page_layout = options[:layout] if options[:layout]
186
+
187
+ [:left,:right,:top,:bottom].each do |side|
188
+ if options[:"#{side}_margin"]
189
+ @margins[side] = options[:"#{side}_margin"]
190
+ end
191
+ end
192
+
193
+ finish_page_content if @page_content
194
+ build_new_page_content
195
+
196
+ @pages.data[:Kids] << @current_page
197
+ @pages.data[:Count] += 1
198
+
199
+ add_content "q"
200
+
201
+ @y = @bounding_box.absolute_top
202
+
203
+ image(@background, :at => [0,@y]) if @background
204
+ end
205
+
206
+ # Returns the number of pages in the document
207
+ #
208
+ # pdf = Prawn::Document.new
209
+ # pdf.page_count #=> 1
210
+ # 3.times { pdf.start_new_page }
211
+ # pdf.page_count #=> 4
212
+ #
213
+ def page_count
214
+ @pages.data[:Count]
215
+ end
216
+
217
+ # The current y drawing position relative to the innermost bounding box,
218
+ # or to the page margins at the top level.
219
+ #
220
+ def cursor
221
+ y - bounds.absolute_bottom
222
+ end
223
+
224
+ # Renders the PDF document to string, useful for example in a Rails
225
+ # application where you want to stream out the PDF to a web browser:
226
+ #
227
+ # def show
228
+ # pdf = Prawn::Document.new do
229
+ # text "Putting PDF generation code in a controller is _BAD_"
230
+ # end
231
+ # send(pdf.render, :filename => 'silly.pdf', :type => 'application/pdf', :disposition => 'inline)
232
+ # end
233
+ #
234
+ def render
235
+ output = StringIO.new
236
+ finish_page_content
237
+
238
+ render_header(output)
239
+ render_body(output)
240
+ render_xref(output)
241
+ render_trailer(output)
242
+ str = output.string
243
+ str.force_encoding("ASCII-8BIT") if str.respond_to?(:force_encoding)
244
+ str
245
+ end
246
+
247
+ # Renders the PDF document to file.
248
+ #
249
+ # pdf.render_file "foo.pdf"
250
+ #
251
+ def render_file(filename)
252
+ Kernel.const_defined?("Encoding") ? mode = "wb:ASCII-8BIT" : mode = "wb"
253
+ File.open(filename,mode) { |f| f << render }
254
+ end
255
+
256
+ # The bounds method returns the current bounding box you are currently in,
257
+ # which is by default the box represented by the margin box on the
258
+ # document itself. When called from within a created <tt>bounding_box</tt>
259
+ # block, the box defined by that call will be returned instead of the
260
+ # document margin box.
261
+ #
262
+ # Another important point about bounding boxes is that all x and y measurements
263
+ # within a bounding box code block are relative to the bottom left corner of the
264
+ # bounding box.
265
+ #
266
+ # For example:
267
+ #
268
+ # Prawn::Document.new do
269
+ # # In the default "margin box" of a Prawn document of 0.5in along each edge
270
+ #
271
+ # # Draw a border around the page (the manual way)
272
+ # stroke do
273
+ # line(bounds.bottom_left, bounds.bottom_right)
274
+ # line(bounds.bottom_right, bounds.top_right)
275
+ # line(bounds.top_right, bounds.top_left)
276
+ # line(bounds.top_left, bounds.bottom_left)
277
+ # end
278
+ #
279
+ # # Draw a border around the page (the easy way)
280
+ # stroke_bounds
281
+ # end
282
+ #
283
+ def bounds
284
+ @bounding_box
285
+ end
286
+
287
+ # Sets Document#bounds to the BoundingBox provided. See above for a brief
288
+ # description of what a bounding box is. This function is useful if you
289
+ # really need to change the bounding box manually, but usually, just entering
290
+ # and existing bounding box code blocks is good enough.
291
+ #
292
+ def bounds=(bounding_box)
293
+ @bounding_box = bounding_box
294
+ end
295
+
296
+ # Moves up the document by n points relative to the current position inside
297
+ # the current bounding box.
298
+ #
299
+ def move_up(n)
300
+ self.y += n
301
+ end
302
+
303
+ # Moves down the document by n points relative to the current position inside
304
+ # the current bounding box.
305
+ #
306
+ def move_down(n)
307
+ self.y -= n
308
+ end
309
+
310
+ # Moves down the document and then executes a block.
311
+ #
312
+ # pdf.text "some text"
313
+ # pdf.pad_top(100) do
314
+ # pdf.text "This is 100 points below the previous line of text"
315
+ # end
316
+ # pdf.text "This text appears right below the previous line of text"
317
+ #
318
+ def pad_top(y)
319
+ move_down(y)
320
+ yield
321
+ end
322
+
323
+ # Executes a block then moves down the document
324
+ #
325
+ # pdf.text "some text"
326
+ # pdf.pad_bottom(100) do
327
+ # pdf.text "This text appears right below the previous line of text"
328
+ # end
329
+ # pdf.text "This is 100 points below the previous line of text"
330
+ #
331
+ def pad_bottom(y)
332
+ yield
333
+ move_down(y)
334
+ end
335
+
336
+ # Moves down the document by y, executes a block, then moves down the
337
+ # document by y again.
338
+ #
339
+ # pdf.text "some text"
340
+ # pdf.pad(100) do
341
+ # pdf.text "This is 100 points below the previous line of text"
342
+ # end
343
+ # pdf.text "This is 100 points below the previous line of text"
344
+ #
345
+ def pad(y)
346
+ move_down(y)
347
+ yield
348
+ move_down(y)
349
+ end
350
+
351
+ def mask(*fields) # :nodoc:
352
+ # Stores the current state of the named attributes, executes the block, and
353
+ # then restores the original values after the block has executed.
354
+ # -- I will remove the nodoc if/when this feature is a little less hacky
355
+ stored = {}
356
+ fields.each { |f| stored[f] = send(f) }
357
+ yield
358
+ fields.each { |f| send("#{f}=", stored[f]) }
359
+ end
360
+
361
+ # Returns true if content streams will be compressed before rendering,
362
+ # false otherwise
363
+ #
364
+ def compression_enabled?
365
+ !!@compress
366
+ end
367
+
368
+ private
369
+
370
+ # See Prawn::Document::Internals for low-level PDF functions
371
+
372
+ def build_new_page_content
373
+ generate_margin_box
374
+ @page_content = ref(:Length => 0)
375
+
376
+ @current_page = ref(:Type => :Page,
377
+ :Parent => @pages,
378
+ :MediaBox => page_dimensions,
379
+ :Contents => @page_content)
380
+ update_colors
381
+ end
382
+
383
+ def generate_margin_box
384
+ old_margin_box = @margin_box
385
+ @margin_box = BoundingBox.new(
386
+ self,
387
+ [ @margins[:left], page_dimensions[-1] - @margins[:top] ] ,
388
+ :width => page_dimensions[-2] - (@margins[:left] + @margins[:right]),
389
+ :height => page_dimensions[-1] - (@margins[:top] + @margins[:bottom])
390
+ )
391
+
392
+ # update bounding box if not flowing from the previous page
393
+ # FIXME: This may have a bug where the old margin is restored
394
+ # when the bounding box exits.
395
+ @bounding_box = @margin_box if old_margin_box == @bounding_box
396
+ end
397
+
398
+ end
399
+ end