fullcirclegroup-prawn 0.2.99.3

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 (117) hide show
  1. data/COPYING +340 -0
  2. data/LICENSE +56 -0
  3. data/README +47 -0
  4. data/Rakefile +76 -0
  5. data/data/fonts/Activa.ttf +0 -0
  6. data/data/fonts/Chalkboard.ttf +0 -0
  7. data/data/fonts/Courier-Bold.afm +342 -0
  8. data/data/fonts/Courier-BoldOblique.afm +342 -0
  9. data/data/fonts/Courier-Oblique.afm +342 -0
  10. data/data/fonts/Courier.afm +342 -0
  11. data/data/fonts/DejaVuSans.ttf +0 -0
  12. data/data/fonts/Dustismo_Roman.ttf +0 -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/fonts/comicsans.ttf +0 -0
  25. data/data/fonts/gkai00mp.ttf +0 -0
  26. data/data/images/arrow.png +0 -0
  27. data/data/images/arrow2.png +0 -0
  28. data/data/images/barcode_issue.png +0 -0
  29. data/data/images/dice.alpha +0 -0
  30. data/data/images/dice.dat +0 -0
  31. data/data/images/dice.png +0 -0
  32. data/data/images/page_white_text.alpha +0 -0
  33. data/data/images/page_white_text.dat +0 -0
  34. data/data/images/page_white_text.png +0 -0
  35. data/data/images/pigs.jpg +0 -0
  36. data/data/images/rails.dat +0 -0
  37. data/data/images/rails.png +0 -0
  38. data/data/images/ruport.png +0 -0
  39. data/data/images/ruport_data.dat +0 -0
  40. data/data/images/ruport_transparent.png +0 -0
  41. data/data/images/ruport_type0.png +0 -0
  42. data/data/images/stef.jpg +0 -0
  43. data/data/images/web-links.dat +1 -0
  44. data/data/images/web-links.png +0 -0
  45. data/data/shift_jis_text.txt +1 -0
  46. data/examples/addressbook.csv +6 -0
  47. data/examples/alignment.rb +16 -0
  48. data/examples/bounding_boxes.rb +30 -0
  49. data/examples/canvas.rb +12 -0
  50. data/examples/cell.rb +38 -0
  51. data/examples/chinese_text_wrapping.rb +17 -0
  52. data/examples/currency.csv +1834 -0
  53. data/examples/curves.rb +10 -0
  54. data/examples/family_based_styling.rb +21 -0
  55. data/examples/fancy_table.rb +61 -0
  56. data/examples/flowing_text_with_header_and_footer.rb +72 -0
  57. data/examples/font_size.rb +27 -0
  58. data/examples/hexagon.rb +14 -0
  59. data/examples/image.rb +23 -0
  60. data/examples/image2.rb +13 -0
  61. data/examples/image_flow.rb +34 -0
  62. data/examples/kerning.rb +27 -0
  63. data/examples/lazy_bounding_boxes.rb +19 -0
  64. data/examples/line.rb +31 -0
  65. data/examples/multi_page_layout.rb +14 -0
  66. data/examples/page_geometry.rb +28 -0
  67. data/examples/png_types.rb +23 -0
  68. data/examples/polygons.rb +16 -0
  69. data/examples/position_by_baseline.rb +26 -0
  70. data/examples/ruport_formatter.rb +50 -0
  71. data/examples/ruport_helpers.rb +18 -0
  72. data/examples/russian_boxes.rb +34 -0
  73. data/examples/simple_text.rb +15 -0
  74. data/examples/simple_text_ttf.rb +16 -0
  75. data/examples/sjis.rb +21 -0
  76. data/examples/span.rb +27 -0
  77. data/examples/table.rb +47 -0
  78. data/examples/table_header_color.rb +16 -0
  79. data/examples/text_flow.rb +65 -0
  80. data/examples/top_and_bottom_cells.rb +40 -0
  81. data/examples/utf8.rb +12 -0
  82. data/lib/prawn.rb +67 -0
  83. data/lib/prawn/compatibility.rb +46 -0
  84. data/lib/prawn/document.rb +309 -0
  85. data/lib/prawn/document/bounding_box.rb +362 -0
  86. data/lib/prawn/document/internals.rb +113 -0
  87. data/lib/prawn/document/page_geometry.rb +79 -0
  88. data/lib/prawn/document/span.rb +47 -0
  89. data/lib/prawn/document/table.rb +350 -0
  90. data/lib/prawn/document/text.rb +196 -0
  91. data/lib/prawn/errors.rb +48 -0
  92. data/lib/prawn/font.rb +356 -0
  93. data/lib/prawn/font/cmap.rb +59 -0
  94. data/lib/prawn/font/metrics.rb +378 -0
  95. data/lib/prawn/font/wrapping.rb +47 -0
  96. data/lib/prawn/graphics.rb +252 -0
  97. data/lib/prawn/graphics/cell.rb +264 -0
  98. data/lib/prawn/graphics/color.rb +132 -0
  99. data/lib/prawn/images.rb +336 -0
  100. data/lib/prawn/images/jpg.rb +45 -0
  101. data/lib/prawn/images/png.rb +199 -0
  102. data/lib/prawn/pdf_object.rb +73 -0
  103. data/lib/prawn/reference.rb +56 -0
  104. data/spec/bounding_box_spec.rb +141 -0
  105. data/spec/document_spec.rb +181 -0
  106. data/spec/font_spec.rb +141 -0
  107. data/spec/graphics_spec.rb +209 -0
  108. data/spec/images_spec.rb +68 -0
  109. data/spec/jpg_spec.rb +25 -0
  110. data/spec/metrics_spec.rb +62 -0
  111. data/spec/pdf_object_spec.rb +112 -0
  112. data/spec/png_spec.rb +196 -0
  113. data/spec/reference_spec.rb +42 -0
  114. data/spec/spec_helper.rb +23 -0
  115. data/spec/table_spec.rb +179 -0
  116. data/spec/text_spec.rb +135 -0
  117. metadata +181 -0
@@ -0,0 +1,45 @@
1
+ # encoding: ASCII-8BIT
2
+
3
+ # jpg.rb : Extracts the data from a JPG that is needed for embedding
4
+ #
5
+ # Copyright April 2008, James Healy. All Rights Reserved.
6
+ #
7
+ # This is free software. Please see the LICENSE and COPYING files for details.
8
+
9
+ require 'stringio'
10
+
11
+ module Prawn
12
+ module Images
13
+ # A convenience class that wraps the logic for extracting the parts
14
+ # of a PNG image that we need to embed them in a PDF
15
+ class JPG
16
+ attr_reader :width, :height, :bits, :channels
17
+ attr_accessor :scaled_width, :scaled_height
18
+
19
+ JPEG_SOF_BLOCKS = %W(\xc0 \xc1 \xc2 \xc3 \xc5 \xc6 \xc7 \xc9 \xca \xcb \xcd \xce \xcf)
20
+ JPEG_APP_BLOCKS = %W(\xe0 \xe1 \xe2 \xe3 \xe4 \xe5 \xe6 \xe7 \xe8 \xe9 \xea \xeb \xec \xed \xee \xef)
21
+
22
+ # Process a new JPG image
23
+ #
24
+ # <tt>:data</tt>:: A string containing a full PNG file
25
+ #
26
+ def initialize(data)
27
+ data = StringIO.new(data.dup)
28
+
29
+ c_marker = "\xff" # Section marker.
30
+ data.read(2) # Skip the first two bytes of JPEG identifier.
31
+ loop do
32
+ marker, code, length = data.read(4).unpack('aan')
33
+ raise "JPEG marker not found!" if marker != c_marker
34
+
35
+ if JPEG_SOF_BLOCKS.include?(code)
36
+ @bits, @height, @width, @channels = data.read(6).unpack("CnnC")
37
+ break
38
+ end
39
+
40
+ buffer = data.read(length - 2)
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,199 @@
1
+ # encoding: ASCII-8BIT
2
+
3
+ # png.rb : Extracts the data from a PNG that is needed for embedding
4
+ #
5
+ # Based on some similar code in PDF::Writer by Austin Ziegler
6
+ #
7
+ # Copyright April 2008, James Healy. All Rights Reserved.
8
+ #
9
+ # This is free software. Please see the LICENSE and COPYING files for details.
10
+
11
+ require 'stringio'
12
+
13
+ module Prawn
14
+ module Images
15
+ # A convenience class that wraps the logic for extracting the parts
16
+ # of a PNG image that we need to embed them in a PDF
17
+ class PNG
18
+ attr_reader :palette, :img_data, :transparency
19
+ attr_reader :width, :height, :bits
20
+ attr_reader :color_type, :compression_method, :filter_method
21
+ attr_reader :interlace_method, :alpha_channel
22
+ attr_accessor :scaled_width, :scaled_height
23
+
24
+ # Process a new PNG image
25
+ #
26
+ # <tt>:data</tt>:: A string containing a full PNG file
27
+ #
28
+ def initialize(data)
29
+ data = StringIO.new(data.dup)
30
+
31
+ data.read(8) # Skip the default header
32
+
33
+ @palette = ""
34
+ @img_data = ""
35
+ @transparency = {}
36
+
37
+ loop do
38
+ chunk_size = data.read(4).unpack("N")[0]
39
+ section = data.read(4)
40
+ case section
41
+ when 'IHDR'
42
+ # we can grab other interesting values from here (like width,
43
+ # height, etc)
44
+ values = data.read(chunk_size).unpack("NNCCCCC")
45
+
46
+ @width = values[0]
47
+ @height = values[1]
48
+ @bits = values[2]
49
+ @color_type = values[3]
50
+ @compression_method = values[4]
51
+ @filter_method = values[5]
52
+ @interlace_method = values[6]
53
+ when 'PLTE'
54
+ @palette << data.read(chunk_size)
55
+ when 'IDAT'
56
+ @img_data << data.read(chunk_size)
57
+ when 'tRNS'
58
+ # This chunk can only occur once and it must occur after the
59
+ # PLTE chunk and before the IDAT chunk
60
+ @transparency = {}
61
+ case @color_type
62
+ when 3
63
+ # Indexed colour, RGB. Each byte in this chunk is an alpha for
64
+ # the palette index in the PLTE ("palette") chunk up until the
65
+ # last non-opaque entry. Set up an array, stretching over all
66
+ # palette entries which will be 0 (opaque) or 1 (transparent).
67
+ @transparency[:indexed] = data.read(chunk_size).unpack("C*")
68
+ short = 255 - @transparency[:indexed].size
69
+ @transparency[:indexed] += ([255] * short) if short > 0
70
+ when 0
71
+ # Greyscale. Corresponding to entries in the PLTE chunk.
72
+ # Grey is two bytes, range 0 .. (2 ^ bit-depth) - 1
73
+ grayval = data.read(chunk_size).unpack("n").first
74
+ @transparency[:grayscale] = grayval
75
+ when 2
76
+ # True colour with proper alpha channel.
77
+ @transparency[:rgb] = data.read(chunk_size).unpack("nnn")
78
+ end
79
+ when 'IEND'
80
+ # we've got everything we need, exit the loop
81
+ break
82
+ else
83
+ # unknown (or un-important) section, skip over it
84
+ data.seek(data.pos + chunk_size)
85
+ end
86
+
87
+ data.read(4) # Skip the CRC
88
+ end
89
+
90
+ # if our img_data contains alpha channel data, split it out
91
+ unfilter_image_data if alpha_channel?
92
+ end
93
+
94
+ def pixel_bytes
95
+ @pixel_bytes ||= case @color_type
96
+ when 0, 3, 4 then 1
97
+ when 1, 2, 6 then 3
98
+ end
99
+ end
100
+
101
+ private
102
+
103
+ def alpha_channel?
104
+ @color_type == 4 || @color_type == 6
105
+ end
106
+
107
+ def unfilter_image_data
108
+ data = Zlib::Inflate.inflate(@img_data).unpack 'C*'
109
+ @img_data = ""
110
+ @alpha_channel = ""
111
+
112
+ # each pixel has the color bytes, plus a byte of alpha channel
113
+ pixel_length = pixel_bytes + 1
114
+ scanline_length = pixel_length * @width + 1 # for filter
115
+ row = 0
116
+ pixels = []
117
+ paeth, pa, pb, pc = nil
118
+ until data.empty? do
119
+ row_data = data.slice! 0, scanline_length
120
+ filter = row_data.shift
121
+ case filter
122
+ when 0 # None
123
+ when 1 # Sub
124
+ row_data.each_with_index do |byte, index|
125
+ left = index < pixel_length ? 0 : row_data[index - pixel_length]
126
+ row_data[index] = (byte + left) % 256
127
+ #p [byte, left, row_data[index]]
128
+ end
129
+ when 2 # Up
130
+ row_data.each_with_index do |byte, index|
131
+ col = index / pixel_length
132
+ upper = row == 0 ? 0 : pixels[row-1][col][index % pixel_length]
133
+ row_data[index] = (upper + byte) % 256
134
+ end
135
+ when 3 # Average
136
+ row_data.each_with_index do |byte, index|
137
+ col = index / pixel_length
138
+ upper = row == 0 ? 0 : pixels[row-1][col][index % pixel_length]
139
+ left = index < pixel_length ? 0 : row_data[index - pixel_length]
140
+
141
+ row_data[index] = (byte + ((left + upper)/2).floor) % 256
142
+ end
143
+ when 4 # Paeth
144
+ left = upper = upper_left = nil
145
+ row_data.each_with_index do |byte, index|
146
+ col = index / pixel_length
147
+
148
+ left = index < pixel_length ? 0 : row_data[index - pixel_length]
149
+ if row.zero?
150
+ upper = upper_left = 0
151
+ else
152
+ upper = pixels[row-1][col][index % pixel_length]
153
+ upper_left = col.zero? ? 0 :
154
+ pixels[row-1][col-1][index % pixel_length]
155
+ end
156
+
157
+ p = left + upper - upper_left
158
+ pa = (p - left).abs
159
+ pb = (p - upper).abs
160
+ pc = (p - upper_left).abs
161
+
162
+ paeth = if pa <= pb && pa <= pc
163
+ left
164
+ elsif pb <= pc
165
+ upper
166
+ else
167
+ upper_left
168
+ end
169
+
170
+ row_data[index] = (byte + paeth) % 256
171
+ #p [byte, paeth, row_data[index]]
172
+ end
173
+ else
174
+ raise ArgumentError, "Invalid filter algorithm #{filter}"
175
+ end
176
+
177
+ s = []
178
+ row_data.each_slice pixel_length do |slice|
179
+ s << slice
180
+ end
181
+ pixels << s
182
+ row += 1
183
+ end
184
+
185
+ # convert the pixel data to seperate strings for colours and alpha
186
+ pixels.each do |row|
187
+ row.each do |pixel|
188
+ @img_data << pixel[0,pixel_bytes].pack("C*")
189
+ @alpha_channel << pixel.last
190
+ end
191
+ end
192
+
193
+ # compress the data
194
+ @img_data = Zlib::Deflate.deflate(@img_data)
195
+ @alpha_channel = Zlib::Deflate.deflate(@alpha_channel)
196
+ end
197
+ end
198
+ end
199
+ end
@@ -0,0 +1,73 @@
1
+ # encoding: utf-8
2
+ #
3
+ # pdf_object.rb : Handles Ruby to PDF object serialization
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
+ # Top level Module
10
+ #
11
+ module Prawn
12
+
13
+ module_function
14
+
15
+ # Serializes Ruby objects to their PDF equivalents. Most primitive objects
16
+ # will work as expected, but please note that Name objects are represented
17
+ # by Ruby Symbol objects and Dictionary objects are represented by Ruby hashes
18
+ # (keyed by symbols)
19
+ #
20
+ # Examples:
21
+ #
22
+ # PdfObject(true) #=> "true"
23
+ # PdfObject(false) #=> "false"
24
+ # PdfObject(1.2124) #=> "1.2124"
25
+ # PdfObject("foo bar") #=> "(foo bar)"
26
+ # PdfObject(:Symbol) #=> "/Symbol"
27
+ # PdfObject(["foo",:bar, [1,2]]) #=> "[foo /bar [1 2]]"
28
+ #
29
+ def PdfObject(obj, in_content_stream = false)
30
+ case(obj)
31
+ when NilClass then "null"
32
+ when TrueClass then "true"
33
+ when FalseClass then "false"
34
+ when Numeric then String(obj)
35
+ when Array
36
+ "[" << obj.map { |e| PdfObject(e, in_content_stream) }.join(' ') << "]"
37
+ when Prawn::LiteralString
38
+ obj = obj.gsub(/[\\\n\(\)]/) { |m| "\\#{m}" }
39
+ "(#{obj})"
40
+ when String
41
+ obj = "\xFE\xFF" + obj.unpack("U*").pack("n*") unless in_content_stream
42
+ "<" << obj.unpack("H*").first << ">"
43
+ when Symbol
44
+ if (obj = obj.to_s) =~ /\s/
45
+ raise Prawn::Errors::FailedObjectConversion,
46
+ "A PDF Name cannot contain whitespace"
47
+ else
48
+ "/" << obj
49
+ end
50
+ when Hash
51
+ output = "<< "
52
+ obj.each do |k,v|
53
+ unless String === k || Symbol === k
54
+ raise Prawn::Errors::FailedObjectConversion,
55
+ "A PDF Dictionary must be keyed by names"
56
+ end
57
+ output << PdfObject(k.to_sym, in_content_stream) << " " <<
58
+ PdfObject(v, in_content_stream) << "\n"
59
+ end
60
+ output << ">>"
61
+ when Prawn::Reference
62
+ obj.to_s
63
+ when Prawn::NameTree::Node
64
+ PdfObject(obj.to_hash)
65
+ when Prawn::NameTree::Value
66
+ PdfObject(obj.name) + " " + PdfObject(obj.value)
67
+ else
68
+ raise Prawn::Errors::FailedObjectConversion,
69
+ "This object cannot be serialized to PDF"
70
+ end
71
+ end
72
+
73
+ end
@@ -0,0 +1,56 @@
1
+ # encoding: utf-8
2
+
3
+ # reference.rb : Implementation of PDF indirect objects
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 'zlib'
10
+
11
+ module Prawn
12
+
13
+ class Reference #:nodoc:
14
+
15
+ attr_accessor :gen, :data, :offset
16
+ attr_reader :identifier, :stream
17
+
18
+ def initialize(id,data)
19
+ @identifier = id
20
+ @gen = 0
21
+ @data = data
22
+ @compressed = false
23
+ end
24
+
25
+ def object
26
+ output = "#{@identifier} #{gen} obj\n" <<
27
+ Prawn::PdfObject(data) << "\n"
28
+ if @stream
29
+ output << "stream\n" << @stream << "\nendstream\n"
30
+ end
31
+ output << "endobj\n"
32
+ end
33
+
34
+ def <<(data)
35
+ raise 'Cannot add data to a stream that is compressed' if @compressed
36
+ (@stream ||= "") << data
37
+ end
38
+
39
+ def to_s
40
+ "#{@identifier} #{gen} R"
41
+ end
42
+
43
+ def compress_stream
44
+ @stream = Zlib::Deflate.deflate(@stream)
45
+ @data[:Filter] = :FlateDecode
46
+ @compressed = true
47
+ end
48
+ end
49
+
50
+ module_function
51
+
52
+ def Reference(*args) #:nodoc:
53
+ Reference.new(*args)
54
+ end
55
+
56
+ end
@@ -0,0 +1,141 @@
1
+ # encoding: utf-8
2
+
3
+ require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
4
+
5
+ describe "A bounding box" do
6
+
7
+ before(:each) do
8
+ @x = 100
9
+ @y = 125
10
+ @width = 50
11
+ @height = 75
12
+ @box = Prawn::Document::BoundingBox.new(nil, [@x,@y], :width => @width,
13
+ :height => @height )
14
+ end
15
+
16
+ it "should have an anchor at (x, y - height)" do
17
+ @box.anchor.should == [@x,@y-@height]
18
+ end
19
+
20
+ it "should have a left boundary of 0" do
21
+ @box.left.should == 0
22
+ end
23
+
24
+ it "should have a right boundary equal to the width" do
25
+ @box.right.should == @width
26
+ end
27
+
28
+ it "should have a top boundary of height" do
29
+ @box.top.should == @height
30
+ end
31
+
32
+ it "should have a bottom boundary of 0" do
33
+ @box.bottom.should == 0
34
+ end
35
+
36
+ it "should have a top-left of [0,height]" do
37
+ @box.top_left.should == [0,@height]
38
+ end
39
+
40
+ it "should have a top-right of [width,height]" do
41
+ @box.top_right.should == [@width,@height]
42
+ end
43
+
44
+ it "should have a bottom-left of [0,0]" do
45
+ @box.bottom_left.should == [0,0]
46
+ end
47
+
48
+ it "should have a bottom-right of [width,0]" do
49
+ @box.bottom_right.should == [@width,0]
50
+ end
51
+
52
+ it "should have an absolute left boundary of x" do
53
+ @box.absolute_left.should == @x
54
+ end
55
+
56
+ it "should have an absolute right boundary of x + width" do
57
+ @box.absolute_right.should == @x + @width
58
+ end
59
+
60
+ it "should have an absolute top boundary of y" do
61
+ @box.absolute_top.should == @y
62
+ end
63
+
64
+ it "should have an absolute bottom boundary of y - height" do
65
+ @box.absolute_bottom.should == @y - @height
66
+ end
67
+
68
+ it "should have an absolute bottom-left of [x,y-height]" do
69
+ @box.absolute_bottom_left.should == [@x, @y - @height]
70
+ end
71
+
72
+ it "should have an absolute bottom-right of [x+width,y-height]" do
73
+ @box.absolute_bottom_right.should == [@x + @width , @y - @height]
74
+ end
75
+
76
+ it "should have an absolute top-left of [x,y]" do
77
+ @box.absolute_top_left.should == [@x, @y]
78
+ end
79
+
80
+ it "should have an absolute top-right of [x+width,y]" do
81
+ @box.absolute_top_right.should == [@x + @width, @y]
82
+ end
83
+
84
+
85
+ end
86
+
87
+ describe "drawing bounding boxes" do
88
+
89
+ before(:each) { create_pdf }
90
+
91
+ it "should restore the margin box when bounding box exits" do
92
+ margin_box = @pdf.bounds
93
+
94
+ @pdf.bounding_box [100,500] do
95
+ #nothing
96
+ end
97
+
98
+ @pdf.bounds.should == margin_box
99
+
100
+ end
101
+
102
+ it "should restore the parent bounding box when calls are nested" do
103
+ @pdf.bounding_box [100,500], :width => 300, :height => 300 do
104
+
105
+ @pdf.bounds.absolute_top.should == 500 + @pdf.margin_box.absolute_bottom
106
+ @pdf.bounds.absolute_left.should == 100 + @pdf.margin_box.absolute_left
107
+
108
+ parent_box = @pdf.bounds
109
+
110
+ @pdf.bounding_box [50,200], :width => 100, :height => 100 do
111
+ @pdf.bounds.absolute_top.should == 200 + parent_box.absolute_bottom
112
+ @pdf.bounds.absolute_left.should == 50 + parent_box.absolute_left
113
+ end
114
+
115
+ @pdf.bounds.absolute_top.should == 500 + @pdf.margin_box.absolute_bottom
116
+ @pdf.bounds.absolute_left.should == 100 + @pdf.margin_box.absolute_left
117
+
118
+ end
119
+ end
120
+
121
+ it "should calculate a height if none is specified" do
122
+ @pdf.bounding_box([100, 500], :width => 100) do
123
+ @pdf.text "The rain in Spain falls mainly on the plains."
124
+ end
125
+
126
+ @pdf.y.should.be.close 458.384, 0.001
127
+ end
128
+
129
+ end
130
+
131
+ describe "A canvas" do
132
+ before(:each) { create_pdf }
133
+
134
+ it "should use whatever the last set y position is" do
135
+ @pdf.canvas do
136
+ @pdf.bounding_box([100,500],:width => 200) { @pdf.move_down 50 }
137
+ end
138
+ @pdf.y.should == 450
139
+ end
140
+ end
141
+