prawn 1.0.0.rc2 → 1.0.0

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 (169) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +9 -0
  3. data/COPYING +2 -2
  4. data/Gemfile +8 -15
  5. data/LICENSE +1 -1
  6. data/Rakefile +25 -16
  7. data/data/images/16bit.alpha +0 -0
  8. data/data/images/16bit.color +0 -0
  9. data/data/images/dice.alpha +0 -0
  10. data/data/images/dice.color +0 -0
  11. data/data/images/indexed_color.dat +0 -0
  12. data/data/images/indexed_color.png +0 -0
  13. data/data/images/license.md +8 -0
  14. data/data/images/page_white_text.alpha +0 -0
  15. data/data/images/page_white_text.color +0 -0
  16. data/lib/prawn.rb +85 -23
  17. data/lib/prawn/document.rb +134 -116
  18. data/lib/prawn/document/bounding_box.rb +33 -4
  19. data/lib/prawn/document/column_box.rb +18 -6
  20. data/lib/prawn/document/graphics_state.rb +11 -74
  21. data/lib/prawn/document/internals.rb +24 -23
  22. data/lib/prawn/document/span.rb +12 -10
  23. data/lib/prawn/encoding.rb +8 -9
  24. data/lib/prawn/errors.rb +13 -32
  25. data/lib/prawn/font.rb +137 -105
  26. data/lib/prawn/font/afm.rb +76 -32
  27. data/lib/prawn/font/dfont.rb +4 -3
  28. data/lib/prawn/font/ttf.rb +33 -25
  29. data/lib/prawn/font_metric_cache.rb +47 -0
  30. data/lib/prawn/graphics.rb +177 -57
  31. data/lib/prawn/graphics/cap_style.rb +4 -3
  32. data/lib/prawn/graphics/color.rb +5 -4
  33. data/lib/prawn/graphics/dash.rb +53 -31
  34. data/lib/prawn/graphics/join_style.rb +9 -7
  35. data/lib/prawn/graphics/patterns.rb +4 -15
  36. data/lib/prawn/graphics/transformation.rb +10 -9
  37. data/lib/prawn/graphics/transparency.rb +3 -1
  38. data/lib/prawn/{layout/grid.rb → grid.rb} +72 -54
  39. data/lib/prawn/image_handler.rb +42 -0
  40. data/lib/prawn/images.rb +58 -54
  41. data/lib/prawn/images/image.rb +6 -22
  42. data/lib/prawn/images/jpg.rb +20 -14
  43. data/lib/prawn/images/png.rb +58 -121
  44. data/lib/prawn/layout.rb +12 -15
  45. data/lib/prawn/measurement_extensions.rb +10 -6
  46. data/lib/prawn/measurements.rb +27 -21
  47. data/lib/prawn/outline.rb +108 -147
  48. data/lib/prawn/repeater.rb +10 -8
  49. data/lib/prawn/security.rb +59 -40
  50. data/lib/prawn/security/arcfour.rb +52 -0
  51. data/lib/prawn/soft_mask.rb +4 -4
  52. data/lib/prawn/stamp.rb +5 -3
  53. data/lib/prawn/table.rb +83 -60
  54. data/lib/prawn/table/cell.rb +17 -21
  55. data/lib/prawn/table/cell/image.rb +2 -3
  56. data/lib/prawn/table/cell/in_table.rb +8 -2
  57. data/lib/prawn/table/cell/span_dummy.rb +5 -0
  58. data/lib/prawn/table/cell/subtable.rb +3 -2
  59. data/lib/prawn/table/cell/text.rb +14 -12
  60. data/lib/prawn/table/cells.rb +58 -14
  61. data/lib/prawn/table/column_width_calculator.rb +61 -0
  62. data/lib/prawn/text.rb +27 -26
  63. data/lib/prawn/text/box.rb +12 -6
  64. data/lib/prawn/text/formatted.rb +5 -4
  65. data/lib/prawn/text/formatted/arranger.rb +290 -0
  66. data/lib/prawn/text/formatted/box.rb +85 -57
  67. data/lib/prawn/text/formatted/fragment.rb +11 -11
  68. data/lib/prawn/text/formatted/line_wrap.rb +266 -0
  69. data/lib/prawn/text/formatted/parser.rb +11 -4
  70. data/lib/prawn/text/formatted/wrap.rb +156 -0
  71. data/lib/prawn/utilities.rb +5 -3
  72. data/manual/document_and_page_options/document_and_page_options.rb +2 -1
  73. data/manual/document_and_page_options/metadata.rb +3 -3
  74. data/manual/document_and_page_options/page_size.rb +2 -2
  75. data/manual/document_and_page_options/print_scaling.rb +20 -0
  76. data/manual/example_file.rb +2 -7
  77. data/manual/example_helper.rb +62 -81
  78. data/manual/graphics/common_lines.rb +2 -0
  79. data/manual/graphics/helper.rb +11 -4
  80. data/manual/graphics/stroke_dash.rb +19 -14
  81. data/manual/manual/cover.rb +16 -0
  82. data/manual/manual/manual.rb +1 -5
  83. data/manual/text/fallback_fonts.rb +4 -4
  84. data/manual/text/formatted_text.rb +5 -5
  85. data/manual/text/inline.rb +2 -4
  86. data/manual/text/registering_families.rb +12 -12
  87. data/manual/text/single_usage.rb +4 -4
  88. data/manual/text/text.rb +0 -2
  89. data/prawn.gemspec +21 -13
  90. data/spec/acceptance/png.rb +23 -0
  91. data/spec/annotations_spec.rb +16 -32
  92. data/spec/bounding_box_spec.rb +22 -5
  93. data/spec/cell_spec.rb +49 -5
  94. data/spec/column_box_spec.rb +32 -0
  95. data/spec/destinations_spec.rb +5 -5
  96. data/spec/document_spec.rb +112 -118
  97. data/spec/extensions/encoding_helpers.rb +5 -2
  98. data/spec/font_metric_cache_spec.rb +52 -0
  99. data/spec/font_spec.rb +121 -120
  100. data/spec/formatted_text_arranger_spec.rb +24 -24
  101. data/spec/formatted_text_box_spec.rb +31 -32
  102. data/spec/formatted_text_fragment_spec.rb +2 -2
  103. data/spec/graphics_spec.rb +63 -45
  104. data/spec/grid_spec.rb +24 -13
  105. data/spec/image_handler_spec.rb +54 -0
  106. data/spec/images_spec.rb +34 -21
  107. data/spec/inline_formatted_text_parser_spec.rb +69 -20
  108. data/spec/jpg_spec.rb +3 -3
  109. data/spec/line_wrap_spec.rb +25 -14
  110. data/spec/measurement_units_spec.rb +5 -5
  111. data/spec/outline_spec.rb +68 -64
  112. data/spec/png_spec.rb +15 -18
  113. data/spec/reference_spec.rb +2 -82
  114. data/spec/repeater_spec.rb +1 -1
  115. data/spec/security_spec.rb +41 -9
  116. data/spec/soft_mask_spec.rb +0 -40
  117. data/spec/span_spec.rb +6 -11
  118. data/spec/spec_helper.rb +20 -2
  119. data/spec/stamp_spec.rb +19 -20
  120. data/spec/stroke_styles_spec.rb +31 -13
  121. data/spec/table/span_dummy_spec.rb +17 -0
  122. data/spec/table_spec.rb +268 -43
  123. data/spec/text_at_spec.rb +13 -27
  124. data/spec/text_box_spec.rb +35 -30
  125. data/spec/text_spec.rb +56 -40
  126. data/spec/transparency_spec.rb +5 -5
  127. metadata +214 -217
  128. data/README.md +0 -98
  129. data/data/fonts/Action Man.dfont +0 -0
  130. data/data/fonts/Activa.ttf +0 -0
  131. data/data/fonts/Chalkboard.ttf +0 -0
  132. data/data/fonts/DejaVuSans.ttf +0 -0
  133. data/data/fonts/Dustismo_Roman.ttf +0 -0
  134. data/data/fonts/comicsans.ttf +0 -0
  135. data/data/fonts/gkai00mp.ttf +0 -0
  136. data/data/images/16bit.dat +0 -0
  137. data/data/images/barcode_issue.png +0 -0
  138. data/data/images/dice.dat +0 -0
  139. data/data/images/page_white_text.dat +0 -0
  140. data/data/images/rails.dat +0 -0
  141. data/data/images/rails.png +0 -0
  142. data/lib/prawn/compatibility.rb +0 -87
  143. data/lib/prawn/core.rb +0 -87
  144. data/lib/prawn/core/annotations.rb +0 -61
  145. data/lib/prawn/core/byte_string.rb +0 -9
  146. data/lib/prawn/core/destinations.rb +0 -90
  147. data/lib/prawn/core/document_state.rb +0 -79
  148. data/lib/prawn/core/literal_string.rb +0 -16
  149. data/lib/prawn/core/name_tree.rb +0 -177
  150. data/lib/prawn/core/object_store.rb +0 -320
  151. data/lib/prawn/core/page.rb +0 -212
  152. data/lib/prawn/core/pdf_object.rb +0 -125
  153. data/lib/prawn/core/reference.rb +0 -119
  154. data/lib/prawn/core/text.rb +0 -268
  155. data/lib/prawn/core/text/formatted/arranger.rb +0 -294
  156. data/lib/prawn/core/text/formatted/line_wrap.rb +0 -288
  157. data/lib/prawn/core/text/formatted/wrap.rb +0 -153
  158. data/lib/prawn/document/page_geometry.rb +0 -136
  159. data/lib/prawn/document/snapshot.rb +0 -89
  160. data/manual/manual/foreword.rb +0 -13
  161. data/manual/templates/full_template.rb +0 -23
  162. data/manual/templates/page_template.rb +0 -47
  163. data/manual/templates/templates.rb +0 -26
  164. data/manual/text/group.rb +0 -29
  165. data/spec/name_tree_spec.rb +0 -112
  166. data/spec/object_store_spec.rb +0 -170
  167. data/spec/pdf_object_spec.rb +0 -172
  168. data/spec/snapshot_spec.rb +0 -186
  169. data/spec/template_spec.rb +0 -351
@@ -1,172 +0,0 @@
1
- # encoding: ASCII-8BIT
2
-
3
- require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
4
-
5
- # See PDF Reference, Sixth Edition (1.7) pp51-60 for details
6
- describe "PDF Object Serialization" do
7
-
8
- it "should convert Ruby's nil to PDF null" do
9
- Prawn::Core::PdfObject(nil).should == "null"
10
- end
11
-
12
- it "should convert Ruby booleans to PDF booleans" do
13
- Prawn::Core::PdfObject(true).should == "true"
14
- Prawn::Core::PdfObject(false).should == "false"
15
- end
16
-
17
- it "should convert a Ruby number to PDF number" do
18
- Prawn::Core::PdfObject(1).should == "1"
19
- Prawn::Core::PdfObject(1.214112421).should == "1.214112421"
20
- # scientific notation is not valid in PDF
21
- Prawn::Core::PdfObject(0.000005).should == "0.000005"
22
- end
23
-
24
- it "should convert a Ruby time object to a PDF timestamp" do
25
- t = Time.now
26
- Prawn::Core::PdfObject(t).should == t.strftime("(D:%Y%m%d%H%M%S%z").chop.chop + "'00')"
27
- end
28
-
29
- it "should convert a Ruby string to PDF string when inside a content stream" do
30
- s = "I can has a string"
31
- PDF::Inspector.parse(Prawn::Core::PdfObject(s, true)).should == s
32
- end
33
-
34
- it "should convert a Ruby string to a UTF-16 PDF string when outside a content stream" do
35
- s = "I can has a string"
36
- s_utf16 = "\xFE\xFF" + s.unpack("U*").pack("n*")
37
- PDF::Inspector.parse(Prawn::Core::PdfObject(s, false)).should == s_utf16
38
- end
39
-
40
- it "should convert a Ruby string with characters outside the BMP to its " +
41
- "UTF-16 representation with a BOM" do
42
- # U+10192 ROMAN SEMUNCIA SIGN
43
- semuncia = [65938].pack("U")
44
- Prawn::Core::PdfObject(semuncia, false).upcase.should == "<FEFFD800DD92>"
45
- end
46
-
47
- it "should pass through bytes regardless of content stream status for ByteString" do
48
- Prawn::Core::PdfObject(Prawn::Core::ByteString.new("\xDE\xAD\xBE\xEF")).upcase.
49
- should == "<DEADBEEF>"
50
- end
51
-
52
- it "should escape parens when converting from Ruby string to PDF" do
53
- s = 'I )(can has a string'
54
- PDF::Inspector.parse(Prawn::Core::PdfObject(s, true)).should == s
55
- end
56
-
57
- it "should handle ruby escaped parens when converting to PDF string" do
58
- s = 'I can \\)( has string'
59
- PDF::Inspector.parse(Prawn::Core::PdfObject(s, true)).should == s
60
- end
61
-
62
- it "should escape various strings correctly when converting a LiteralString" do
63
- ls = Prawn::Core::LiteralString.new("abc")
64
- Prawn::Core::PdfObject(ls).should == "(abc)"
65
-
66
- ls = Prawn::Core::LiteralString.new("abc\x0Ade") # should escape \n
67
- Prawn::Core::PdfObject(ls).should == "(abc\x5C\x0Ade)"
68
-
69
- ls = Prawn::Core::LiteralString.new("abc\x0Dde") # should escape \r
70
- Prawn::Core::PdfObject(ls).should == "(abc\x5C\x0Dde)"
71
-
72
- ls = Prawn::Core::LiteralString.new("abc\x09de") # should escape \t
73
- Prawn::Core::PdfObject(ls).should == "(abc\x5C\x09de)"
74
-
75
- ls = Prawn::Core::LiteralString.new("abc\x08de") # should escape \b
76
- Prawn::Core::PdfObject(ls).should == "(abc\x5C\x08de)"
77
-
78
- ls = Prawn::Core::LiteralString.new("abc\x0Cde") # should escape \f
79
- Prawn::Core::PdfObject(ls).should == "(abc\x5C\x0Cde)"
80
-
81
- ls = Prawn::Core::LiteralString.new("abc(de") # should escape \(
82
- Prawn::Core::PdfObject(ls).should == "(abc\x5C(de)"
83
-
84
- ls = Prawn::Core::LiteralString.new("abc)de") # should escape \)
85
- Prawn::Core::PdfObject(ls).should == "(abc\x5C)de)"
86
-
87
- ls = Prawn::Core::LiteralString.new("abc\x5Cde") # should escape \\
88
- Prawn::Core::PdfObject(ls).should == "(abc\x5C\x5Cde)"
89
- Prawn::Core::PdfObject(ls).size.should == 9
90
- end
91
-
92
- it "should escape strings correctly when converting a LiteralString that is not utf-8" do
93
- data = "\x43\xaf\xc9\x7f\xef\xf\xe6\xa8\xcb\x5c\xaf\xd0"
94
- ls = Prawn::Core::LiteralString.new(data)
95
- Prawn::Core::PdfObject(ls).should == "(\x43\xaf\xc9\x7f\xef\xf\xe6\xa8\xcb\x5c\x5c\xaf\xd0)"
96
- end
97
-
98
- it "should convert a Ruby symbol to PDF name" do
99
- Prawn::Core::PdfObject(:my_symbol).should == "/my_symbol"
100
- Prawn::Core::PdfObject(:"A;Name_With-Various***Characters?").should ==
101
- "/A;Name_With-Various***Characters?"
102
- end
103
-
104
- it "should convert a whitespace or delimiter containing Ruby symbol to a PDF name" do
105
- Prawn::Core::PdfObject(:"my symbol").should == "/my#20symbol"
106
- Prawn::Core::PdfObject(:"my#symbol").should == "/my#23symbol"
107
- Prawn::Core::PdfObject(:"my/symbol").should == "/my#2Fsymbol"
108
- Prawn::Core::PdfObject(:"my(symbol").should == "/my#28symbol"
109
- Prawn::Core::PdfObject(:"my)symbol").should == "/my#29symbol"
110
- Prawn::Core::PdfObject(:"my<symbol").should == "/my#3Csymbol"
111
- Prawn::Core::PdfObject(:"my>symbol").should == "/my#3Esymbol"
112
- end
113
-
114
- it "should convert a Ruby array to PDF Array when inside a content stream" do
115
- Prawn::Core::PdfObject([1,2,3]).should == "[1 2 3]"
116
- PDF::Inspector.parse(Prawn::Core::PdfObject([[1,2],:foo,"Bar"], true)).should ==
117
- [[1,2],:foo, "Bar"]
118
- end
119
-
120
- it "should convert a Ruby array to PDF Array when outside a content stream" do
121
- bar = "\xFE\xFF" + "Bar".unpack("U*").pack("n*")
122
- Prawn::Core::PdfObject([1,2,3]).should == "[1 2 3]"
123
- PDF::Inspector.parse(Prawn::Core::PdfObject([[1,2],:foo,"Bar"], false)).should ==
124
- [[1,2],:foo, bar]
125
- end
126
-
127
- it "should convert a Ruby hash to a PDF Dictionary when inside a content stream" do
128
- dict = Prawn::Core::PdfObject( {:foo => :bar,
129
- "baz" => [1,2,3],
130
- :bang => {:a => "what", :b => [:you, :say] }}, true )
131
-
132
- res = PDF::Inspector.parse(dict)
133
-
134
- res[:foo].should == :bar
135
- res[:baz].should == [1,2,3]
136
- res[:bang].should == { :a => "what", :b => [:you, :say] }
137
-
138
- end
139
-
140
- it "should convert a Ruby hash to a PDF Dictionary when outside a content stream" do
141
- what = "\xFE\xFF" + "what".unpack("U*").pack("n*")
142
- dict = Prawn::Core::PdfObject( {:foo => :bar,
143
- "baz" => [1,2,3],
144
- :bang => {:a => "what", :b => [:you, :say] }}, false )
145
-
146
- res = PDF::Inspector.parse(dict)
147
-
148
- res[:foo].should == :bar
149
- res[:baz].should == [1,2,3]
150
- res[:bang].should == { :a => what, :b => [:you, :say] }
151
-
152
- end
153
-
154
- it "should not allow keys other than strings or symbols for PDF dicts" do
155
- lambda { Prawn::Core::PdfObject(:foo => :bar, :baz => :bang, 1 => 4) }.
156
- should raise_error(Prawn::Errors::FailedObjectConversion)
157
- end
158
-
159
- it "should convert a Prawn::Reference to a PDF indirect object reference" do
160
- ref = Prawn::Core::Reference(1,true)
161
- Prawn::Core::PdfObject(ref).should == ref.to_s
162
- end
163
-
164
- it "should convert a NameTree::Node to a PDF hash" do
165
- node = Prawn::Core::NameTree::Node.new(Prawn::Document.new, 10)
166
- node.add "hello", 1.0
167
- node.add "world", 2.0
168
- data = Prawn::Core::PdfObject(node)
169
- res = PDF::Inspector.parse(data)
170
- res.should == {:Names => ["hello", 1.0, "world", 2.0]}
171
- end
172
- end
@@ -1,186 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
4
-
5
- describe "Prawn::Document#transaction" do
6
-
7
- it "should properly commit if no error is raised" do
8
- pdf = Prawn::Document.new do
9
- transaction do
10
- text "This is shown"
11
- end
12
- end
13
- text = PDF::Inspector::Text.analyze(pdf.render)
14
- text.strings.should == ["This is shown"]
15
- end
16
-
17
- it "should not display text if transaction is rolled back" do
18
- pdf = Prawn::Document.new do
19
- transaction do
20
- text "This is not shown"
21
- rollback
22
- end
23
- end
24
- text = PDF::Inspector::Text.analyze(pdf.render)
25
- text.strings.should == []
26
- end
27
-
28
- it "should return true/false value indicating success of the transaction" do
29
- Prawn::Document.new do
30
- success = transaction { }
31
- success.should == true
32
-
33
- success = transaction { rollback }
34
- success.should == false
35
- end
36
- end
37
-
38
- it "should support nested transactions" do
39
- pdf = Prawn::Document.new do
40
- transaction do
41
- text "This is shown"
42
- transaction do
43
- text "and this is not"
44
- rollback
45
- end
46
- text "and this is"
47
- end
48
- end
49
- text = PDF::Inspector::Text.analyze(pdf.render)
50
- text.strings.should == ["This is shown", "and this is"]
51
- end
52
-
53
- it "should allow rollback of multiple pages" do
54
- pdf = Prawn::Document.new do
55
- transaction do
56
- 5.times { start_new_page }
57
- text "way out there and will never be shown"
58
- rollback
59
- end
60
- text "This is the real text, only one page"
61
- end
62
-
63
- pages = PDF::Inspector::Page.analyze(pdf.render).pages
64
- pages.size.should == 1
65
- end
66
-
67
- it "should not propagate a RollbackTransaction outside its bounds" do
68
- def add_lines(pdf)
69
- 100.times { |i| pdf.text "Line #{i}" }
70
- end
71
-
72
- Prawn::Document.new do |pdf|
73
- lambda do
74
- begin
75
- pdf.group { add_lines(pdf) }
76
- rescue Prawn::Errors::CannotGroup
77
- add_lines(pdf)
78
- end
79
- end.should_not raise_error#(Prawn::Document::Snapshot::RollbackTransaction)
80
- end
81
- end
82
-
83
- # Because the Pages object, when restored, points to the snapshotted pages
84
- # by identifier, we have to restore the snapshot into the same page objects,
85
- # or else old pages will appear in the post-rollback document.
86
- it "should restore the pages into the same objects" do
87
- Prawn::Document.new do
88
- old_page_object_id = state.page.dictionary.identifier
89
- old_page_content_id = state.page.content.identifier
90
-
91
- transaction do
92
- start_new_page
93
- rollback
94
- end
95
-
96
- state.page.dictionary.identifier.should == old_page_object_id
97
- state.page.content.identifier.should == old_page_content_id
98
- end
99
-
100
- end
101
-
102
- it "page object should refer to the page_content object after restore" do
103
-
104
- Prawn::Document.new do
105
- transaction do
106
- start_new_page
107
- rollback
108
- end
109
-
110
- # should be the exact same object, not a clone
111
- state.page.dictionary.data[:Contents].should == state.page.content
112
- end
113
-
114
- end
115
-
116
- it "should restore bounds on rollback" do
117
- Prawn::Document.new(:page_layout => :landscape) do
118
- size = [bounds.width, bounds.height]
119
- transaction do
120
- start_new_page :layout => :portrait
121
- rollback
122
- end
123
- [bounds.width, bounds.height].should == size
124
- end
125
- end
126
-
127
- it "should set new bounding box on start_new_page with different layout" do
128
- Prawn::Document.new(:page_layout => :landscape) do
129
- size = [bounds.width, bounds.height]
130
- transaction do
131
- start_new_page
132
- rollback
133
- end
134
-
135
- start_new_page :layout => :portrait
136
- [bounds.width, bounds.height].should == size.reverse
137
- end
138
- end
139
-
140
- it "should work with dests" do
141
- Prawn::Document.new do |pdf|
142
- pdf.add_dest("dest", pdf.dest_fit_horizontally(pdf.cursor, pdf.page))
143
- pdf.text("Hello world")
144
- lambda { pdf.transaction{} }.should_not raise_error
145
- end
146
- end
147
-
148
- describe "with a stamp dictionary present" do
149
-
150
- it "should properly commit if no error is raised" do
151
- pdf = Prawn::Document.new do
152
- create_stamp("test_stamp") { draw_text "This is shown", :at => [0,0] }
153
- transaction do
154
- stamp("test_stamp")
155
- end
156
- end
157
- pdf.render.should =~ /\/Stamp1 Do/
158
- end
159
-
160
- it "should properly rollback when #rollback is called" do
161
- pdf = Prawn::Document.new do
162
- create_stamp("test_stamp") { draw_text "This is not shown", :at => [0,0] }
163
-
164
- transaction do
165
- stamp("test_stamp")
166
- rollback
167
- end
168
- end
169
- pdf.render.should_not =~ /\/Stamp1 Do/
170
- end
171
-
172
- end
173
-
174
- it "should restore page_number on rollback" do
175
- Prawn::Document.new do
176
- transaction do
177
- 5.times { start_new_page }
178
- rollback
179
- end
180
-
181
- page_number.should == 1
182
- end
183
- end
184
-
185
- end
186
-
@@ -1,351 +0,0 @@
1
- require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
2
-
3
- describe "Document built from a template" do
4
- it "should have the same page count as the source document" do
5
- filename = "#{Prawn::BASEDIR}/spec/data/curves.pdf"
6
- @pdf = Prawn::Document.new(:template => filename)
7
- page_counter = PDF::Inspector::Page.analyze(@pdf.render)
8
-
9
- page_counter.pages.size.should == 1
10
- end
11
-
12
- it "should not set the template page's parent to the document pages catalog (especially with nested pages)" do
13
- filename = "#{Prawn::DATADIR}/pdfs/nested_pages.pdf"
14
- @pdf = Prawn::Document.new(:template => filename, :skip_page_creation => true)
15
- @pdf.state.page.dictionary.data[:Parent].should_not == @pdf.state.store.pages
16
- end
17
-
18
-
19
- it "should have start with the Y cursor at the top of the document" do
20
- filename = "#{Prawn::BASEDIR}/spec/data/curves.pdf"
21
-
22
- @pdf = Prawn::Document.new(:template => filename)
23
- (@pdf.y == nil).should == false
24
- end
25
-
26
- it "should respect margins set by Prawn" do
27
- filename = "#{Prawn::BASEDIR}/spec/data/curves.pdf"
28
-
29
- @pdf = Prawn::Document.new(:template => filename, :margin => 0)
30
- @pdf.page.margins.should == { :left => 0,
31
- :right => 0,
32
- :top => 0,
33
- :bottom => 0 }
34
-
35
- @pdf = Prawn::Document.new(:template => filename, :left_margin => 0)
36
-
37
- @pdf.page.margins.should == { :left => 0,
38
- :right => 36,
39
- :top => 36,
40
- :bottom => 36 }
41
-
42
- @pdf.start_new_page(:right_margin => 0)
43
-
44
- @pdf.page.margins.should == { :left => 0,
45
- :right => 0,
46
- :top => 36,
47
- :bottom => 36 }
48
-
49
-
50
-
51
- end
52
-
53
- it "should not add an extra restore_graphics_state operator to the end of any content stream" do
54
- filename = "#{Prawn::BASEDIR}/spec/data/curves.pdf"
55
-
56
- @pdf = Prawn::Document.new(:template => filename)
57
- output = StringIO.new(@pdf.render)
58
- hash = PDF::Reader::ObjectHash.new(output)
59
-
60
- hash.each_value do |obj|
61
- next unless obj.kind_of?(PDF::Reader::Stream)
62
-
63
- data = obj.data.tr(" \n\r","")
64
- data.include?("QQ").should == false
65
- end
66
- end
67
-
68
- it "should have a single page object if importing a single page template" do
69
- filename = "#{Prawn::DATADIR}/pdfs/hexagon.pdf"
70
-
71
- @pdf = Prawn::Document.new(:template => filename)
72
- output = StringIO.new(@pdf.render)
73
- hash = PDF::Reader::ObjectHash.new(output)
74
-
75
- pages = hash.values.select { |obj| obj.kind_of?(Hash) && obj[:Type] == :Page }
76
-
77
- pages.size.should == 1
78
- end
79
-
80
- it "should have two content streams if importing a single page template" do
81
- filename = "#{Prawn::DATADIR}/pdfs/hexagon.pdf"
82
-
83
- @pdf = Prawn::Document.new(:template => filename)
84
- output = StringIO.new(@pdf.render)
85
- hash = PDF::Reader::ObjectHash.new(output)
86
-
87
- streams = hash.values.select { |obj| obj.kind_of?(PDF::Reader::Stream) }
88
-
89
- streams.size.should == 2
90
- end
91
-
92
- it "should not die if using this PDF as a template" do
93
- filename = "#{Prawn::DATADIR}/pdfs/complex_template.pdf"
94
-
95
- lambda {
96
- @pdf = Prawn::Document.new(:template => filename)
97
- }.should_not raise_error
98
- end
99
-
100
-
101
- it "should have balance q/Q operators on all content streams" do
102
- filename = "#{Prawn::DATADIR}/pdfs/hexagon.pdf"
103
-
104
- @pdf = Prawn::Document.new(:template => filename)
105
- output = StringIO.new(@pdf.render)
106
- hash = PDF::Reader::ObjectHash.new(output)
107
-
108
- streams = hash.values.select { |obj| obj.kind_of?(PDF::Reader::Stream) }
109
-
110
- streams.each do |stream|
111
- data = stream.unfiltered_data
112
- data.scan("q").size.should == 1
113
- data.scan("Q").size.should == 1
114
- end
115
- end
116
-
117
- it "should allow text to be added to a single page template" do
118
- filename = "#{Prawn::DATADIR}/pdfs/hexagon.pdf"
119
-
120
- @pdf = Prawn::Document.new(:template => filename)
121
-
122
- @pdf.text "Adding some text"
123
-
124
- text = PDF::Inspector::Text.analyze(@pdf.render)
125
- text.strings.first.should == "Adding some text"
126
- end
127
-
128
- it "should allow PDFs with page resources behind an indirect object to be used as templates" do
129
- filename = "#{Prawn::DATADIR}/pdfs/resources_as_indirect_object.pdf"
130
-
131
- @pdf = Prawn::Document.new(:template => filename)
132
-
133
- @pdf.text "Adding some text"
134
-
135
- text = PDF::Inspector::Text.analyze(@pdf.render)
136
- all_text = text.strings.join
137
- all_text.include?("Adding some text").should == true
138
- end
139
-
140
- it "should copy the PDF version from the template file" do
141
- filename = "#{Prawn::DATADIR}/pdfs/version_1_6.pdf"
142
-
143
- @pdf = Prawn::Document.new(:template => filename)
144
- str = @pdf.render
145
- str[0,8].should == "%PDF-1.6"
146
- end
147
-
148
- it "should correctly add a TTF font to a template that has existing fonts" do
149
- filename = "#{Prawn::DATADIR}/pdfs/contains_ttf_font.pdf"
150
- @pdf = Prawn::Document.new(:template => filename)
151
- @pdf.font "#{Prawn::DATADIR}/fonts/Chalkboard.ttf"
152
- @pdf.move_down(40)
153
- @pdf.text "Hi There"
154
-
155
- output = StringIO.new(@pdf.render)
156
- hash = PDF::Reader::ObjectHash.new(output)
157
-
158
- page_dict = hash.values.detect{ |obj| obj.is_a?(Hash) && obj[:Type] == :Page }
159
- resources = page_dict[:Resources]
160
- fonts = resources[:Font]
161
- fonts.size.should == 2
162
- end
163
-
164
- it "should correctly import a template file that is missing a MediaBox entry" do
165
- filename = "#{Prawn::DATADIR}/pdfs/page_without_mediabox.pdf"
166
-
167
- @pdf = Prawn::Document.new(:template => filename)
168
- str = @pdf.render
169
- str[0,4].should == "%PDF"
170
- end
171
-
172
- context "with the template as a stream" do
173
- it "should correctly import a template file from a stream" do
174
- filename = "#{Prawn::DATADIR}/pdfs/hexagon.pdf"
175
- io = StringIO.new(File.binread(filename))
176
- @pdf = Prawn::Document.new(:template => io)
177
- str = @pdf.render
178
- str[0,4].should == "%PDF"
179
- end
180
- end
181
-
182
- it "merges metadata info" do
183
- filename = "#{Prawn::DATADIR}/pdfs/hexagon.pdf"
184
- info = { :Title => "Sample METADATA",
185
- :Author => "Me",
186
- :Subject => "Not Working",
187
- :CreationDate => Time.now }
188
-
189
- @pdf = Prawn::Document.new(:template => filename, :info => info)
190
- output = StringIO.new(@pdf.render)
191
- hash = PDF::Reader::ObjectHash.new(output)
192
- info.keys.each { |k| hash[hash.trailer[:Info]].keys.include?(k).should == true }
193
- end
194
-
195
- end
196
-
197
- describe "Document#start_new_page with :template option" do
198
- filename = "#{Prawn::BASEDIR}/spec/data/curves.pdf"
199
-
200
- it "should set the imported page's parent to the document pages catalog" do
201
- @pdf = Prawn::Document.new()
202
- @pdf.start_new_page(:template => filename)
203
- @pdf.state.page.dictionary.data[:Parent].should == @pdf.state.store.pages
204
- end
205
-
206
- it "should set start the Y cursor at the top of the page" do
207
- @pdf = Prawn::Document.new()
208
- @pdf.start_new_page(:template => filename)
209
- (@pdf.y == nil).should == false
210
- end
211
-
212
- it "should respect margins set by Prawn" do
213
- @pdf = Prawn::Document.new(:margin => 0)
214
- @pdf.start_new_page(:template => filename)
215
- @pdf.page.margins.should == { :left => 0,
216
- :right => 0,
217
- :top => 0,
218
- :bottom => 0 }
219
-
220
- @pdf = Prawn::Document.new(:left_margin => 0)
221
- @pdf.start_new_page(:template => filename)
222
- @pdf.page.margins.should == { :left => 0,
223
- :right => 36,
224
- :top => 36,
225
- :bottom => 36 }
226
- @pdf.start_new_page(:template => filename, :right_margin => 0)
227
- @pdf.page.margins.should == { :left => 0,
228
- :right => 0,
229
- :top => 36,
230
- :bottom => 36 }
231
- end
232
-
233
- it "should not add an extra restore_graphics_state operator to the end of any content stream" do
234
- @pdf = Prawn::Document.new
235
- @pdf.start_new_page(:template => filename)
236
- output = StringIO.new(@pdf.render)
237
- hash = PDF::Reader::ObjectHash.new(output)
238
-
239
- hash.each_value do |obj|
240
- next unless obj.kind_of?(PDF::Reader::Stream)
241
-
242
- data = obj.data.tr(" \n\r","")
243
- data.include?("QQ").should == false
244
- end
245
- end
246
-
247
- it "should have two content streams if importing a single page template" do
248
- filename = "#{Prawn::DATADIR}/pdfs/hexagon.pdf"
249
- @pdf = Prawn::Document.new()
250
- @pdf.start_new_page(:template => filename)
251
- output = StringIO.new(@pdf.render)
252
- hash = PDF::Reader::ObjectHash.new(output)
253
- pages = hash.values.find {|obj| obj.is_a?(Hash) && obj[:Type] == :Pages}[:Kids]
254
- template_page = hash[pages[1]]
255
- template_page[:Contents].size.should == 2
256
- end
257
-
258
- it "should have balance q/Q operators on all content streams" do
259
- filename = "#{Prawn::DATADIR}/pdfs/hexagon.pdf"
260
-
261
- @pdf = Prawn::Document.new()
262
- @pdf.start_new_page(:template => filename)
263
- output = StringIO.new(@pdf.render)
264
- hash = PDF::Reader::ObjectHash.new(output)
265
-
266
- streams = hash.values.select { |obj| obj.kind_of?(PDF::Reader::Stream) }
267
-
268
- streams.each do |stream|
269
- data = stream.unfiltered_data
270
- data.scan("q").size.should == 1
271
- data.scan("Q").size.should == 1
272
- end
273
- end
274
-
275
- it "should allow text to be added to a single page template" do
276
-
277
- @pdf = Prawn::Document.new()
278
- @pdf.start_new_page(:template => filename)
279
-
280
- @pdf.text "Adding some text"
281
-
282
- text = PDF::Inspector::Text.analyze(@pdf.render)
283
- text.strings.first.should == "Adding some text"
284
- end
285
-
286
- it "should allow PDFs with page resources behind an indirect object to be used as templates" do
287
- filename = "#{Prawn::DATADIR}/pdfs/resources_as_indirect_object.pdf"
288
-
289
- @pdf = Prawn::Document.new()
290
- @pdf.start_new_page(:template => filename)
291
-
292
- @pdf.text "Adding some text"
293
-
294
- text = PDF::Inspector::Text.analyze(@pdf.render)
295
- all_text = text.strings.join
296
- all_text.include?("Adding some text").should == true
297
- end
298
-
299
- it "should correctly add a TTF font to a template that has existing fonts" do
300
- filename = "#{Prawn::DATADIR}/pdfs/contains_ttf_font.pdf"
301
- @pdf = Prawn::Document.new()
302
- @pdf.start_new_page(:template => filename)
303
- @pdf.font "#{Prawn::DATADIR}/fonts/Chalkboard.ttf"
304
- @pdf.move_down(40)
305
- @pdf.text "Hi There"
306
-
307
- output = StringIO.new(@pdf.render)
308
- hash = PDF::Reader::ObjectHash.new(output)
309
- hash = PDF::Reader::ObjectHash.new(output)
310
- pages = hash.values.find {|obj| obj.is_a?(Hash) && obj[:Type] == :Pages}[:Kids]
311
- template_page = hash[pages[1]]
312
- resources = template_page[:Resources]
313
- fonts = resources[:Font]
314
- fonts.size.should == 2
315
- end
316
-
317
- it "indexes template pages when used multiple times" do
318
- filename = "#{Prawn::DATADIR}/pdfs/multipage_template.pdf"
319
- @repeated_pdf = Prawn::Document.new()
320
- 3.times { @repeated_pdf.start_new_page(:template => filename) }
321
- repeated_hash = PDF::Reader::ObjectHash.new(StringIO.new(@repeated_pdf.render))
322
- @sequential_pdf = Prawn::Document.new()
323
- (1..3).each { |p| @sequential_pdf.start_new_page(:template => filename, :template_page => p ) }
324
- sequential_hash = PDF::Reader::ObjectHash.new(StringIO.new(@sequential_pdf.render))
325
- (repeated_hash.size < sequential_hash.size).should == true
326
- end
327
-
328
- context "with the template as a stream" do
329
- it "should correctly import a template file from a stream" do
330
- filename = "#{Prawn::DATADIR}/pdfs/hexagon.pdf"
331
- io = StringIO.new(File.binread(filename))
332
-
333
- @pdf = Prawn::Document.new()
334
- @pdf.start_new_page(:template => io)
335
-
336
- str = @pdf.render
337
- str[0,4].should == "%PDF"
338
- end
339
- end
340
-
341
- context "using template_page option" do
342
- it "uses the specified page option" do
343
- filename = "#{Prawn::DATADIR}/pdfs/multipage_template.pdf"
344
- @pdf = Prawn::Document.new()
345
- @pdf.start_new_page(:template => filename, :template_page => 2)
346
- text = PDF::Inspector::Text.analyze(@pdf.render)
347
- text.strings.first.should == "This is template page 2"
348
- end
349
- end
350
-
351
- end