prawn 2.0.2 → 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 (277) 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 +37 -49
  8. data/lib/prawn/document.rb +181 -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 +18 -8
  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 +115 -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 +120 -80
  23. data/lib/prawn/graphics/blend_mode.rb +65 -0
  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 +197 -67
  29. data/lib/prawn/graphics/transformation.rb +17 -8
  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 +107 -66
  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 +78 -49
  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 +121 -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 +44 -0
  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 +52 -0
  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 -39
  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 +4 -5
  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 +45 -33
  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/prawn/image_handler_spec.rb +53 -0
  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/prawn/transformation_stack_spec.rb +66 -0
  195. data/spec/prawn/view_spec.rb +63 -0
  196. data/spec/prawn_manual_spec.rb +35 -0
  197. data/spec/spec_helper.rb +19 -23
  198. metadata +145 -185
  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/dice.alpha +0 -0
  206. data/data/images/dice.color +0 -0
  207. data/data/images/dice.png +0 -0
  208. data/data/images/dice_interlaced.png +0 -0
  209. data/data/images/fractal.jpg +0 -0
  210. data/data/images/indexed_color.dat +0 -0
  211. data/data/images/indexed_color.png +0 -0
  212. data/data/images/letterhead.jpg +0 -0
  213. data/data/images/license.md +0 -8
  214. data/data/images/page_white_text.alpha +0 -0
  215. data/data/images/page_white_text.color +0 -0
  216. data/data/images/page_white_text.png +0 -0
  217. data/data/images/pal_bk.png +0 -0
  218. data/data/images/pigs.jpg +0 -0
  219. data/data/images/prawn.png +0 -0
  220. data/data/images/ruport.png +0 -0
  221. data/data/images/ruport_data.dat +0 -0
  222. data/data/images/ruport_transparent.png +0 -0
  223. data/data/images/ruport_type0.png +0 -0
  224. data/data/images/stef.jpg +0 -0
  225. data/data/images/tru256.bmp +0 -0
  226. data/data/images/web-links.dat +0 -1
  227. data/data/images/web-links.png +0 -0
  228. data/data/pdfs/complex_template.pdf +0 -0
  229. data/data/pdfs/contains_ttf_font.pdf +0 -0
  230. data/data/pdfs/encrypted.pdf +0 -0
  231. data/data/pdfs/form.pdf +1 -819
  232. data/data/pdfs/hexagon.pdf +0 -61
  233. data/data/pdfs/indirect_reference.pdf +0 -86
  234. data/data/pdfs/multipage_template.pdf +0 -127
  235. data/data/pdfs/nested_pages.pdf +0 -118
  236. data/data/pdfs/page_without_mediabox.pdf +0 -193
  237. data/data/pdfs/resources_as_indirect_object.pdf +0 -83
  238. data/data/pdfs/two_hexagons.pdf +0 -90
  239. data/data/pdfs/version_1_6.pdf +0 -61
  240. data/data/shift_jis_text.txt +0 -1
  241. data/spec/acceptance/png.rb +0 -24
  242. data/spec/annotations_spec.rb +0 -67
  243. data/spec/bounding_box_spec.rb +0 -501
  244. data/spec/column_box_spec.rb +0 -59
  245. data/spec/destinations_spec.rb +0 -13
  246. data/spec/document_spec.rb +0 -742
  247. data/spec/extensions/mocha.rb +0 -45
  248. data/spec/font_metric_cache_spec.rb +0 -52
  249. data/spec/font_spec.rb +0 -475
  250. data/spec/formatted_text_arranger_spec.rb +0 -423
  251. data/spec/formatted_text_box_spec.rb +0 -716
  252. data/spec/formatted_text_fragment_spec.rb +0 -299
  253. data/spec/graphics_spec.rb +0 -666
  254. data/spec/grid_spec.rb +0 -95
  255. data/spec/image_handler_spec.rb +0 -53
  256. data/spec/images_spec.rb +0 -167
  257. data/spec/inline_formatted_text_parser_spec.rb +0 -568
  258. data/spec/jpg_spec.rb +0 -23
  259. data/spec/line_wrap_spec.rb +0 -366
  260. data/spec/measurement_units_spec.rb +0 -22
  261. data/spec/outline_spec.rb +0 -409
  262. data/spec/png_spec.rb +0 -235
  263. data/spec/reference_spec.rb +0 -25
  264. data/spec/repeater_spec.rb +0 -154
  265. data/spec/security_spec.rb +0 -151
  266. data/spec/soft_mask_spec.rb +0 -78
  267. data/spec/span_spec.rb +0 -43
  268. data/spec/stamp_spec.rb +0 -179
  269. data/spec/stroke_styles_spec.rb +0 -208
  270. data/spec/text_at_spec.rb +0 -142
  271. data/spec/text_box_spec.rb +0 -1038
  272. data/spec/text_rendering_mode_spec.rb +0 -45
  273. data/spec/text_spacing_spec.rb +0 -93
  274. data/spec/text_spec.rb +0 -549
  275. data/spec/text_with_inline_formatting_spec.rb +0 -35
  276. data/spec/transparency_spec.rb +0 -91
  277. data/spec/view_spec.rb +0 -42
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Prawn::Document::ColumnBox do
6
+ let(:pdf) { create_pdf }
7
+
8
+ it 'has sensible left and right values' do
9
+ pdf.column_box(
10
+ [0, pdf.cursor],
11
+ width: pdf.bounds.width,
12
+ height: 200,
13
+ columns: 3,
14
+ spacer: 25
15
+ ) do
16
+ left = pdf.bounds.left
17
+ right = pdf.bounds.right
18
+
19
+ pdf.bounds.move_past_bottom # next column
20
+
21
+ expect(pdf.bounds.left).to be > left
22
+ expect(pdf.bounds.left).to be > right
23
+ expect(pdf.bounds.right).to be > pdf.bounds.left
24
+ end
25
+ end
26
+
27
+ it 'includes spacers between columns but not at the end' do
28
+ pdf.column_box(
29
+ [0, pdf.cursor],
30
+ width: 500,
31
+ height: 200,
32
+ columns: 3,
33
+ spacer: 25
34
+ ) do
35
+ expect(pdf.bounds.width).to eq(150) # (500 - (25 * 2)) / 3
36
+
37
+ pdf.bounds.move_past_bottom
38
+ pdf.bounds.move_past_bottom
39
+
40
+ expect(pdf.bounds.right).to eq(500)
41
+ end
42
+ end
43
+
44
+ it 'does not reset the top margin on a new page by default' do
45
+ page_top = pdf.cursor
46
+ pdf.move_down 50
47
+ init_column_top = pdf.cursor
48
+ pdf.column_box [0, pdf.cursor], width: 500, height: 200, columns: 2 do
49
+ pdf.bounds.move_past_bottom
50
+ pdf.bounds.move_past_bottom
51
+
52
+ expect(pdf.bounds.absolute_top).to eq(init_column_top)
53
+ expect(pdf.bounds.absolute_top).to_not eq(page_top)
54
+ end
55
+ end
56
+
57
+ it 'does reset the top margin when reflow_margins is set' do
58
+ page_top = pdf.cursor
59
+ pdf.move_down 50
60
+ init_column_top = pdf.cursor
61
+ pdf.column_box(
62
+ [0, pdf.cursor],
63
+ width: 500,
64
+ reflow_margins: true,
65
+ height: 200,
66
+ columns: 2
67
+ ) do
68
+ pdf.bounds.move_past_bottom
69
+ pdf.bounds.move_past_bottom
70
+
71
+ expect(pdf.bounds.absolute_top).to eq(page_top)
72
+ expect(pdf.bounds.absolute_top).to_not eq(init_column_top)
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,176 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'tempfile'
5
+
6
+ describe Prawn::Document::Security do
7
+ describe 'Password padding' do
8
+ include described_class
9
+
10
+ it 'truncates long passwords' do
11
+ pw = 'Long long string' * 30
12
+ padded = pad_password(pw)
13
+ expect(padded.length).to eq(32)
14
+ expect(padded).to eq(pw[0, 32])
15
+ end
16
+
17
+ it 'pads short passwords' do
18
+ pw = 'abcd'
19
+ padded = pad_password(pw)
20
+ expect(padded.length).to eq(32)
21
+ expect(padded).to eq(
22
+ pw + Prawn::Document::Security::PASSWORD_PADDING[0, 28]
23
+ )
24
+ end
25
+
26
+ it 'fullies pad null passwords' do
27
+ pw = ''
28
+ padded = pad_password(pw)
29
+ expect(padded.length).to eq(32)
30
+ expect(padded).to eq(Prawn::Document::Security::PASSWORD_PADDING)
31
+ end
32
+ end
33
+
34
+ describe 'Setting permissions' do
35
+ def doc_with_permissions(permissions)
36
+ pdf = Prawn::Document.new
37
+
38
+ # Make things easier to test
39
+ pdf.singleton_class.send :public, :permissions_value
40
+ # class << pdf
41
+ # public :permissions_value
42
+ # end
43
+
44
+ pdf.encrypt_document(permissions: permissions)
45
+ pdf
46
+ end
47
+
48
+ it 'defaults to full permissions' do
49
+ expect(doc_with_permissions({}).permissions_value).to eq(0xFFFFFFFF)
50
+ expect(doc_with_permissions(
51
+ print_document: true,
52
+ modify_contents: true,
53
+ copy_contents: true,
54
+ modify_annotations: true
55
+ ).permissions_value)
56
+ .to eq(0xFFFFFFFF)
57
+ end
58
+
59
+ it 'clears the appropriate bits for each permission flag' do
60
+ expect(doc_with_permissions(print_document: false).permissions_value)
61
+ .to eq(0b1111_1111_1111_1111_1111_1111_1111_1011)
62
+ expect(doc_with_permissions(modify_contents: false).permissions_value)
63
+ .to eq(0b1111_1111_1111_1111_1111_1111_1111_0111)
64
+ expect(doc_with_permissions(copy_contents: false).permissions_value)
65
+ .to eq(0b1111_1111_1111_1111_1111_1111_1110_1111)
66
+ expect(doc_with_permissions(modify_annotations: false).permissions_value)
67
+ .to eq(0b1111_1111_1111_1111_1111_1111_1101_1111)
68
+ end
69
+
70
+ it 'raise_errors ArgumentError if invalid option is provided' do
71
+ expect do
72
+ doc_with_permissions(modify_document: false)
73
+ end.to raise_error(ArgumentError)
74
+ end
75
+ end
76
+
77
+ describe 'Encryption keys' do
78
+ # Since PDF::Reader doesn't read encrypted PDF files, we just take the
79
+ # roundabout method of verifying each step of the encryption. This works
80
+ # fine because the encryption method is deterministic.
81
+
82
+ let(:pdf) do
83
+ Prawn::Document.new do |pdf|
84
+ class << pdf
85
+ public :owner_password_hash, :user_password_hash, :user_encryption_key
86
+ end
87
+ pdf.encrypt_document(
88
+ user_password: 'foo',
89
+ owner_password: 'bar',
90
+ permissions: { print_document: false }
91
+ )
92
+ end
93
+ end
94
+
95
+ it 'calculates the correct owner hash' do
96
+ expect(pdf.owner_password_hash.unpack1('H*'))
97
+ .to match(/^61CA855012/i)
98
+ end
99
+
100
+ it 'calculates the correct user hash' do
101
+ expect(pdf.user_password_hash.unpack1('H*'))
102
+ .to match(/^6BC8C51031/i)
103
+ end
104
+
105
+ it 'calculates the correct user_encryption_key' do
106
+ expect(pdf.user_encryption_key.unpack1('H*').upcase)
107
+ .to eq('B100AB6429')
108
+ end
109
+ end
110
+
111
+ describe 'encrypted_pdf_object' do
112
+ it 'delegates to PdfObject for simple types' do
113
+ expect(PDF::Core.encrypted_pdf_object(true, nil, nil, nil)).to eq('true')
114
+ expect(PDF::Core.encrypted_pdf_object(42, nil, nil, nil)).to eq('42')
115
+ end
116
+
117
+ it 'encrypts strings properly' do
118
+ expect(PDF::Core.encrypted_pdf_object('foo', '12345', 123, 0))
119
+ .to eq('<4ad6e3>')
120
+ end
121
+
122
+ it 'encrypts literal strings properly' do
123
+ expect(PDF::Core.encrypted_pdf_object(
124
+ PDF::Core::LiteralString.new('foo'), '12345', 123, 0
125
+ )).to eq(bin_string("(J\xD6\xE3)"))
126
+ expect(PDF::Core.encrypted_pdf_object(
127
+ PDF::Core::LiteralString.new('lhfbqg3do5u0satu3fjf'), nil, 123, 0
128
+ )).to eq(bin_string(
129
+ "(\xF1\x8B\\(\b\xBB\xE18S\x130~4*#\\(%\x87\xE7\x8E\\\n)"
130
+ ))
131
+ end
132
+
133
+ it 'encrypts time properly' do
134
+ expect(PDF::Core.encrypted_pdf_object(
135
+ Time.utc(2050, 0o4, 26, 10, 17, 10), '12345', 123, 0
136
+ )).to eq(bin_string(
137
+ "(h\x83\xBE\xDC\xEC\x99\x0F\xD7\\)%\x13\xD4$\xB8\xF0\x16\xB8\x80\xC5"\
138
+ "\xE91+\xCF)"
139
+ ))
140
+ end
141
+
142
+ it 'properlies handle compound types' do
143
+ expect(PDF::Core.encrypted_pdf_object({ Bar: 'foo' }, '12345', 123, 0))
144
+ .to eq(
145
+ "<< /Bar <4ad6e3>\n>>"
146
+ )
147
+ expect(PDF::Core.encrypted_pdf_object(%w[foo bar], '12345', 123, 0))
148
+ .to eq('[<4ad6e3> <4ed8fe>]')
149
+ end
150
+ end
151
+
152
+ describe 'Reference#encrypted_object' do
153
+ it 'encrypts references properly' do
154
+ ref = PDF::Core::Reference.new(1, ['foo'])
155
+ expect(ref.encrypted_object(nil)).to eq("1 0 obj\n[<4fca3f>]\nendobj\n")
156
+ end
157
+
158
+ it 'encrypts references with streams properly' do
159
+ ref = PDF::Core::Reference.new(1, {})
160
+ ref << 'foo'
161
+ result = bin_string(
162
+ "1 0 obj\n<< /Length 3\n>>\nstream\nO\xCA?\nendstream\nendobj\n"
163
+ )
164
+ expect(ref.encrypted_object(nil)).to eq(result)
165
+ end
166
+ end
167
+
168
+ describe 'String#encrypted_object' do
169
+ it 'encrypts stream properly' do
170
+ stream = PDF::Core::Stream.new
171
+ stream << 'foo'
172
+ result = bin_string("stream\nO\xCA?\nendstream\n")
173
+ expect(stream.encrypted_object(nil, 1, 0)).to eq(result)
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Prawn::Document do
6
+ let(:pdf) { create_pdf }
7
+
8
+ describe 'When creating annotations' do
9
+ it 'appends annotation to current page' do
10
+ pdf.start_new_page
11
+ pdf.annotate(
12
+ Rect: [0, 0, 10, 10],
13
+ Subtype: :Text,
14
+ Contents: 'Hello world!'
15
+ )
16
+ PDF::Reader.open(StringIO.new(pdf.render)) do |pdf|
17
+ expect(pdf.page(1).attributes[:Annots]).to be_nil
18
+ expect(pdf.page(2).attributes[:Annots].size).to eq(1)
19
+ end
20
+ end
21
+
22
+ it 'forces :Type to be :Annot' do
23
+ opts = pdf.annotate(
24
+ Rect: [0, 0, 10, 10],
25
+ Subtype: :Text,
26
+ Contents: 'Hello world!'
27
+ )
28
+ expect(opts[:Type]).to eq(:Annot)
29
+ opts = pdf.annotate(
30
+ Type: :Bogus,
31
+ Rect: [0, 0, 10, 10],
32
+ Subtype: :Text,
33
+ Contents: 'Hello world!'
34
+ )
35
+ expect(opts[:Type]).to eq(:Annot)
36
+ end
37
+ end
38
+
39
+ describe 'When creating text annotations' do
40
+ let(:rect) { [0, 0, 10, 10] }
41
+ let(:content) { 'Hello, world!' }
42
+
43
+ it 'builds appropriate annotation' do
44
+ opts = pdf.text_annotation(rect, content)
45
+ expect(opts[:Type]).to eq(:Annot)
46
+ expect(opts[:Subtype]).to eq(:Text)
47
+ expect(opts[:Rect]).to eq(rect)
48
+ expect(opts[:Contents]).to eq(content)
49
+ end
50
+
51
+ it 'merges extra options' do
52
+ opts = pdf.text_annotation(rect, content, Open: true, Subtype: :Bogus)
53
+ expect(opts[:Subtype]).to eq(:Text)
54
+ expect(opts[:Open]).to eq(true)
55
+ end
56
+ end
57
+
58
+ describe 'When creating link annotations' do
59
+ let(:rect) { [0, 0, 10, 10] }
60
+ let(:dest) { 'home' }
61
+
62
+ it 'builds appropriate annotation' do
63
+ opts = pdf.link_annotation(rect, Dest: dest)
64
+ expect(opts[:Type]).to eq(:Annot)
65
+ expect(opts[:Subtype]).to eq(:Link)
66
+ expect(opts[:Rect]).to eq(rect)
67
+ expect(opts[:Dest]).to eq(dest)
68
+ end
69
+
70
+ it 'merges extra options' do
71
+ opts = pdf.link_annotation(rect, Dest: dest, Subtype: :Bogus)
72
+ expect(opts[:Subtype]).to eq(:Link)
73
+ expect(opts[:Dest]).to eq(dest)
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Prawn::Document do
6
+ describe 'When creating destinations' do
7
+ let(:pdf) { create_pdf }
8
+
9
+ it 'adds entry to Dests name tree' do
10
+ expect(pdf.dests.data.empty?).to eq(true)
11
+ pdf.add_dest 'candy', 'chocolate'
12
+ expect(pdf.dests.data.size).to eq(1)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Prawn::Document do
6
+ describe 'grid' do
7
+ let(:pdf) { described_class.new }
8
+
9
+ it 'allows definition of a grid' do
10
+ pdf.define_grid(columns: 5, rows: 8, gutter: 0.1)
11
+ expect(pdf.grid.columns).to eq(5)
12
+ expect(pdf.grid.rows).to eq(8)
13
+ expect(pdf.grid.gutter).to eq(0.1)
14
+ end
15
+
16
+ it 'allows re-definition of a grid' do
17
+ pdf.define_grid(columns: 5, rows: 8, gutter: 0.1)
18
+ expect(pdf.grid.columns).to eq(5)
19
+ expect(pdf.grid.rows).to eq(8)
20
+ expect(pdf.grid.gutter).to eq(0.1)
21
+ pdf.define_grid(columns: 3, rows: 6, gutter: 0.1)
22
+ expect(pdf.grid.columns).to eq(3)
23
+ expect(pdf.grid.rows).to eq(6)
24
+ expect(pdf.grid.gutter).to eq(0.1)
25
+ end
26
+
27
+ describe 'when a grid is defined' do
28
+ let(:num_columns) { 5 }
29
+ let(:num_rows) { 8 }
30
+ let(:gutter) { 10.0 }
31
+
32
+ before do
33
+ pdf.define_grid(
34
+ columns: num_columns,
35
+ rows: num_rows,
36
+ gutter: gutter
37
+ )
38
+ end
39
+
40
+ it 'computes the column width' do
41
+ expect(pdf.grid.column_width * num_columns.to_f +
42
+ gutter * (num_columns - 1).to_f).to eq(pdf.bounds.width)
43
+ end
44
+
45
+ it 'computes the row height' do
46
+ expect(pdf.grid.row_height * num_rows.to_f +
47
+ gutter * (num_rows - 1).to_f).to eq(pdf.bounds.height)
48
+ end
49
+
50
+ it 'gives the edges of a grid box' do
51
+ grid_width = (pdf.bounds.width.to_f -
52
+ (gutter * (num_columns - 1).to_f)) / num_columns.to_f
53
+ grid_height = (pdf.bounds.height.to_f -
54
+ (gutter * (num_rows - 1).to_f)) / num_rows.to_f
55
+
56
+ exp_tl_x = (grid_width + gutter.to_f) * 4.0
57
+ exp_tl_y = pdf.bounds.height.to_f - (grid_height + gutter.to_f)
58
+
59
+ expect(pdf.grid(1, 4).top_left).to eq([exp_tl_x, exp_tl_y])
60
+ expect(pdf.grid(1, 4).top_right).to eq [exp_tl_x + grid_width, exp_tl_y]
61
+ expect(pdf.grid(1, 4).bottom_left)
62
+ .to eq([exp_tl_x, exp_tl_y - grid_height])
63
+ expect(pdf.grid(1, 4).bottom_right)
64
+ .to eq([exp_tl_x + grid_width, exp_tl_y - grid_height])
65
+ end
66
+
67
+ it 'gives the edges of a multiple grid boxes' do
68
+ # Hand verified. Cheating a bit. Don't tell.
69
+ expect(pdf.grid([1, 3], [2, 5]).top_left).to eq([330.0, 628.75])
70
+ expect(pdf.grid([1, 3], [2, 5]).top_right).to eq([650.0, 628.75])
71
+ expect(pdf.grid([1, 3], [2, 5]).bottom_left).to eq([330.0, 456.25])
72
+ expect(pdf.grid([1, 3], [2, 5]).bottom_right).to eq([650.0, 456.25])
73
+ end
74
+
75
+ it 'draws outlines without changing global default colors' do
76
+ pdf.grid.show_all('cccccc')
77
+
78
+ colors = PDF::Inspector::Graphics::Color.analyze(pdf.render)
79
+ expect(colors.fill_color).to_not eq([0.8, 0.8, 0.8])
80
+ expect(colors.stroke_color).to_not eq([0.8, 0.8, 0.8])
81
+
82
+ # Hardcoded default color as I haven't been able to come up with
83
+ # a stable converter between fill_color without lots code.
84
+ expect(colors.stroke_color).to eq([0.0, 0.0, 0.0])
85
+ end
86
+
87
+ it 'draws outlines without curent color settings' do
88
+ pdf.fill_color 'ccff00'
89
+ pdf.stroke_color 'ffcc00'
90
+
91
+ pdf.grid.show_all
92
+
93
+ colors = PDF::Inspector::Graphics::Color.analyze(pdf.render)
94
+ expect(colors.fill_color).to eq([0.8, 1.0, 0.0])
95
+ expect(colors.stroke_color).to eq([1.0, 0.8, 0.0])
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Prawn::Document do
6
+ describe 'A Reference object' do
7
+ describe 'generated via Prawn::Document' do
8
+ it 'returns a proper reference on ref!' do
9
+ pdf = described_class.new
10
+ expect(pdf.ref!({}).is_a?(PDF::Core::Reference)).to eq(true)
11
+ end
12
+
13
+ it 'returns an identifier on ref' do
14
+ pdf = described_class.new
15
+ r = pdf.ref({})
16
+ expect(r.is_a?(Integer)).to eq(true)
17
+ end
18
+
19
+ it 'has :Length of stream if it has one when compression disabled' do
20
+ pdf = described_class.new compress: false
21
+ ref = pdf.ref!({})
22
+ ref << 'Hello'
23
+ expect(ref.stream.data[:Length]).to eq(5)
24
+ end
25
+ end
26
+ end
27
+ end