prawn 2.1.0 → 2.3.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 (280) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/GPLv2 +20 -21
  5. data/Gemfile +3 -9
  6. data/Rakefile +20 -23
  7. data/lib/prawn.rb +36 -49
  8. data/lib/prawn/document.rb +180 -133
  9. data/lib/prawn/document/bounding_box.rb +41 -29
  10. data/lib/prawn/document/column_box.rb +7 -7
  11. data/lib/prawn/document/internals.rb +8 -6
  12. data/lib/prawn/document/span.rb +21 -16
  13. data/lib/prawn/encoding.rb +69 -68
  14. data/lib/prawn/errors.rb +12 -7
  15. data/lib/prawn/font.rb +102 -69
  16. data/lib/prawn/font_metric_cache.rb +14 -8
  17. data/lib/prawn/{font → fonts}/afm.rb +102 -68
  18. data/lib/prawn/{font → fonts}/dfont.rb +5 -11
  19. data/lib/prawn/fonts/otf.rb +11 -0
  20. data/lib/prawn/fonts/ttc.rb +36 -0
  21. data/lib/prawn/{font → fonts}/ttf.rb +87 -68
  22. data/lib/prawn/graphics.rb +119 -81
  23. data/lib/prawn/graphics/blend_mode.rb +9 -8
  24. data/lib/prawn/graphics/cap_style.rb +3 -3
  25. data/lib/prawn/graphics/color.rb +27 -25
  26. data/lib/prawn/graphics/dash.rb +23 -11
  27. data/lib/prawn/graphics/join_style.rb +9 -3
  28. data/lib/prawn/graphics/patterns.rb +190 -96
  29. data/lib/prawn/graphics/transformation.rb +15 -9
  30. data/lib/prawn/graphics/transparency.rb +17 -13
  31. data/lib/prawn/grid.rb +48 -47
  32. data/lib/prawn/image_handler.rb +5 -5
  33. data/lib/prawn/images.rb +39 -30
  34. data/lib/prawn/images/image.rb +2 -1
  35. data/lib/prawn/images/jpg.rb +28 -22
  36. data/lib/prawn/images/png.rb +65 -62
  37. data/lib/prawn/measurement_extensions.rb +10 -9
  38. data/lib/prawn/measurements.rb +19 -15
  39. data/lib/prawn/outline.rb +97 -77
  40. data/lib/prawn/repeater.rb +14 -10
  41. data/lib/prawn/security.rb +81 -61
  42. data/lib/prawn/security/arcfour.rb +2 -2
  43. data/lib/prawn/soft_mask.rb +26 -26
  44. data/lib/prawn/stamp.rb +20 -13
  45. data/lib/prawn/text.rb +68 -52
  46. data/lib/prawn/text/box.rb +11 -8
  47. data/lib/prawn/text/formatted.rb +5 -5
  48. data/lib/prawn/text/formatted/arranger.rb +53 -32
  49. data/lib/prawn/text/formatted/box.rb +134 -100
  50. data/lib/prawn/text/formatted/fragment.rb +11 -14
  51. data/lib/prawn/text/formatted/line_wrap.rb +122 -63
  52. data/lib/prawn/text/formatted/parser.rb +139 -117
  53. data/lib/prawn/text/formatted/wrap.rb +43 -31
  54. data/lib/prawn/transformation_stack.rb +7 -5
  55. data/lib/prawn/utilities.rb +7 -22
  56. data/lib/prawn/version.rb +2 -2
  57. data/lib/prawn/view.rb +17 -7
  58. data/manual/basic_concepts/adding_pages.rb +6 -7
  59. data/manual/basic_concepts/basic_concepts.rb +31 -22
  60. data/manual/basic_concepts/creation.rb +10 -11
  61. data/manual/basic_concepts/cursor.rb +4 -5
  62. data/manual/basic_concepts/measurement.rb +6 -7
  63. data/manual/basic_concepts/origin.rb +5 -6
  64. data/manual/basic_concepts/other_cursor_helpers.rb +11 -12
  65. data/manual/basic_concepts/view.rb +22 -16
  66. data/manual/bounding_box/bounding_box.rb +29 -24
  67. data/manual/bounding_box/bounds.rb +11 -12
  68. data/manual/bounding_box/canvas.rb +4 -5
  69. data/manual/bounding_box/creation.rb +6 -7
  70. data/manual/bounding_box/indentation.rb +14 -15
  71. data/manual/bounding_box/nesting.rb +24 -17
  72. data/manual/bounding_box/russian_boxes.rb +14 -13
  73. data/manual/bounding_box/stretchy.rb +12 -13
  74. data/manual/contents.rb +28 -22
  75. data/manual/cover.rb +33 -28
  76. data/manual/document_and_page_options/background.rb +11 -13
  77. data/manual/document_and_page_options/document_and_page_options.rb +25 -20
  78. data/manual/document_and_page_options/metadata.rb +18 -16
  79. data/manual/document_and_page_options/page_margins.rb +18 -20
  80. data/manual/document_and_page_options/page_size.rb +13 -12
  81. data/manual/document_and_page_options/print_scaling.rb +17 -15
  82. data/manual/example_helper.rb +5 -4
  83. data/manual/graphics/blend_mode.rb +12 -9
  84. data/manual/graphics/circle_and_ellipse.rb +4 -5
  85. data/manual/graphics/color.rb +7 -9
  86. data/manual/graphics/common_lines.rb +7 -8
  87. data/manual/graphics/fill_and_stroke.rb +4 -5
  88. data/manual/graphics/fill_rules.rb +9 -10
  89. data/manual/graphics/gradients.rb +27 -21
  90. data/manual/graphics/graphics.rb +48 -40
  91. data/manual/graphics/helper.rb +12 -9
  92. data/manual/graphics/line_width.rb +8 -7
  93. data/manual/graphics/lines_and_curves.rb +7 -8
  94. data/manual/graphics/polygon.rb +6 -8
  95. data/manual/graphics/rectangle.rb +4 -5
  96. data/manual/graphics/rotate.rb +6 -7
  97. data/manual/graphics/scale.rb +14 -15
  98. data/manual/graphics/soft_masks.rb +3 -4
  99. data/manual/graphics/stroke_cap.rb +6 -7
  100. data/manual/graphics/stroke_dash.rb +11 -12
  101. data/manual/graphics/stroke_join.rb +5 -6
  102. data/manual/graphics/translate.rb +9 -10
  103. data/manual/graphics/transparency.rb +7 -8
  104. data/manual/how_to_read_this_manual.rb +6 -6
  105. data/manual/images/absolute_position.rb +6 -7
  106. data/manual/images/fit.rb +7 -8
  107. data/manual/images/horizontal.rb +9 -10
  108. data/manual/images/images.rb +28 -24
  109. data/manual/images/plain_image.rb +5 -6
  110. data/manual/images/scale.rb +9 -10
  111. data/manual/images/vertical.rb +13 -14
  112. data/manual/images/width_and_height.rb +10 -11
  113. data/manual/layout/boxes.rb +5 -6
  114. data/manual/layout/content.rb +7 -8
  115. data/manual/layout/layout.rb +18 -16
  116. data/manual/layout/simple_grid.rb +6 -7
  117. data/manual/outline/add_subsection_to.rb +20 -21
  118. data/manual/outline/insert_section_after.rb +15 -16
  119. data/manual/outline/outline.rb +21 -17
  120. data/manual/outline/sections_and_pages.rb +17 -18
  121. data/manual/repeatable_content/alternate_page_numbering.rb +21 -17
  122. data/manual/repeatable_content/page_numbering.rb +17 -16
  123. data/manual/repeatable_content/repeatable_content.rb +25 -19
  124. data/manual/repeatable_content/repeater.rb +14 -15
  125. data/manual/repeatable_content/stamp.rb +14 -15
  126. data/manual/security/encryption.rb +9 -10
  127. data/manual/security/permissions.rb +19 -14
  128. data/manual/security/security.rb +19 -16
  129. data/manual/table.rb +3 -3
  130. data/manual/text/alignment.rb +16 -17
  131. data/manual/text/color.rb +12 -11
  132. data/manual/text/column_box.rb +9 -10
  133. data/manual/text/fallback_fonts.rb +25 -21
  134. data/manual/text/font.rb +11 -12
  135. data/manual/text/font_size.rb +13 -14
  136. data/manual/text/font_style.rb +7 -8
  137. data/manual/text/formatted_callbacks.rb +25 -21
  138. data/manual/text/formatted_text.rb +33 -25
  139. data/manual/text/free_flowing_text.rb +20 -21
  140. data/manual/text/inline.rb +18 -19
  141. data/manual/text/kerning_and_character_spacing.rb +14 -15
  142. data/manual/text/leading.rb +7 -8
  143. data/manual/text/line_wrapping.rb +37 -18
  144. data/manual/text/paragraph_indentation.rb +13 -14
  145. data/manual/text/positioned_text.rb +15 -16
  146. data/manual/text/registering_families.rb +20 -21
  147. data/manual/text/rendering_and_color.rb +9 -10
  148. data/manual/text/right_to_left_text.rb +26 -19
  149. data/manual/text/rotation.rb +28 -23
  150. data/manual/text/single_usage.rb +8 -9
  151. data/manual/text/text.rb +57 -52
  152. data/manual/text/text_box_excess.rb +20 -17
  153. data/manual/text/text_box_extensions.rb +18 -15
  154. data/manual/text/text_box_overflow.rb +18 -19
  155. data/manual/text/utf8.rb +11 -12
  156. data/manual/text/win_ansi_charset.rb +21 -19
  157. data/prawn.gemspec +44 -31
  158. data/spec/extensions/encoding_helpers.rb +3 -3
  159. data/spec/prawn/document/bounding_box_spec.rb +546 -0
  160. data/spec/prawn/document/column_box_spec.rb +75 -0
  161. data/spec/prawn/document/security_spec.rb +176 -0
  162. data/spec/prawn/document_annotations_spec.rb +76 -0
  163. data/spec/prawn/document_destinations_spec.rb +15 -0
  164. data/spec/prawn/document_grid_spec.rb +99 -0
  165. data/spec/prawn/document_reference_spec.rb +27 -0
  166. data/spec/prawn/document_span_spec.rb +36 -0
  167. data/spec/prawn/document_spec.rb +802 -0
  168. data/spec/prawn/font_metric_cache_spec.rb +54 -0
  169. data/spec/prawn/font_spec.rb +542 -0
  170. data/spec/prawn/graphics/blend_mode_spec.rb +63 -0
  171. data/spec/prawn/graphics/transparency_spec.rb +81 -0
  172. data/spec/prawn/graphics_spec.rb +837 -0
  173. data/spec/prawn/graphics_stroke_styles_spec.rb +229 -0
  174. data/spec/{image_handler_spec.rb → prawn/image_handler_spec.rb} +14 -14
  175. data/spec/prawn/images/jpg_spec.rb +20 -0
  176. data/spec/prawn/images/png_spec.rb +283 -0
  177. data/spec/prawn/images_spec.rb +224 -0
  178. data/spec/prawn/measurements_extensions_spec.rb +24 -0
  179. data/spec/prawn/outline_spec.rb +412 -0
  180. data/spec/prawn/repeater_spec.rb +165 -0
  181. data/spec/prawn/soft_mask_spec.rb +74 -0
  182. data/spec/prawn/stamp_spec.rb +172 -0
  183. data/spec/prawn/text/box_spec.rb +1112 -0
  184. data/spec/prawn/text/formatted/arranger_spec.rb +466 -0
  185. data/spec/prawn/text/formatted/box_spec.rb +846 -0
  186. data/spec/prawn/text/formatted/fragment_spec.rb +343 -0
  187. data/spec/prawn/text/formatted/line_wrap_spec.rb +494 -0
  188. data/spec/prawn/text/formatted/parser_spec.rb +697 -0
  189. data/spec/prawn/text_draw_text_spec.rb +149 -0
  190. data/spec/prawn/text_rendering_mode_spec.rb +48 -0
  191. data/spec/prawn/text_spacing_spec.rb +95 -0
  192. data/spec/prawn/text_spec.rb +603 -0
  193. data/spec/prawn/text_with_inline_formatting_spec.rb +35 -0
  194. data/spec/{transformation_stack_spec.rb → prawn/transformation_stack_spec.rb} +22 -19
  195. data/spec/prawn/view_spec.rb +63 -0
  196. data/spec/prawn_manual_spec.rb +35 -0
  197. data/spec/spec_helper.rb +18 -19
  198. metadata +144 -180
  199. metadata.gz.sig +4 -0
  200. data/data/images/16bit.alpha +0 -0
  201. data/data/images/16bit.color +0 -0
  202. data/data/images/16bit.png +0 -0
  203. data/data/images/arrow.png +0 -0
  204. data/data/images/arrow2.png +0 -0
  205. data/data/images/blend_modes_bottom_layer.jpg +0 -0
  206. data/data/images/blend_modes_top_layer.jpg +0 -0
  207. data/data/images/dice.alpha +0 -0
  208. data/data/images/dice.color +0 -0
  209. data/data/images/dice.png +0 -0
  210. data/data/images/dice_interlaced.png +0 -0
  211. data/data/images/fractal.jpg +0 -0
  212. data/data/images/indexed_color.dat +0 -0
  213. data/data/images/indexed_color.png +0 -0
  214. data/data/images/indexed_transparency.png +0 -0
  215. data/data/images/indexed_transparency_alpha.dat +0 -0
  216. data/data/images/indexed_transparency_color.dat +0 -0
  217. data/data/images/letterhead.jpg +0 -0
  218. data/data/images/license.md +0 -8
  219. data/data/images/page_white_text.alpha +0 -0
  220. data/data/images/page_white_text.color +0 -0
  221. data/data/images/page_white_text.png +0 -0
  222. data/data/images/pigs.jpg +0 -0
  223. data/data/images/prawn.png +0 -0
  224. data/data/images/ruport.png +0 -0
  225. data/data/images/ruport_data.dat +0 -0
  226. data/data/images/ruport_transparent.png +0 -0
  227. data/data/images/ruport_type0.png +0 -0
  228. data/data/images/stef.jpg +0 -0
  229. data/data/images/tru256.bmp +0 -0
  230. data/data/images/web-links.dat +0 -1
  231. data/data/images/web-links.png +0 -0
  232. data/data/pdfs/complex_template.pdf +0 -0
  233. data/data/pdfs/contains_ttf_font.pdf +0 -0
  234. data/data/pdfs/encrypted.pdf +0 -0
  235. data/data/pdfs/form.pdf +1 -819
  236. data/data/pdfs/hexagon.pdf +0 -61
  237. data/data/pdfs/indirect_reference.pdf +0 -86
  238. data/data/pdfs/multipage_template.pdf +0 -127
  239. data/data/pdfs/nested_pages.pdf +0 -118
  240. data/data/pdfs/page_without_mediabox.pdf +0 -193
  241. data/data/pdfs/resources_as_indirect_object.pdf +0 -83
  242. data/data/pdfs/two_hexagons.pdf +0 -90
  243. data/data/pdfs/version_1_6.pdf +0 -61
  244. data/data/shift_jis_text.txt +0 -1
  245. data/spec/acceptance/png_spec.rb +0 -35
  246. data/spec/annotations_spec.rb +0 -67
  247. data/spec/blend_mode_spec.rb +0 -71
  248. data/spec/bounding_box_spec.rb +0 -501
  249. data/spec/column_box_spec.rb +0 -59
  250. data/spec/destinations_spec.rb +0 -13
  251. data/spec/document_spec.rb +0 -738
  252. data/spec/font_metric_cache_spec.rb +0 -52
  253. data/spec/font_spec.rb +0 -475
  254. data/spec/formatted_text_arranger_spec.rb +0 -452
  255. data/spec/formatted_text_box_spec.rb +0 -716
  256. data/spec/formatted_text_fragment_spec.rb +0 -299
  257. data/spec/graphics_spec.rb +0 -705
  258. data/spec/grid_spec.rb +0 -95
  259. data/spec/images_spec.rb +0 -167
  260. data/spec/inline_formatted_text_parser_spec.rb +0 -568
  261. data/spec/jpg_spec.rb +0 -23
  262. data/spec/line_wrap_spec.rb +0 -366
  263. data/spec/measurement_units_spec.rb +0 -22
  264. data/spec/outline_spec.rb +0 -409
  265. data/spec/png_spec.rb +0 -257
  266. data/spec/reference_spec.rb +0 -25
  267. data/spec/repeater_spec.rb +0 -154
  268. data/spec/security_spec.rb +0 -151
  269. data/spec/soft_mask_spec.rb +0 -78
  270. data/spec/span_spec.rb +0 -43
  271. data/spec/stamp_spec.rb +0 -179
  272. data/spec/stroke_styles_spec.rb +0 -208
  273. data/spec/text_at_spec.rb +0 -142
  274. data/spec/text_box_spec.rb +0 -1042
  275. data/spec/text_rendering_mode_spec.rb +0 -45
  276. data/spec/text_spacing_spec.rb +0 -93
  277. data/spec/text_spec.rb +0 -543
  278. data/spec/text_with_inline_formatting_spec.rb +0 -35
  279. data/spec/transparency_spec.rb +0 -91
  280. data/spec/view_spec.rb +0 -42
@@ -1,59 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
4
-
5
- describe "A column box" do
6
- it "has sensible left and right values" do
7
- create_pdf
8
- @pdf.column_box [0, @pdf.cursor], :width => @pdf.bounds.width, :height => 200, :columns => 3, :spacer => 25 do
9
- left = @pdf.bounds.left
10
- right = @pdf.bounds.right
11
-
12
- @pdf.bounds.move_past_bottom # next column
13
-
14
- expect(@pdf.bounds.left).to be > left
15
- expect(@pdf.bounds.left).to be > right
16
- expect(@pdf.bounds.right).to be > @pdf.bounds.left
17
- end
18
- end
19
-
20
- it "includes spacers between columns but not at the end" do
21
- create_pdf
22
- @pdf.column_box [0, @pdf.cursor], :width => 500, :height => 200, :columns => 3, :spacer => 25 do
23
- expect(@pdf.bounds.width).to eq(150) # (500 - (25 * 2)) / 3
24
-
25
- @pdf.bounds.move_past_bottom
26
- @pdf.bounds.move_past_bottom
27
-
28
- expect(@pdf.bounds.right).to eq(500)
29
- end
30
- end
31
-
32
- it "does not reset the top margin on a new page by default" do
33
- create_pdf
34
- page_top = @pdf.cursor
35
- @pdf.move_down 50
36
- init_column_top = @pdf.cursor
37
- @pdf.column_box [0, @pdf.cursor], :width => 500, :height => 200, :columns => 2 do
38
- @pdf.bounds.move_past_bottom
39
- @pdf.bounds.move_past_bottom
40
-
41
- expect(@pdf.bounds.absolute_top).to eq(init_column_top)
42
- expect(@pdf.bounds.absolute_top).not_to eq(page_top)
43
- end
44
- end
45
-
46
- it "does reset the top margin when reflow_margins is set" do
47
- create_pdf
48
- page_top = @pdf.cursor
49
- @pdf.move_down 50
50
- init_column_top = @pdf.cursor
51
- @pdf.column_box [0, @pdf.cursor], :width => 500, :reflow_margins => true, :height => 200, :columns => 2 do
52
- @pdf.bounds.move_past_bottom
53
- @pdf.bounds.move_past_bottom
54
-
55
- expect(@pdf.bounds.absolute_top).to eq(page_top)
56
- expect(@pdf.bounds.absolute_top).not_to eq(init_column_top)
57
- end
58
- end
59
- end
@@ -1,13 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
4
-
5
- describe "When creating destinations" do
6
- before(:each) { create_pdf }
7
-
8
- it "should add entry to Dests name tree" do
9
- expect(@pdf.dests.data.empty?).to eq(true)
10
- @pdf.add_dest "candy", "chocolate"
11
- expect(@pdf.dests.data.size).to eq(1)
12
- end
13
- end
@@ -1,738 +0,0 @@
1
- # encoding: utf-8
2
- require "tempfile"
3
-
4
- require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
5
-
6
- describe "Prawn::Document.new" do
7
- it "should not modify its argument" do
8
- options = { :page_layout => :landscape }
9
- Prawn::Document.new(options)
10
- expect(options).to eq(:page_layout => :landscape)
11
- end
12
- end
13
-
14
- describe "The cursor" do
15
- it "should == pdf.y - bounds.absolute_bottom" do
16
- pdf = Prawn::Document.new
17
- expect(pdf.cursor).to eq(pdf.bounds.top)
18
-
19
- pdf.y = 300
20
- expect(pdf.cursor).to eq(pdf.y - pdf.bounds.absolute_bottom)
21
- end
22
-
23
- it "should be able to move relative to the bottom margin" do
24
- pdf = Prawn::Document.new
25
- pdf.move_cursor_to(10)
26
-
27
- expect(pdf.cursor).to eq(10)
28
- expect(pdf.y).to eq(pdf.cursor + pdf.bounds.absolute_bottom)
29
- end
30
- end
31
-
32
- describe "when generating a document with a custom text formatter" do
33
- it "should use the provided text formatter" do
34
- class TestTextFormatter
35
- def self.format(string)
36
- [
37
- {
38
- text: string.gsub("Dr. Who?", "Just 'The Doctor'."),
39
- styles: [],
40
- color: nil,
41
- link: nil,
42
- anchor: nil,
43
- local: nil,
44
- font: nil,
45
- size: nil,
46
- character_spacing: nil
47
- }
48
- ]
49
- end
50
- end
51
- pdf = Prawn::Document.new text_formatter: TestTextFormatter
52
- pdf.text "Dr. Who?", inline_format: true
53
- text = PDF::Inspector::Text.analyze(pdf.render)
54
- expect(text.strings.first).to eq("Just 'The Doctor'.")
55
- end
56
- end
57
-
58
- describe "when generating a document from a subclass" do
59
- it "should be an instance of the subclass" do
60
- custom_document = Class.new(Prawn::Document)
61
- custom_document.generate(Tempfile.new("generate_test").path) do |e|
62
- expect(e.class).to eq(custom_document)
63
- expect(e).to be_a_kind_of(Prawn::Document)
64
- end
65
- end
66
-
67
- it "should retain any extensions found on Prawn::Document" do
68
- mod1 = Module.new { attr_reader :test_extensions1 }
69
- mod2 = Module.new { attr_reader :test_extensions2 }
70
-
71
- Prawn::Document.extensions << mod1 << mod2
72
-
73
- custom_document = Class.new(Prawn::Document)
74
- expect(custom_document.extensions).to eq([mod1, mod2])
75
-
76
- # remove the extensions we added to prawn document
77
- Prawn::Document.extensions.delete(mod1)
78
- Prawn::Document.extensions.delete(mod2)
79
-
80
- expect(Prawn::Document.new.respond_to?(:test_extensions1)).to eq false
81
- expect(Prawn::Document.new.respond_to?(:test_extensions2)).to eq false
82
-
83
- # verify these still exist on custom class
84
- expect(custom_document.extensions).to eq([mod1, mod2])
85
-
86
- expect(custom_document.new.respond_to?(:test_extensions1)).to eq true
87
- expect(custom_document.new.respond_to?(:test_extensions2)).to eq true
88
- end
89
- end
90
-
91
- describe "When creating multi-page documents" do
92
- before(:each) { create_pdf }
93
-
94
- it "should initialize with a single page" do
95
- page_counter = PDF::Inspector::Page.analyze(@pdf.render)
96
-
97
- expect(page_counter.pages.size).to eq(1)
98
- expect(@pdf.page_count).to eq(1)
99
- end
100
-
101
- it "should provide an accurate page_count" do
102
- 3.times { @pdf.start_new_page }
103
- page_counter = PDF::Inspector::Page.analyze(@pdf.render)
104
-
105
- expect(page_counter.pages.size).to eq(4)
106
- expect(@pdf.page_count).to eq(4)
107
- end
108
- end
109
-
110
- describe "When beginning each new page" do
111
- describe "Background image feature" do
112
- before(:each) do
113
- @filename = "#{Prawn::DATADIR}/images/pigs.jpg"
114
- @pdf = Prawn::Document.new(:background => @filename)
115
- end
116
- it "should place a background image if it is in options block" do
117
- output = @pdf.render
118
- images = PDF::Inspector::XObject.analyze(output)
119
- # there should be 2 images in the page resources
120
- expect(images.page_xobjects.first.size).to eq(1)
121
- end
122
- it "should place a background image if it is in options block" do
123
- expect(@pdf.instance_variable_defined?(:@background)).to eq(true)
124
- expect(@pdf.instance_variable_get(:@background)).to eq(@filename)
125
- end
126
- end
127
- end
128
-
129
- describe "Prawn::Document#float" do
130
- it "should restore the original y-position" do
131
- create_pdf
132
- orig_y = @pdf.y
133
- @pdf.float { @pdf.text "Foo" }
134
- expect(@pdf.y).to eq(orig_y)
135
- end
136
-
137
- it "should teleport across pages if necessary" do
138
- create_pdf
139
-
140
- @pdf.float do
141
- @pdf.text "Foo"
142
- @pdf.start_new_page
143
- @pdf.text "Bar"
144
- end
145
- @pdf.text "Baz"
146
-
147
- pages = PDF::Inspector::Page.analyze(@pdf.render).pages
148
- expect(pages.size).to eq(2)
149
- expect(pages[0][:strings]).to eq(["Foo", "Baz"])
150
- expect(pages[1][:strings]).to eq(["Bar"])
151
- end
152
- end
153
-
154
- describe "The page_number method" do
155
- it "should be 1 for a new document" do
156
- pdf = Prawn::Document.new
157
- expect(pdf.page_number).to eq(1)
158
- end
159
-
160
- it "should be 0 for documents with no pages" do
161
- pdf = Prawn::Document.new(:skip_page_creation => true)
162
- expect(pdf.page_number).to eq(0)
163
- end
164
-
165
- it "should be changed by go_to_page" do
166
- pdf = Prawn::Document.new
167
- 10.times { pdf.start_new_page }
168
- pdf.go_to_page 3
169
- expect(pdf.page_number).to eq(3)
170
- end
171
- end
172
-
173
- describe "on_page_create callback" do
174
- before do
175
- create_pdf
176
- end
177
-
178
- it "should be delegated from Document to renderer" do
179
- expect(@pdf.respond_to?(:on_page_create)).to eq true
180
- end
181
-
182
- it "should be invoked with document" do
183
- called_with = nil
184
-
185
- @pdf.renderer.on_page_create { |*args| called_with = args }
186
-
187
- @pdf.start_new_page
188
-
189
- expect(called_with).to eq([@pdf])
190
- end
191
-
192
- it "should be invoked for each new page" do
193
- trigger = double("trigger")
194
- expect(trigger).to receive(:fire).exactly(5).times
195
-
196
- @pdf.renderer.on_page_create { trigger.fire }
197
-
198
- 5.times { @pdf.start_new_page }
199
- end
200
-
201
- it "should be replaceable" do
202
- trigger1 = double("trigger 1")
203
- expect(trigger1).to receive(:fire).once
204
-
205
- trigger2 = double("trigger 2")
206
- expect(trigger2).to receive(:fire).once
207
-
208
- @pdf.renderer.on_page_create { trigger1.fire }
209
-
210
- @pdf.start_new_page
211
-
212
- @pdf.renderer.on_page_create { trigger2.fire }
213
-
214
- @pdf.start_new_page
215
- end
216
-
217
- it "should be clearable by calling on_page_create without a block" do
218
- trigger = double("trigger")
219
- expect(trigger).to receive(:fire).once
220
-
221
- @pdf.renderer.on_page_create { trigger.fire }
222
-
223
- @pdf.start_new_page
224
-
225
- @pdf.renderer.on_page_create
226
-
227
- @pdf.start_new_page
228
- end
229
- end
230
-
231
- describe "Document compression" do
232
- it "should not compress the page content stream if compression is disabled" do
233
- pdf = Prawn::Document.new(:compress => false)
234
- allow(pdf.page.content.stream).to receive(:compress!).and_return(true)
235
- expect(pdf.page.content.stream).to_not receive(:compress!)
236
-
237
- pdf.text "Hi There" * 20
238
- pdf.render
239
- end
240
-
241
- it "should compress the page content stream if compression is enabled" do
242
- pdf = Prawn::Document.new(:compress => true)
243
- allow(pdf.page.content.stream).to receive(:compress!).and_return(true)
244
- expect(pdf.page.content.stream).to receive(:compress!).once
245
-
246
- pdf.text "Hi There" * 20
247
- pdf.render
248
- end
249
-
250
- it "should result in a smaller file size when compressed" do
251
- doc_uncompressed = Prawn::Document.new
252
- doc_compressed = Prawn::Document.new(:compress => true)
253
- [doc_compressed, doc_uncompressed].each do |pdf|
254
- pdf.font "#{Prawn::DATADIR}/fonts/gkai00mp.ttf"
255
- pdf.text "更可怕的是,同质化竞争对手可以按照URL中后面这个ID来遍历" * 10
256
- end
257
-
258
- expect(doc_compressed.render.length).to be < doc_uncompressed.render.length
259
- end
260
- end
261
-
262
- describe "Document metadata" do
263
- it "should output strings as UTF-16 with a byte order mark" do
264
- pdf = Prawn::Document.new(:info => { :Author => "Lóránt" })
265
- expect(pdf.state.store.info.object).to match(
266
- # UTF-16: BOM L ó r á n t
267
- %r{/Author\s*<feff004c00f3007200e1006e0074>}i
268
- )
269
- end
270
- end
271
-
272
- describe "When reopening pages" do
273
- it "should modify the content stream size" do
274
- @pdf = Prawn::Document.new do |pdf|
275
- pdf.text "Page 1"
276
- pdf.start_new_page
277
- pdf.text "Page 2"
278
- pdf.go_to_page 1
279
- pdf.text "More for page 1"
280
- end
281
-
282
- # Indirectly verify that the actual length does not match dictionary length.
283
- # If it isn't, a MalformedPDFError will be raised
284
- PDF::Inspector::Page.analyze(@pdf.render)
285
- end
286
-
287
- it "should insert pages after the current page when calling start_new_page" do
288
- pdf = Prawn::Document.new
289
- 3.times do |i|
290
- pdf.text "Old page #{i + 1}"
291
- pdf.start_new_page
292
- end
293
-
294
- pdf.go_to_page 1
295
- pdf.start_new_page
296
- pdf.text "New page 2"
297
-
298
- expect(pdf.page_number).to eq(2)
299
-
300
- pages = PDF::Inspector::Page.analyze(pdf.render).pages
301
- expect(pages.size).to eq(5)
302
- expect(pages[1][:strings]).to eq(["New page 2"])
303
- expect(pages[2][:strings]).to eq(["Old page 2"])
304
- end
305
-
306
- it "should restore the layout of the page" do
307
- doc = Prawn::Document.new do
308
- start_new_page :layout => :landscape
309
- end
310
-
311
- lsize = [doc.bounds.width, doc.bounds.height]
312
-
313
- expect([doc.bounds.width, doc.bounds.height]).to eq lsize
314
- doc.go_to_page 1
315
- expect([doc.bounds.width, doc.bounds.height]).to eq lsize.reverse
316
- end
317
-
318
- it "should restore the margin box of the page" do
319
- doc = Prawn::Document.new(:margin => [100, 100])
320
- page1_bounds = doc.bounds
321
-
322
- doc.start_new_page(:margin => [200, 200])
323
-
324
- expect([doc.bounds.width, doc.bounds.height]).to eq(
325
- [page1_bounds.width - 200, page1_bounds.height - 200]
326
- )
327
-
328
- doc.go_to_page(1)
329
-
330
- expect(doc.bounds.width).to eq page1_bounds.width
331
- expect(doc.bounds.height).to eq page1_bounds.height
332
- end
333
- end
334
-
335
- describe "When setting page size" do
336
- it "should default to LETTER" do
337
- @pdf = Prawn::Document.new
338
- pages = PDF::Inspector::Page.analyze(@pdf.render).pages
339
- expect(pages.first[:size]).to eq(PDF::Core::PageGeometry::SIZES["LETTER"])
340
- end
341
-
342
- (PDF::Core::PageGeometry::SIZES.keys - ["LETTER"]).each do |k|
343
- it "should provide #{k} geometry" do
344
- @pdf = Prawn::Document.new(:page_size => k)
345
- pages = PDF::Inspector::Page.analyze(@pdf.render).pages
346
- expect(pages.first[:size]).to eq(PDF::Core::PageGeometry::SIZES[k])
347
- end
348
- end
349
-
350
- it "should allow custom page size" do
351
- @pdf = Prawn::Document.new(:page_size => [1920, 1080])
352
- pages = PDF::Inspector::Page.analyze(@pdf.render).pages
353
- expect(pages.first[:size]).to eq([1920, 1080])
354
- end
355
-
356
- it "should retain page size by default when starting a new page" do
357
- @pdf = Prawn::Document.new(:page_size => "LEGAL")
358
- @pdf.start_new_page
359
- pages = PDF::Inspector::Page.analyze(@pdf.render).pages
360
- pages.each do |page|
361
- expect(page[:size]).to eq(PDF::Core::PageGeometry::SIZES["LEGAL"])
362
- end
363
- end
364
- end
365
-
366
- describe "When setting page layout" do
367
- it "should reverse coordinates for landscape" do
368
- @pdf = Prawn::Document.new(:page_size => "A4", :page_layout => :landscape)
369
- pages = PDF::Inspector::Page.analyze(@pdf.render).pages
370
- expect(pages.first[:size]).to eq(PDF::Core::PageGeometry::SIZES["A4"].reverse)
371
- end
372
-
373
- it "should retain page layout by default when starting a new page" do
374
- @pdf = Prawn::Document.new(:page_layout => :landscape)
375
- @pdf.start_new_page(:trace => true)
376
- pages = PDF::Inspector::Page.analyze(@pdf.render).pages
377
- pages.each do |page|
378
- expect(page[:size]).to eq(PDF::Core::PageGeometry::SIZES["LETTER"].reverse)
379
- end
380
- end
381
-
382
- it "should swap the bounds when starting a new page with different layout" do
383
- @pdf = Prawn::Document.new
384
- size = [@pdf.bounds.width, @pdf.bounds.height]
385
- @pdf.start_new_page(:layout => :landscape)
386
- expect([@pdf.bounds.width, @pdf.bounds.height]).to eq(size.reverse)
387
- end
388
- end
389
-
390
- describe "The mask() feature" do
391
- it "should allow transactional restoration of attributes" do
392
- @pdf = Prawn::Document.new
393
- y, line_width = @pdf.y, @pdf.line_width
394
- @pdf.mask(:y, :line_width) do
395
- @pdf.y = y + 1
396
- @pdf.line_width = line_width + 1
397
- expect(@pdf.y).not_to eq(y)
398
- expect(@pdf.line_width).not_to eq(line_width)
399
- end
400
- expect(@pdf.y).to eq(y)
401
- expect(@pdf.line_width).to eq(line_width)
402
- end
403
- end
404
-
405
- describe "The group() feature" do
406
- xit "should return a true value if the content fits on one page" do
407
- pdf = Prawn::Document.new do
408
- val = group {
409
- text "Hello"
410
- text "World"
411
- }
412
- expect(!!val).to eq(true)
413
- end
414
- end
415
-
416
- xit "should group a simple block on a single page" do
417
- pdf = Prawn::Document.new do
418
- self.y = 50
419
- val = group do
420
- text "Hello"
421
- text "World"
422
- end
423
-
424
- # group should return a false value since a new page was started
425
- expect(!!val).to eq(false)
426
- end
427
- pages = PDF::Inspector::Page.analyze(pdf.render).pages
428
- expect(pages.size).to eq(2)
429
- expect(pages[0][:strings]).to eq([])
430
- expect(pages[1][:strings]).to eq(["Hello", "World"])
431
- end
432
-
433
- xit "should raise_error CannotGroup if the content is too tall" do
434
- expect {
435
- Prawn::Document.new do
436
- group do
437
- 100.times { text "Too long" }
438
- end
439
- end.render
440
- }.to raise_error(Prawn::Errors::CannotGroup)
441
- end
442
-
443
- xit "should group within individual column boxes" do
444
- pdf = Prawn::Document.new do
445
- # Set up columns with grouped blocks of 0..49. 0 to 49 is slightly short
446
- # of the height of one page / column, so each column should get its own
447
- # group (every column should start with zero).
448
- column_box([0, bounds.top], :width => bounds.width, :columns => 7) do
449
- 10.times do
450
- group { 50.times { |i| text(i.to_s) } }
451
- end
452
- end
453
- end
454
-
455
- # Second page should start with a 0 because it's a new group.
456
- pages = PDF::Inspector::Page.analyze(pdf.render).pages
457
- expect(pages.size).to eq(2)
458
- expect(pages[1][:strings].first).to eq('0')
459
- end
460
- end
461
-
462
- describe "The render() feature" do
463
- it "should return a 8 bit encoded string on a m17n aware VM" do
464
- @pdf = Prawn::Document.new(:page_size => "A4", :page_layout => :landscape)
465
- @pdf.line [100, 100], [200, 200]
466
- str = @pdf.render
467
- expect(str.encoding.to_s).to eq("ASCII-8BIT")
468
- end
469
-
470
- it "should trigger before_render callbacks just before rendering" do
471
- pdf = Prawn::Document.new
472
-
473
- # Verify the order: finalize -> fire callbacks -> render body
474
- expect(pdf.renderer).to receive(:finalize_all_page_contents).and_call_original.ordered
475
-
476
- trigger = double("trigger")
477
- expect(trigger).to receive(:fire).ordered
478
-
479
- pdf.renderer.before_render{ trigger.fire }
480
-
481
- expect(pdf.renderer).to receive(:render_body).and_call_original.ordered
482
-
483
- pdf.render(StringIO.new)
484
- end
485
-
486
- it "should be idempotent" do
487
- pdf = Prawn::Document.new
488
-
489
- contents = pdf.render
490
- contents2 = pdf.render
491
- expect(contents2).to eq(contents)
492
- end
493
- end
494
-
495
- describe "PDF file versions" do
496
- it "should default to 1.3" do
497
- @pdf = Prawn::Document.new
498
- str = @pdf.render
499
- expect(str[0, 8]).to eq("%PDF-1.3")
500
- end
501
-
502
- it "should allow the default to be changed" do
503
- @pdf = Prawn::Document.new
504
- @pdf.renderer.min_version(1.4)
505
- str = @pdf.render
506
- expect(str[0, 8]).to eq("%PDF-1.4")
507
- end
508
- end
509
-
510
- describe "Documents that use go_to_page" do
511
- it "should have 2 pages after calling start_new_page and go_to_page" do
512
- @pdf = Prawn::Document.new
513
- @pdf.text "James"
514
- @pdf.start_new_page
515
- @pdf.text "Anthony"
516
- @pdf.go_to_page(1)
517
- @pdf.text "Healy"
518
-
519
- page_counter = PDF::Inspector::Page.analyze(@pdf.render)
520
- expect(page_counter.pages.size).to eq(2)
521
- end
522
-
523
- it "should correctly add text to pages" do
524
- @pdf = Prawn::Document.new
525
- @pdf.text "James"
526
- @pdf.start_new_page
527
- @pdf.text "Anthony"
528
- @pdf.go_to_page(1)
529
- @pdf.text "Healy"
530
-
531
- text = PDF::Inspector::Text.analyze(@pdf.render)
532
-
533
- expect(text.strings.size).to eq(3)
534
- expect(text.strings.include?("James")).to eq(true)
535
- expect(text.strings.include?("Anthony")).to eq(true)
536
- expect(text.strings.include?("Healy")).to eq(true)
537
- end
538
- end
539
-
540
- describe "content stream characteristics" do
541
- it "should have 1 single content stream for a single page PDF" do
542
- @pdf = Prawn::Document.new
543
- @pdf.text "James"
544
- output = StringIO.new(@pdf.render)
545
- hash = PDF::Reader::ObjectHash.new(output)
546
-
547
- streams = hash.values.select { |obj| obj.kind_of?(PDF::Reader::Stream) }
548
-
549
- expect(streams.size).to eq(1)
550
- end
551
-
552
- it "should have 1 single content stream for a single page PDF, even if go_to_page is used" do
553
- @pdf = Prawn::Document.new
554
- @pdf.text "James"
555
- @pdf.go_to_page(1)
556
- @pdf.text "Healy"
557
- output = StringIO.new(@pdf.render)
558
- hash = PDF::Reader::ObjectHash.new(output)
559
-
560
- streams = hash.values.select { |obj| obj.kind_of?(PDF::Reader::Stream) }
561
-
562
- expect(streams.size).to eq(1)
563
- end
564
- end
565
-
566
- describe "The number_pages method" do
567
- before do
568
- @pdf = Prawn::Document.new(:skip_page_creation => true)
569
- end
570
-
571
- it "replaces the '<page>' string with the proper page number" do
572
- @pdf.start_new_page
573
- expect(@pdf).to receive(:text_box).with("1, test", :height => 50)
574
- @pdf.number_pages "<page>, test", :page_filter => :all
575
- end
576
-
577
- it "replaces the '<total>' string with the total page count" do
578
- @pdf.start_new_page
579
- expect(@pdf).to receive(:text_box).with("test, 1", :height => 50)
580
- @pdf.number_pages "test, <total>", :page_filter => :all
581
- end
582
-
583
- it "must print each page if given the :all page_filter" do
584
- 10.times { @pdf.start_new_page }
585
- expect(@pdf).to receive(:text_box).exactly(10).times
586
- @pdf.number_pages "test", :page_filter => :all
587
- end
588
-
589
- it "must print each page if no :page_filter is specified" do
590
- 10.times { @pdf.start_new_page }
591
- expect(@pdf).to receive(:text_box).exactly(10).times
592
- @pdf.number_pages "test"
593
- end
594
-
595
- it "must not print the page number if given a nil filter" do
596
- 10.times { @pdf.start_new_page }
597
- expect(@pdf).to_not receive(:text_box)
598
- @pdf.number_pages "test", :page_filter => nil
599
- end
600
-
601
- context "start_count_at option" do
602
- [1, 2].each do |startat|
603
- context "equal to #{startat}" do
604
- it "increments the pages" do
605
- 2.times { @pdf.start_new_page }
606
- options = { :page_filter => :all, :start_count_at => startat }
607
- expect(@pdf).to receive(:text_box).with("#{startat} 2", :height => 50)
608
- expect(@pdf).to receive(:text_box).with("#{startat + 1} 2", :height => 50)
609
- @pdf.number_pages "<page> <total>", options
610
- end
611
- end
612
- end
613
-
614
- [0, nil].each do |val|
615
- context "equal to #{val}" do
616
- it "defaults to start at page 1" do
617
- 3.times { @pdf.start_new_page }
618
- options = { :page_filter => :all, :start_count_at => val }
619
- expect(@pdf).to receive(:text_box).with("1 3", :height => 50)
620
- expect(@pdf).to receive(:text_box).with("2 3", :height => 50)
621
- expect(@pdf).to receive(:text_box).with("3 3", :height => 50)
622
- @pdf.number_pages "<page> <total>", options
623
- end
624
- end
625
- end
626
- end
627
-
628
- context "total_pages option" do
629
- it "allows the total pages count to be overridden" do
630
- 2.times { @pdf.start_new_page }
631
- expect(@pdf).to receive(:text_box).with("1 10", :height => 50)
632
- expect(@pdf).to receive(:text_box).with("2 10", :height => 50)
633
- @pdf.number_pages "<page> <total>", :page_filter => :all, :total_pages => 10
634
- end
635
- end
636
-
637
- context "special page filter" do
638
- context "such as :odd" do
639
- it "increments the pages" do
640
- 3.times { @pdf.start_new_page }
641
- expect(@pdf).to receive(:text_box).with("1 3", :height => 50)
642
- expect(@pdf).to receive(:text_box).with("3 3", :height => 50)
643
- expect(@pdf).to_not receive(:text_box).with("2 3", :height => 50)
644
- @pdf.number_pages "<page> <total>", :page_filter => :odd
645
- end
646
- end
647
- context "missing" do
648
- it "does not print any page numbers" do
649
- 3.times { @pdf.start_new_page }
650
- expect(@pdf).to_not receive(:text_box)
651
- @pdf.number_pages "<page> <total>", :page_filter => nil
652
- end
653
- end
654
- end
655
-
656
- context "given both a special page filter and a start_count_at parameter" do
657
- context "such as :odd and 7" do
658
- it "increments the pages" do
659
- 3.times { @pdf.start_new_page }
660
- expect(@pdf).to_not receive(:text_box).with("1 3", :height => 50)
661
- expect(@pdf).to receive(:text_box).with("5 3", :height => 50) # page 1
662
- expect(@pdf).to_not receive(:text_box).with("6 3", :height => 50) # page 2
663
- expect(@pdf).to receive(:text_box).with("7 3", :height => 50) # page 3
664
- @pdf.number_pages "<page> <total>", :page_filter => :odd, :start_count_at => 5
665
- end
666
- end
667
- context "some crazy proc and 2" do
668
- it "increments the pages" do
669
- 6.times { @pdf.start_new_page }
670
- options = { :page_filter => lambda { |p| p != 2 && p != 5 }, :start_count_at => 4 }
671
- expect(@pdf).to receive(:text_box).with("4 6", :height => 50) # page 1
672
- expect(@pdf).to_not receive(:text_box).with("5 6", :height => 50) # page 2
673
- expect(@pdf).to receive(:text_box).with("6 6", :height => 50) # page 3
674
- expect(@pdf).to receive(:text_box).with("7 6", :height => 50) # page 4
675
- expect(@pdf).to_not receive(:text_box).with("8 6", :height => 50) # page 5
676
- expect(@pdf).to receive(:text_box).with("9 6", :height => 50) # page 6
677
- @pdf.number_pages "<page> <total>", options
678
- end
679
- end
680
- end
681
-
682
- context "height option" do
683
- before do
684
- @pdf.start_new_page
685
- end
686
-
687
- it "with 10 height" do
688
- expect(@pdf).to receive(:text_box).with("1 1", :height => 10)
689
- @pdf.number_pages "<page> <total>", :height => 10
690
- end
691
-
692
- it "with nil height" do
693
- expect(@pdf).to receive(:text_box).with("1 1", :height => nil)
694
- @pdf.number_pages "<page> <total>", :height => nil
695
- end
696
-
697
- it "with no height" do
698
- expect(@pdf).to receive(:text_box).with("1 1", height: 50)
699
- @pdf.number_pages "<page> <total>"
700
- end
701
- end
702
- end
703
-
704
- describe "The page_match? method" do
705
- before do
706
- @pdf = Prawn::Document.new(:skip_page_creation => true)
707
- 10.times { @pdf.start_new_page }
708
- end
709
-
710
- it "returns nil given no filter" do
711
- expect(@pdf.page_match?(:nil, 1)).to be_falsey
712
- end
713
-
714
- it "must provide an :all filter" do
715
- expect((1..@pdf.page_count).all? { |i| @pdf.page_match?(:all, i) }).to eq true
716
- end
717
-
718
- it "must provide an :odd filter" do
719
- odd, even = (1..@pdf.page_count).partition(&:odd?)
720
- expect(odd.all? { |i| @pdf.page_match?(:odd, i) }).to eq true
721
- expect(even.any? { |i| @pdf.page_match?(:odd, i) }).to be_falsey
722
- end
723
-
724
- it "must be able to filter by an array of page numbers" do
725
- fltr = [1, 2, 7]
726
- expect((1..10).select { |i| @pdf.page_match?(fltr, i) }).to eq([1, 2, 7])
727
- end
728
-
729
- it "must be able to filter by a range of page numbers" do
730
- fltr = 2..4
731
- expect((1..10).select { |i| @pdf.page_match?(fltr, i) }).to eq([2, 3, 4])
732
- end
733
-
734
- it "must be able to filter by an arbitrary proc" do
735
- fltr = lambda { |x| x == 1 or x % 3 == 0 }
736
- expect((1..10).select { |i| @pdf.page_match?(fltr, i) }).to eq([1, 3, 6, 9])
737
- end
738
- end